blob: c9bf779481d8ca141ff18b944e8e6d2657125112 [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 Remnant9f56fad2009-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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 }
Jiri Slaby4d768202009-09-19 13:13:15 -07001462 if (tty->termios->c_cflag & HUPCL)
1463 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 Slaby9fa1b3b2007-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 Slaby9fa1b3b2007-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
Jiri Slaby4d768202009-09-19 13:13:15 -07001491 if (tty->termios->c_cflag & HUPCL)
1492 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 Slaby9fa1b3b2007-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 Slaby65f76a82007-10-18 03:06:22 -07001518 unsigned int i, line;
1519 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Jiri Slaby02f11752006-12-08 02:39:28 -08001521 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001522 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001524
Jiri Slabydd025c02007-05-08 00:37:02 -07001525 for (i = 0; i < NR_CARDS; i++)
1526 if (line < cy_card[i].first_line + cy_card[i].nports &&
1527 line >= cy_card[i].first_line)
1528 break;
1529 if (i >= NR_CARDS)
1530 return -ENODEV;
1531 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001532 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001533 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001534
1535 /* If the card's firmware hasn't been loaded,
1536 treat it as absent from the system. This
1537 will make the user pay attention.
1538 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001539 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001540 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001541 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1542
Jiri Slaby2693f482009-06-11 12:31:06 +01001543 if (!cyz_is_loaded(cinfo)) {
1544 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001545 readl(&firm_id->signature) ==
1546 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001547 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1548 "need an external power supply for "
1549 "this number of ports.\nFirmware "
1550 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001551 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001552 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1553 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001554 }
1555 return -ENODEV;
1556 }
1557#ifdef CONFIG_CYZ_INTR
1558 else {
1559 /* In case this Z board is operating in interrupt mode, its
1560 interrupts should be enabled as soon as the first open
1561 happens to one of its ports. */
1562 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001563 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001564
Jiri Slaby02f11752006-12-08 02:39:28 -08001565 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001566 intr = readw(&cinfo->ctl_addr.p9060->
1567 intr_ctrl_stat) | 0x0900;
1568 cy_writew(&cinfo->ctl_addr.p9060->
1569 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001570 /* Enable interrupts on the FW */
1571 retval = cyz_issue_cmd(cinfo, 0,
1572 C_CM_IRQ_ENBL, 0L);
1573 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001574 printk(KERN_ERR "cyc:IRQ enable retval "
1575 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001576 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001577 cinfo->intr_enabled = 1;
1578 }
1579 }
1580#endif /* CONFIG_CYZ_INTR */
1581 /* Make sure this Z port really exists in hardware */
1582 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1583 return -ENODEV;
1584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001586 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001588 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001589 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001590 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001591
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001593 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001594 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595#endif
Alan Cox77451e52008-07-16 21:57:02 +01001596 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001598 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001599 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
Jiri Slaby02f11752006-12-08 02:39:28 -08001602 /*
1603 * If the port is the middle of closing, bail out now
1604 */
Alan Cox77451e52008-07-16 21:57:02 +01001605 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
Arnd Bergmannbe1bc282010-06-01 22:53:05 +02001606 wait_event_interruptible_tty(info->port.close_wait,
Alan Cox77451e52008-07-16 21:57:02 +01001607 !(info->port.flags & ASYNC_CLOSING));
1608 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Jiri Slaby02f11752006-12-08 02:39:28 -08001611 /*
1612 * Start up serial port
1613 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001614 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001615 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001616 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
Jiri Slabyf0737572009-09-19 13:13:12 -07001618 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001619 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001621 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1622 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001624 return retval;
1625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Jiri Slaby02f11752006-12-08 02:39:28 -08001627 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001628 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
1630#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001631 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001633 return 0;
1634} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
1636/*
1637 * cy_wait_until_sent() --- wait until the transmitter is empty
1638 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001639static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640{
Jiri Slaby875b2062007-05-08 00:36:49 -07001641 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001642 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001643 unsigned long orig_jiffies;
1644 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Jiri Slaby02f11752006-12-08 02:39:28 -08001646 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1647 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Jiri Slaby02f11752006-12-08 02:39:28 -08001649 if (info->xmit_fifo_size == 0)
1650 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Jiri Slaby02f11752006-12-08 02:39:28 -08001652 orig_jiffies = jiffies;
1653 /*
1654 * Set the check interval to be 1/5 of the estimated time to
1655 * send a single character, and make it at least 1. The check
1656 * interval should also be less than the timeout.
1657 *
1658 * Note: we have to use pretty tight timings here to satisfy
1659 * the NIST-PCTS.
1660 */
1661 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1662 char_time = char_time / 5;
1663 if (char_time <= 0)
1664 char_time = 1;
1665 if (timeout < 0)
1666 timeout = 0;
1667 if (timeout)
1668 char_time = min(char_time, timeout);
1669 /*
1670 * If the transmitter hasn't cleared in twice the approximate
1671 * amount of time to send the entire FIFO, it probably won't
1672 * ever clear. This assumes the UART isn't doing flow
1673 * control, which is currently the case. Hence, if it ever
1674 * takes longer than info->timeout, this is probably due to a
1675 * UART bug of some kind. So, we clamp the timeout parameter at
1676 * 2*info->timeout.
1677 */
1678 if (!timeout || timeout > 2 * info->timeout)
1679 timeout = 2 * info->timeout;
Jiri Slaby8bab5342011-07-14 14:35:15 +02001680
Jiri Slaby02f11752006-12-08 02:39:28 -08001681 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001682 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001683 while (cyy_readb(info, CySRER) & CyTxRdy) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001684 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1685 break;
1686 if (timeout && time_after(jiffies, orig_jiffies +
1687 timeout))
1688 break;
1689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001691 /* Run one more char cycle */
1692 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693}
1694
Alan Cox978e5952008-04-30 00:53:59 -07001695static void cy_flush_buffer(struct tty_struct *tty)
1696{
1697 struct cyclades_port *info = tty->driver_data;
1698 struct cyclades_card *card;
1699 int channel, retval;
1700 unsigned long flags;
1701
1702#ifdef CY_DEBUG_IO
1703 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1704#endif
1705
1706 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1707 return;
1708
1709 card = info->card;
1710 channel = info->line - card->first_line;
1711
1712 spin_lock_irqsave(&card->card_lock, flags);
1713 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1714 spin_unlock_irqrestore(&card->card_lock, flags);
1715
Jiri Slaby2693f482009-06-11 12:31:06 +01001716 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001717 buffers as well */
1718 spin_lock_irqsave(&card->card_lock, flags);
1719 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1720 if (retval != 0) {
1721 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1722 "was %x\n", info->line, retval);
1723 }
1724 spin_unlock_irqrestore(&card->card_lock, flags);
1725 }
1726 tty_wakeup(tty);
1727} /* cy_flush_buffer */
1728
1729
Alan Coxe936ffd2009-09-19 13:13:22 -07001730static void cy_do_close(struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
Alan Coxe936ffd2009-09-19 13:13:22 -07001732 struct cyclades_port *info = container_of(port, struct cyclades_port,
1733 port);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001734 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001735 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001736 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001738 card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001739 channel = info->line - card->first_line;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001740 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001741
Jiri Slaby2693f482009-06-11 12:31:06 +01001742 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001743 /* Stop accepting input */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001744 cyy_writeb(info, CyCAR, channel & 0x03);
1745 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001746 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001747 /* Waiting for on-board buffers to be empty before
1748 closing the port */
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001749 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001750 cy_wait_until_sent(port->tty, info->timeout);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001751 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001752 }
1753 } else {
1754#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001755 /* Waiting for on-board buffers to be empty before closing
1756 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001757 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001758 int retval;
1759
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001760 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001761 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001762 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001763 printk(KERN_DEBUG "cyc:cy_close retval on "
1764 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001765 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001766 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001767 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001768 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001769 }
1770#endif
1771 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001772 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001773 cy_shutdown(info, port->tty);
1774}
Jiri Slaby02f11752006-12-08 02:39:28 -08001775
Alan Coxe936ffd2009-09-19 13:13:22 -07001776/*
1777 * This routine is called when a particular tty device is closed.
1778 */
1779static void cy_close(struct tty_struct *tty, struct file *filp)
1780{
1781 struct cyclades_port *info = tty->driver_data;
1782 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1783 return;
1784 tty_port_close(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001785} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
1787/* This routine gets called when tty_write has put something into
1788 * the write_queue. The characters may come from user space or
1789 * kernel space.
1790 *
1791 * This routine will return the number of characters actually
1792 * accepted for writing.
1793 *
1794 * If the port is not already transmitting stuff, start it off by
1795 * enabling interrupts. The interrupt service routine will then
1796 * ensure that the characters are sent.
1797 * If the port is already active, there is no need to kick it.
1798 *
1799 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001800static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001802 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001803 unsigned long flags;
1804 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
1806#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001807 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808#endif
1809
Alan Cox15ed6cc2008-04-30 00:53:55 -07001810 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001811 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Alan Cox77451e52008-07-16 21:57:02 +01001813 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001814 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001816 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001817 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001818 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1819 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
Jiri Slaby02f11752006-12-08 02:39:28 -08001821 if (c <= 0)
1822 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
Alan Cox77451e52008-07-16 21:57:02 +01001824 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001825 info->xmit_head = (info->xmit_head + c) &
1826 (SERIAL_XMIT_SIZE - 1);
1827 info->xmit_cnt += c;
1828 buf += c;
1829 count -= c;
1830 ret += c;
1831 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001832 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
Jiri Slaby02f11752006-12-08 02:39:28 -08001834 info->idle_stats.xmit_bytes += ret;
1835 info->idle_stats.xmit_idle = jiffies;
1836
Alan Cox15ed6cc2008-04-30 00:53:55 -07001837 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001838 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001839
Jiri Slaby02f11752006-12-08 02:39:28 -08001840 return ret;
1841} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843/*
1844 * This routine is called by the kernel to write a single
1845 * character to the tty device. If the kernel uses this routine,
1846 * it must call the flush_chars() routine (if defined) when it is
1847 * done stuffing characters into the driver. If there is no room
1848 * in the queue, the character is ignored.
1849 */
Alan Cox76b25a52008-04-30 00:54:03 -07001850static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001852 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001853 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001856 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857#endif
1858
Jiri Slaby02f11752006-12-08 02:39:28 -08001859 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001860 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
Alan Cox77451e52008-07-16 21:57:02 +01001862 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001863 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001865 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001866 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001867 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001868 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Alan Cox77451e52008-07-16 21:57:02 +01001871 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001872 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1873 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 info->idle_stats.xmit_bytes++;
1875 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001876 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001877 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001878} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880/*
1881 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001882 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001884static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001886 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001889 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890#endif
1891
Jiri Slaby02f11752006-12-08 02:39:28 -08001892 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1893 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Jiri Slaby02f11752006-12-08 02:39:28 -08001895 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001896 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001897 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
Jiri Slaby02f11752006-12-08 02:39:28 -08001899 start_xmit(info);
1900} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902/*
1903 * This routine returns the numbers of characters the tty driver
1904 * will accept for queuing to be written. This number is subject
1905 * to change as output buffers get emptied, or if the output flow
1906 * control is activated.
1907 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001908static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001910 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001911 int ret;
1912
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001914 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915#endif
1916
Jiri Slaby02f11752006-12-08 02:39:28 -08001917 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1918 return 0;
1919 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1920 if (ret < 0)
1921 ret = 0;
1922 return ret;
1923} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
Jiri Slaby02f11752006-12-08 02:39:28 -08001925static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001927 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
Jiri Slaby02f11752006-12-08 02:39:28 -08001929 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1930 return 0;
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001933 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001934#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001936 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1937 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001939 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08001941 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001942 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001943 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07001944 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001946 tx_get = readl(&buf_ctrl->tx_get);
1947 tx_put = readl(&buf_ctrl->tx_put);
1948 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08001949 if (tx_put >= tx_get)
1950 char_count = tx_put - tx_get;
1951 else
1952 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001954 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1955 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956#endif
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001957 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08001958 }
1959#endif /* Z_EXT_CHARS_IN_BUFFER */
1960} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
1962/*
1963 * ------------------------------------------------------------
1964 * cy_ioctl() and friends
1965 * ------------------------------------------------------------
1966 */
1967
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001968static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969{
Jiri Slaby02f11752006-12-08 02:39:28 -08001970 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001971 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08001972 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
Jiri Slaby02f11752006-12-08 02:39:28 -08001974 if (baud == 0) {
1975 info->tbpr = info->tco = info->rbpr = info->rco = 0;
1976 return;
1977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
Jiri Slaby02f11752006-12-08 02:39:28 -08001979 /* determine which prescaler to use */
1980 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
1981 if (cy_clock / co_val / baud > 63)
1982 break;
1983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Jiri Slaby02f11752006-12-08 02:39:28 -08001985 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
1986 if (bpr > 255)
1987 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Jiri Slaby02f11752006-12-08 02:39:28 -08001989 info->tbpr = info->rbpr = bpr;
1990 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991}
1992
1993/*
1994 * This routine finds or computes the various line characteristics.
1995 * It used to be called config_setup
1996 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001997static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998{
Jiri Slaby875b2062007-05-08 00:36:49 -07001999 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002000 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002001 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002002 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002003 int baud, baud_rate = 0;
2004 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Jiri Slabyd13549f2009-09-19 13:13:12 -07002006 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002007 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002008
2009 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002010 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002011
Jiri Slabyd13549f2009-09-19 13:13:12 -07002012 cflag = tty->termios->c_cflag;
2013 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Jiri Slaby02f11752006-12-08 02:39:28 -08002015 /*
2016 * Set up the tty->alt_speed kludge
2017 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002018 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2019 tty->alt_speed = 57600;
2020 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2021 tty->alt_speed = 115200;
2022 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2023 tty->alt_speed = 230400;
2024 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2025 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Jiri Slaby02f11752006-12-08 02:39:28 -08002027 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002028 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002029
Jiri Slaby2693f482009-06-11 12:31:06 +01002030 if (!cy_is_Z(card)) {
Jiri Slaby46fb7822009-09-19 13:13:17 -07002031 u32 cflags;
2032
Jiri Slaby02f11752006-12-08 02:39:28 -08002033 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002034 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002035 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002036 ASYNC_SPD_CUST) {
2037 if (info->custom_divisor)
2038 baud_rate = info->baud / info->custom_divisor;
2039 else
2040 baud_rate = info->baud;
2041 } else if (baud > CD1400_MAX_SPEED) {
2042 baud = CD1400_MAX_SPEED;
2043 }
2044 /* find the baud index */
2045 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002046 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002047 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002048 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002049 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002050 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002051
Alan Cox77451e52008-07-16 21:57:02 +01002052 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002053 ASYNC_SPD_CUST) {
2054 cyy_baud_calc(info, baud_rate);
2055 } else {
2056 if (info->chip_rev >= CD1400_REV_J) {
2057 /* It is a CD1400 rev. J or later */
2058 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2059 info->tco = baud_co_60[i]; /* Tx CO */
2060 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2061 info->rco = baud_co_60[i]; /* Rx CO */
2062 } else {
2063 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2064 info->tco = baud_co_25[i]; /* Tx CO */
2065 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2066 info->rco = baud_co_25[i]; /* Rx CO */
2067 }
2068 }
2069 if (baud_table[i] == 134) {
2070 /* get it right for 134.5 baud */
2071 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2072 2;
Alan Cox77451e52008-07-16 21:57:02 +01002073 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002074 ASYNC_SPD_CUST) {
2075 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2076 baud_rate) + 2;
2077 } else if (baud_table[i]) {
2078 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2079 baud_table[i]) + 2;
2080 /* this needs to be propagated into the card info */
2081 } else {
2082 info->timeout = 0;
2083 }
2084 /* By tradition (is it a standard?) a baud rate of zero
2085 implies the line should be/has been closed. A bit
2086 later in this routine such a test is performed. */
2087
2088 /* byte size and parity */
2089 info->cor5 = 0;
2090 info->cor4 = 0;
2091 /* receive threshold */
2092 info->cor3 = (info->default_threshold ?
2093 info->default_threshold : baud_cor3[i]);
2094 info->cor2 = CyETC;
2095 switch (cflag & CSIZE) {
2096 case CS5:
2097 info->cor1 = Cy_5_BITS;
2098 break;
2099 case CS6:
2100 info->cor1 = Cy_6_BITS;
2101 break;
2102 case CS7:
2103 info->cor1 = Cy_7_BITS;
2104 break;
2105 case CS8:
2106 info->cor1 = Cy_8_BITS;
2107 break;
2108 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002109 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002110 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002111
Jiri Slaby02f11752006-12-08 02:39:28 -08002112 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002113 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002114 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002115 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002116 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002117 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002118 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002119
2120 /* CTS flow control flag */
2121 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002122 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002123 info->cor2 |= CyCtsAE;
2124 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002125 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002126 info->cor2 &= ~CyCtsAE;
2127 }
2128 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002129 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002130 else
Alan Cox77451e52008-07-16 21:57:02 +01002131 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
2133 /***********************************************
2134 The hardware option, CyRtsAO, presents RTS when
2135 the chip has characters to send. Since most modems
2136 use RTS as reverse (inbound) flow control, this
2137 option is not used. If inbound flow control is
2138 necessary, DTR can be programmed to provide the
2139 appropriate signals for use with a non-standard
2140 cable. Contact Marcio Saito for details.
2141 ***********************************************/
2142
Jiri Slaby02f11752006-12-08 02:39:28 -08002143 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002145 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002146 cyy_writeb(info, CyCAR, channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
Jiri Slaby02f11752006-12-08 02:39:28 -08002148 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002150 cyy_writeb(info, CyTCOR, info->tco);
2151 cyy_writeb(info, CyTBPR, info->tbpr);
2152 cyy_writeb(info, CyRCOR, info->rco);
2153 cyy_writeb(info, CyRBPR, info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Jiri Slaby02f11752006-12-08 02:39:28 -08002155 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002157 cyy_writeb(info, CySCHR1, START_CHAR(tty));
2158 cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2159 cyy_writeb(info, CyCOR1, info->cor1);
2160 cyy_writeb(info, CyCOR2, info->cor2);
2161 cyy_writeb(info, CyCOR3, info->cor3);
2162 cyy_writeb(info, CyCOR4, info->cor4);
2163 cyy_writeb(info, CyCOR5, info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002165 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2166 CyCOR3ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
Alan Cox15ed6cc2008-04-30 00:53:55 -07002168 /* !!! Is this needed? */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002169 cyy_writeb(info, CyCAR, channel);
2170 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08002171 (info->default_timeout ? info->default_timeout : 0x02));
2172 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173
Jiri Slaby46fb7822009-09-19 13:13:17 -07002174 cflags = CyCTS;
2175 if (!C_CLOCAL(tty))
2176 cflags |= CyDSR | CyRI | CyDCD;
2177 /* without modem intr */
2178 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2179 /* act on 1->0 modem transitions */
2180 if ((cflag & CRTSCTS) && info->rflow)
2181 cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2182 else
2183 cyy_writeb(info, CyMCOR1, cflags);
2184 /* act on 0->1 modem transitions */
2185 cyy_writeb(info, CyMCOR2, cflags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002186
Jiri Slaby4d768202009-09-19 13:13:15 -07002187 if (i == 0) /* baud rate is zero, turn off line */
2188 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2189 else
2190 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Jiri Slabyd13549f2009-09-19 13:13:12 -07002192 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002193 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002196 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002197 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002198 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Jiri Slaby2693f482009-06-11 12:31:06 +01002200 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002201 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
Jiri Slaby02f11752006-12-08 02:39:28 -08002203 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002204 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002205 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002206 ASYNC_SPD_CUST) {
2207 if (info->custom_divisor)
2208 baud_rate = info->baud / info->custom_divisor;
2209 else
2210 baud_rate = info->baud;
2211 } else if (baud > CYZ_MAX_SPEED) {
2212 baud = CYZ_MAX_SPEED;
2213 }
2214 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 if (baud == 134) {
2217 /* get it right for 134.5 baud */
2218 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2219 2;
Alan Cox77451e52008-07-16 21:57:02 +01002220 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002221 ASYNC_SPD_CUST) {
2222 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2223 baud_rate) + 2;
2224 } else if (baud) {
2225 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2226 baud) + 2;
2227 /* this needs to be propagated into the card info */
2228 } else {
2229 info->timeout = 0;
2230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Jiri Slaby02f11752006-12-08 02:39:28 -08002232 /* byte size and parity */
2233 switch (cflag & CSIZE) {
2234 case CS5:
2235 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2236 break;
2237 case CS6:
2238 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2239 break;
2240 case CS7:
2241 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2242 break;
2243 case CS8:
2244 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2245 break;
2246 }
2247 if (cflag & CSTOPB) {
2248 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002249 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002250 } else {
2251 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002252 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002253 }
2254 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002255 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002256 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002257 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002258 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002259 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002260 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
Jiri Slaby02f11752006-12-08 02:39:28 -08002262 /* CTS flow control flag */
2263 if (cflag & CRTSCTS) {
2264 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002265 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002266 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002267 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2268 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002269 }
2270 /* As the HW flow control is done in firmware, the driver
2271 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002272 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002273
2274 /* XON/XOFF/XANY flow control flags */
2275 sw_flow = 0;
2276 if (iflag & IXON) {
2277 sw_flow |= C_FL_OXX;
2278 if (iflag & IXANY)
2279 sw_flow |= C_FL_OIXANY;
2280 }
2281 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2282
Jiri Slaby875b2062007-05-08 00:36:49 -07002283 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002284 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002285 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2286 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002287 }
2288
2289 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002290 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002291 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002292 else
Alan Cox77451e52008-07-16 21:57:02 +01002293 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002294
2295 if (baud == 0) { /* baud rate is zero, turn off line */
2296 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002297 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002299 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002301 } else {
2302 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002303 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002305 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Alan Cox15ed6cc2008-04-30 00:53:55 -07002309 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002310 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002311 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2312 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Jiri Slabyd13549f2009-09-19 13:13:12 -07002315 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002317} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Jiri Slaby6c281812009-09-19 13:13:15 -07002319static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002320 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321{
Jiri Slaby875b2062007-05-08 00:36:49 -07002322 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002323 struct serial_struct tmp = {
2324 .type = info->type,
2325 .line = info->line,
2326 .port = (info->card - cy_card) * 0x100 + info->line -
2327 cinfo->first_line,
2328 .irq = cinfo->irq,
2329 .flags = info->port.flags,
2330 .close_delay = info->port.close_delay,
2331 .closing_wait = info->port.closing_wait,
2332 .baud_base = info->baud,
2333 .custom_divisor = info->custom_divisor,
2334 .hub6 = 0, /*!!! */
2335 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002336 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002337}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002340cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002341 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342{
Jiri Slaby02f11752006-12-08 02:39:28 -08002343 struct serial_struct new_serial;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002344 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Jiri Slaby02f11752006-12-08 02:39:28 -08002346 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2347 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Alan Cox25c3cdf2010-06-01 22:52:47 +02002349 mutex_lock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002350 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002351 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002352 new_serial.baud_base != info->baud ||
2353 (new_serial.flags & ASYNC_FLAGS &
2354 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002355 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Alan Cox25c3cdf2010-06-01 22:52:47 +02002356 {
2357 mutex_unlock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002358 return -EPERM;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002359 }
Alan Cox77451e52008-07-16 21:57:02 +01002360 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002361 (new_serial.flags & ASYNC_USR_MASK);
2362 info->baud = new_serial.baud_base;
2363 info->custom_divisor = new_serial.custom_divisor;
2364 goto check_and_exit;
2365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Jiri Slaby02f11752006-12-08 02:39:28 -08002367 /*
2368 * OK, past this point, all the error checking has been done.
2369 * At this point, we start making changes.....
2370 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Jiri Slaby02f11752006-12-08 02:39:28 -08002372 info->baud = new_serial.baud_base;
2373 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002374 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002375 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002376 info->port.close_delay = new_serial.close_delay * HZ / 100;
2377 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
2379check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002380 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002381 cy_set_line_char(info, tty);
Alan Cox25c3cdf2010-06-01 22:52:47 +02002382 ret = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002383 } else {
Alan Cox25c3cdf2010-06-01 22:52:47 +02002384 ret = cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002385 }
Alan Cox25c3cdf2010-06-01 22:52:47 +02002386 mutex_unlock(&info->port.mutex);
2387 return ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002388} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389
2390/*
2391 * get_lsr_info - get line status register info
2392 *
2393 * Purpose: Let user call ioctl() to get info when the UART physically
2394 * is emptied. On bus types like RS485, the transmitter must
2395 * release the bus after transmitting. This must be done when
2396 * the transmit shift register is empty, not be done when the
2397 * transmit holding register is empty. This functionality
2398 * allows an RS485 driver to be written in user space.
2399 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002400static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002402 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002403 unsigned int result;
2404 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002405 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Jiri Slaby2693f482009-06-11 12:31:06 +01002407 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002408 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002409 status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002410 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002411 result = (status ? 0 : TIOCSER_TEMT);
2412 } else {
2413 /* Not supported yet */
2414 return -EINVAL;
2415 }
2416 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417}
2418
Alan Cox60b33c12011-02-14 16:26:14 +00002419static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002421 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002422 struct cyclades_card *card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002423 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002425 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002426 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Jiri Slaby02f11752006-12-08 02:39:28 -08002428 card = info->card;
Jiri Slaby0d348722009-09-19 13:13:16 -07002429
Jiri Slaby2693f482009-06-11 12:31:06 +01002430 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002431 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002432 int channel = info->line - card->first_line;
2433 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002435 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002436 cyy_writeb(info, CyCAR, channel & 0x03);
2437 status = cyy_readb(info, CyMSVR1);
2438 status |= cyy_readb(info, CyMSVR2);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002439 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
Jiri Slaby02f11752006-12-08 02:39:28 -08002441 if (info->rtsdtr_inv) {
2442 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2443 ((status & CyDTR) ? TIOCM_RTS : 0);
2444 } else {
2445 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2446 ((status & CyDTR) ? TIOCM_DTR : 0);
2447 }
2448 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2449 ((status & CyRI) ? TIOCM_RNG : 0) |
2450 ((status & CyDSR) ? TIOCM_DSR : 0) |
2451 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002453 u32 lstatus;
2454
2455 if (!cyz_is_loaded(card)) {
2456 result = -ENODEV;
2457 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002458 }
2459
Jiri Slaby0d348722009-09-19 13:13:16 -07002460 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2461 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2462 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2463 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2464 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2465 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2466 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002468end:
Jiri Slaby02f11752006-12-08 02:39:28 -08002469 return result;
2470} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
2472static int
Alan Cox20b9d172011-02-14 16:26:50 +00002473cy_tiocmset(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002474 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002476 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002477 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002478 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002480 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002481 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
Jiri Slaby02f11752006-12-08 02:39:28 -08002483 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002484 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002485 spin_lock_irqsave(&card->card_lock, flags);
2486 cyy_change_rts_dtr(info, set, clear);
2487 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002488 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002489 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2490 int retval, channel = info->line - card->first_line;
2491 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002492
Jiri Slaby0d348722009-09-19 13:13:16 -07002493 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002494 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002495
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002496 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002497 rs = readl(&ch_ctrl->rs_control);
2498 if (set & TIOCM_RTS)
2499 rs |= C_RS_RTS;
2500 if (clear & TIOCM_RTS)
2501 rs &= ~C_RS_RTS;
2502 if (set & TIOCM_DTR) {
2503 rs |= C_RS_DTR;
2504#ifdef CY_DEBUG_DTR
2505 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2506#endif
2507 }
2508 if (clear & TIOCM_DTR) {
2509 rs &= ~C_RS_DTR;
2510#ifdef CY_DEBUG_DTR
2511 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2512 "Z DTR\n");
2513#endif
2514 }
2515 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002516 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002517 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002518 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002519 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2520 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002523 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002524}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
2526/*
2527 * cy_break() --- routine which turns the break handling on or off
2528 */
Alan Cox9e989662008-07-22 11:18:03 +01002529static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002531 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002532 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002533 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002534 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Jiri Slaby02f11752006-12-08 02:39:28 -08002536 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002537 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002539 card = info->card;
2540
2541 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002542 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002543 /* Let the transmit ISR take care of this (since it
2544 requires stuffing characters into the output stream).
2545 */
2546 if (break_state == -1) {
2547 if (!info->breakon) {
2548 info->breakon = 1;
2549 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002550 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002551 start_xmit(info);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002552 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002553 }
2554 }
2555 } else {
2556 if (!info->breakoff) {
2557 info->breakoff = 1;
2558 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002559 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002560 start_xmit(info);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002561 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002562 }
2563 }
2564 }
2565 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002566 if (break_state == -1) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002567 retval = cyz_issue_cmd(card,
2568 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002569 C_CM_SET_BREAK, 0L);
2570 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002571 printk(KERN_ERR "cyc:cy_break (set) retval on "
2572 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002573 }
2574 } else {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002575 retval = cyz_issue_cmd(card,
2576 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002577 C_CM_CLR_BREAK, 0L);
2578 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002579 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2580 "on ttyC%d was %x\n", info->line,
2581 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002582 }
2583 }
2584 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002585 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002586 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002587} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
Jiri Slaby02f11752006-12-08 02:39:28 -08002589static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002591 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002592 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
Jiri Slaby2693f482009-06-11 12:31:06 +01002594 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002595 info->cor3 &= ~CyREC_FIFO;
2596 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002598 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002599 cyy_writeb(info, CyCOR3, info->cor3);
2600 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002601 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002604} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Alan Cox15ed6cc2008-04-30 00:53:55 -07002606static int get_threshold(struct cyclades_port *info,
2607 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002609 struct cyclades_card *card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Jiri Slaby2693f482009-06-11 12:31:06 +01002611 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002612 u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002613 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002614 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002615 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002616} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
Jiri Slaby02f11752006-12-08 02:39:28 -08002618static int set_timeout(struct cyclades_port *info, unsigned long value)
2619{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002620 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002621 unsigned long flags;
2622
Jiri Slaby2693f482009-06-11 12:31:06 +01002623 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002624 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002625 cyy_writeb(info, CyRTPR, value & 0xff);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002626 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002627 }
2628 return 0;
2629} /* set_timeout */
2630
Alan Cox15ed6cc2008-04-30 00:53:55 -07002631static int get_timeout(struct cyclades_port *info,
2632 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002633{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002634 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002635
Jiri Slaby2693f482009-06-11 12:31:06 +01002636 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002637 u8 tmp = cyy_readb(info, CyRTPR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002638 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002639 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002640 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002641} /* get_timeout */
2642
Jiri Slaby6c281812009-09-19 13:13:15 -07002643static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2644 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002645{
Jiri Slaby6c281812009-09-19 13:13:15 -07002646 struct cyclades_icount cnow;
2647 unsigned long flags;
2648 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002649
Jiri Slaby6c281812009-09-19 13:13:15 -07002650 spin_lock_irqsave(&info->card->card_lock, flags);
2651 cnow = info->icount; /* atomic copy */
2652 spin_unlock_irqrestore(&info->card->card_lock, flags);
2653
2654 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2655 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2656 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2657 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2658
2659 *cprev = cnow;
2660
2661 return ret;
2662}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664/*
2665 * This routine allows the tty driver to implement device-
2666 * specific ioctl's. If the ioctl number passed in cmd is
2667 * not recognized by the driver, it should return ENOIOCTLCMD.
2668 */
2669static int
Alan Cox6caa76b2011-02-14 16:27:22 +00002670cy_ioctl(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002671 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002673 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002674 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002675 int ret_val = 0;
2676 unsigned long flags;
2677 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
Jiri Slaby02f11752006-12-08 02:39:28 -08002679 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2680 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
2682#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002683 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2684 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685#endif
2686
Jiri Slaby02f11752006-12-08 02:39:28 -08002687 switch (cmd) {
2688 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002689 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2690 ret_val = -EFAULT;
2691 break;
2692 }
2693 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002695 case CYGETTHRESH:
2696 ret_val = get_threshold(info, argp);
2697 break;
2698 case CYSETTHRESH:
2699 ret_val = set_threshold(info, arg);
2700 break;
2701 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002702 ret_val = put_user(info->default_threshold,
2703 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002704 break;
2705 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002706 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002707 break;
2708 case CYGETTIMEOUT:
2709 ret_val = get_timeout(info, argp);
2710 break;
2711 case CYSETTIMEOUT:
2712 ret_val = set_timeout(info, arg);
2713 break;
2714 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002715 ret_val = put_user(info->default_timeout,
2716 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002717 break;
2718 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002719 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002720 break;
2721 case CYSETRFLOW:
2722 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002723 break;
2724 case CYGETRFLOW:
2725 ret_val = info->rflow;
2726 break;
2727 case CYSETRTSDTR_INV:
2728 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002729 break;
2730 case CYGETRTSDTR_INV:
2731 ret_val = info->rtsdtr_inv;
2732 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 ret_val = info->chip_rev;
2735 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736#ifndef CONFIG_CYZ_INTR
2737 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002738 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002739 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002741 ret_val = (cyz_polling_cycle * 1000) / HZ;
2742 break;
2743#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002745 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002746 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002748 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002749 break;
2750 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002751 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002752 break;
2753 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002754 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002755 break;
2756 case TIOCSERGETLSR: /* Get line status register */
2757 ret_val = get_lsr_info(info, argp);
2758 break;
2759 /*
2760 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2761 * - mask passed in arg for lines of interest
2762 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2763 * Caller should use TIOCGICOUNT to see which one it was
2764 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 case TIOCMIWAIT:
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002766 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002767 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002768 cnow = info->icount;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002769 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Coxbdc04e32009-09-19 13:13:31 -07002770 ret_val = wait_event_interruptible(info->port.delta_msr_wait,
Jiri Slaby6c281812009-09-19 13:13:15 -07002771 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002772 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002773
2774 /*
2775 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2776 * Return: write counters to the user passed counter struct
2777 * NB: both 1->0 and 0->1 transitions are counted except for
2778 * RI where only 0->1 is counted.
2779 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002780 default:
2781 ret_val = -ENOIOCTLCMD;
2782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002785 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002787 return ret_val;
2788} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Alan Cox05871022010-09-16 18:21:52 +01002790static int cy_get_icount(struct tty_struct *tty,
2791 struct serial_icounter_struct *sic)
2792{
2793 struct cyclades_port *info = tty->driver_data;
2794 struct cyclades_icount cnow; /* Used to snapshot */
2795 unsigned long flags;
2796
2797 spin_lock_irqsave(&info->card->card_lock, flags);
2798 cnow = info->icount;
2799 spin_unlock_irqrestore(&info->card->card_lock, flags);
2800
2801 sic->cts = cnow.cts;
2802 sic->dsr = cnow.dsr;
2803 sic->rng = cnow.rng;
2804 sic->dcd = cnow.dcd;
2805 sic->rx = cnow.rx;
2806 sic->tx = cnow.tx;
2807 sic->frame = cnow.frame;
2808 sic->overrun = cnow.overrun;
2809 sic->parity = cnow.parity;
2810 sic->brk = cnow.brk;
2811 sic->buf_overrun = cnow.buf_overrun;
2812 return 0;
2813}
2814
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815/*
2816 * This routine allows the tty driver to be notified when
2817 * device's termios settings have changed. Note that a
2818 * well-designed tty driver should be prepared to accept the case
2819 * where old == NULL, and try to do something rational.
2820 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002821static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002823 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
2825#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002826 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827#endif
2828
Jiri Slabyd13549f2009-09-19 13:13:12 -07002829 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
Jiri Slaby02f11752006-12-08 02:39:28 -08002831 if ((old_termios->c_cflag & CRTSCTS) &&
2832 !(tty->termios->c_cflag & CRTSCTS)) {
2833 tty->hw_stopped = 0;
2834 cy_start(tty);
2835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002837 /*
2838 * No need to wake up processes in open wait, since they
2839 * sample the CLOCAL flag once, and don't recheck it.
2840 * XXX It's not clear whether the current behavior is correct
2841 * or not. Hence, this may change.....
2842 */
2843 if (!(old_termios->c_cflag & CLOCAL) &&
2844 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01002845 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002847} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
2849/* This function is used to send a high-priority XON/XOFF character to
2850 the device.
2851*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002852static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002854 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002855 struct cyclades_card *card;
2856 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Jiri Slaby02f11752006-12-08 02:39:28 -08002858 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 return;
2860
Jiri Slaby02f11752006-12-08 02:39:28 -08002861 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
2863 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08002864 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865
2866 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002867 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
Jiri Slaby2693f482009-06-11 12:31:06 +01002869 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002870 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002871 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002872 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002873 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 }
2875}
2876
2877/* This routine is called by the upper-layer tty layer to signal
2878 that incoming characters should be throttled because the input
2879 buffers are close to full.
2880 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002881static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002883 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002884 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002885 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002888 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
Jiri Slaby21719192007-05-08 00:36:42 -07002890 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08002891 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892#endif
2893
Alan Cox15ed6cc2008-04-30 00:53:55 -07002894 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002895 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
Jiri Slaby02f11752006-12-08 02:39:28 -08002897 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
Jiri Slaby02f11752006-12-08 02:39:28 -08002899 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002900 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002901 cy_send_xchar(tty, STOP_CHAR(tty));
2902 else
2903 info->throttle = 1;
2904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Jiri Slaby02f11752006-12-08 02:39:28 -08002906 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002907 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002908 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002909 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002910 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002911 } else {
2912 info->throttle = 1;
2913 }
2914 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002915} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917/*
2918 * This routine notifies the tty driver that it should signal
2919 * that characters can now be sent to the tty without fear of
2920 * overrunning the input buffers of the line disciplines.
2921 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002922static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002924 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002925 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002926 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002929 char buf[64];
2930
Jiri Slaby21719192007-05-08 00:36:42 -07002931 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07002932 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933#endif
2934
Alan Cox15ed6cc2008-04-30 00:53:55 -07002935 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002936 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Jiri Slaby02f11752006-12-08 02:39:28 -08002938 if (I_IXOFF(tty)) {
2939 if (info->x_char)
2940 info->x_char = 0;
2941 else
2942 cy_send_xchar(tty, START_CHAR(tty));
2943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Jiri Slaby02f11752006-12-08 02:39:28 -08002945 if (tty->termios->c_cflag & CRTSCTS) {
2946 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002947 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002948 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002949 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002950 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002951 } else {
2952 info->throttle = 0;
2953 }
2954 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002955} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
2957/* cy_start and cy_stop provide software output flow control as a
2958 function of XON/XOFF, software CTS, and other such stuff.
2959*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002960static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961{
Jiri Slaby02f11752006-12-08 02:39:28 -08002962 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002963 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002964 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002965 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
2967#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002968 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969#endif
2970
Jiri Slaby02f11752006-12-08 02:39:28 -08002971 if (serial_paranoia_check(info, tty->name, "cy_stop"))
2972 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Jiri Slaby875b2062007-05-08 00:36:49 -07002974 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002975 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002976 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002977 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002978 cyy_writeb(info, CyCAR, channel & 0x03);
2979 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002980 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002982} /* cy_stop */
2983
2984static void cy_start(struct tty_struct *tty)
2985{
2986 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002987 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002988 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002989 unsigned long flags;
2990
2991#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002992 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08002993#endif
2994
2995 if (serial_paranoia_check(info, tty->name, "cy_start"))
2996 return;
2997
Jiri Slaby875b2062007-05-08 00:36:49 -07002998 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002999 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003000 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003001 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003002 cyy_writeb(info, CyCAR, channel & 0x03);
3003 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003004 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003005 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003006} /* cy_start */
3007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008/*
3009 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3010 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003011static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003013 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003014
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003016 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017#endif
3018
Jiri Slaby02f11752006-12-08 02:39:28 -08003019 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3020 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
Jiri Slaby02f11752006-12-08 02:39:28 -08003022 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003023 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003024 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003025} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Jiri Slabyf0737572009-09-19 13:13:12 -07003027static int cyy_carrier_raised(struct tty_port *port)
3028{
3029 struct cyclades_port *info = container_of(port, struct cyclades_port,
3030 port);
3031 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003032 unsigned long flags;
3033 int channel = info->line - cinfo->first_line;
Jiri Slabyf0737572009-09-19 13:13:12 -07003034 u32 cd;
3035
Jiri Slabyf0737572009-09-19 13:13:12 -07003036 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003037 cyy_writeb(info, CyCAR, channel & 0x03);
3038 cd = cyy_readb(info, CyMSVR1) & CyDCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003039 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3040
3041 return cd;
3042}
3043
3044static void cyy_dtr_rts(struct tty_port *port, int raise)
3045{
3046 struct cyclades_port *info = container_of(port, struct cyclades_port,
3047 port);
3048 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003049 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003050
3051 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003052 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3053 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003054 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3055}
3056
3057static int cyz_carrier_raised(struct tty_port *port)
3058{
3059 struct cyclades_port *info = container_of(port, struct cyclades_port,
3060 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003061
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003062 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003063}
3064
3065static void cyz_dtr_rts(struct tty_port *port, int raise)
3066{
3067 struct cyclades_port *info = container_of(port, struct cyclades_port,
3068 port);
3069 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003070 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003071 int ret, channel = info->line - cinfo->first_line;
3072 u32 rs;
3073
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003074 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003075 if (raise)
3076 rs |= C_RS_RTS | C_RS_DTR;
3077 else
3078 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003079 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003080 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3081 if (ret != 0)
3082 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3083 __func__, info->line, ret);
3084#ifdef CY_DEBUG_DTR
3085 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3086#endif
3087}
3088
3089static const struct tty_port_operations cyy_port_ops = {
3090 .carrier_raised = cyy_carrier_raised,
3091 .dtr_rts = cyy_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003092 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003093};
3094
3095static const struct tty_port_operations cyz_port_ops = {
3096 .carrier_raised = cyz_carrier_raised,
3097 .dtr_rts = cyz_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003098 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003099};
3100
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101/*
3102 * ---------------------------------------------------------------------
3103 * cy_init() and friends
3104 *
3105 * cy_init() is called at boot-time to initialize the serial driver.
3106 * ---------------------------------------------------------------------
3107 */
3108
Jiri Slabydd025c02007-05-08 00:37:02 -07003109static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003110{
3111 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003112 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003113
Jiri Slaby3046d502007-05-08 00:36:46 -07003114 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003115 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003116
Jiri Slaby963118e2009-06-11 12:34:27 +01003117 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3118 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003119 if (cinfo->ports == NULL) {
3120 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3121 return -ENOMEM;
3122 }
3123
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003124 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3125 channel++, port++) {
3126 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003127 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003128 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003129 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003130 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003131
Alan Cox44b7d1b2008-07-16 21:57:18 +01003132 info->port.closing_wait = CLOSING_WAIT_DELAY;
3133 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003134 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003135 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003136
Jiri Slaby2693f482009-06-11 12:31:06 +01003137 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003138 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3139 struct ZFW_CTRL *zfw_ctrl;
3140
Jiri Slabyf0737572009-09-19 13:13:12 -07003141 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003142 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003143
3144 zfw_ctrl = cinfo->base_addr +
3145 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3146 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3147 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3148
Jiri Slaby101b8152009-06-11 12:30:10 +01003149 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003150 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3151 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003152 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003153#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003154 setup_timer(&cyz_rx_full_timer[port],
3155 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003156#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003157 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003158 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003159 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003160
Jiri Slabyf0737572009-09-19 13:13:12 -07003161 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003162 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003163 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003164 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003165 info->cor2 = CyETC;
3166 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003167
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003168 chip_number = channel / CyPORTS_PER_CHIP;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003169 info->u.cyy.base_addr = cinfo->base_addr +
3170 (cy_chip_offset[chip_number] << index);
3171 info->chip_rev = cyy_readb(info, CyGFRCR);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003172
3173 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003174 /* It is a CD1400 rev. J or later */
3175 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3176 info->tco = baud_co_60[13]; /* Tx CO */
3177 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3178 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003179 info->rtsdtr_inv = 1;
3180 } else {
3181 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3182 info->tco = baud_co_25[13]; /* Tx CO */
3183 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3184 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003185 info->rtsdtr_inv = 0;
3186 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003187 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3188 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003189 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003190
Jiri Slaby0809e262007-05-08 00:36:14 -07003191 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003192
3193#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003194 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003195 mod_timer(&cyz_timerlist, jiffies + 1);
3196#ifdef CY_PCI_DEBUG
3197 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3198#endif
3199 }
3200#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003201 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003202}
3203
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204/* initialize chips on Cyclom-Y card -- return number of valid
3205 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003206static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3207 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
Jiri Slaby02f11752006-12-08 02:39:28 -08003209 unsigned int chip_number;
3210 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
Jiri Slaby02f11752006-12-08 02:39:28 -08003212 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3213 /* Cy_HwReset is 0x1400 */
3214 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3215 /* Cy_ClrIntr is 0x1800 */
3216 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Alan Cox15ed6cc2008-04-30 00:53:55 -07003218 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3219 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003220 base_addr =
3221 true_base_addr + (cy_chip_offset[chip_number] << index);
3222 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003223 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003224 /*************
3225 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3226 chip_number, (unsigned long)base_addr);
3227 *************/
3228 return chip_number;
3229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
Jiri Slaby02f11752006-12-08 02:39:28 -08003231 cy_writeb(base_addr + (CyGFRCR << index), 0);
3232 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
Jiri Slaby02f11752006-12-08 02:39:28 -08003234 /* The Cyclom-16Y does not decode address bit 9 and therefore
3235 cannot distinguish between references to chip 0 and a non-
3236 existent chip 4. If the preceding clearing of the supposed
3237 chip 4 GFRCR register appears at chip 0, there is no chip 4
3238 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3239 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003240 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003241 (cy_chip_offset[0] << index) +
3242 (CyGFRCR << index)) == 0) {
3243 return chip_number;
3244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
Jiri Slaby02f11752006-12-08 02:39:28 -08003246 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3247 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003249 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003250 /*
3251 printk(" chip #%d at %#6lx is not responding ",
3252 chip_number, (unsigned long)base_addr);
3253 printk("(GFRCR stayed 0)\n",
3254 */
3255 return chip_number;
3256 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003257 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003258 0x40) {
3259 /*
3260 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3261 "%#2x)\n",
3262 chip_number, (unsigned long)base_addr,
3263 base_addr[CyGFRCR<<index]);
3264 */
3265 return chip_number;
3266 }
3267 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003268 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003269 /* It is a CD1400 rev. J or later */
3270 /* Impossible to reach 5ms with this chip.
3271 Changed to 2ms instead (f = 500 Hz). */
3272 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3273 } else {
3274 /* f = 200 Hz */
3275 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3276 }
3277
3278 /*
3279 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3280 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003281 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003282 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003284 return chip_number;
3285} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
3287/*
3288 * ---------------------------------------------------------------------
3289 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3290 * sets global variables and return the number of ISA boards found.
3291 * ---------------------------------------------------------------------
3292 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003293static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294{
3295#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003296 unsigned short cy_isa_irq, nboard;
3297 void __iomem *cy_isa_address;
3298 unsigned short i, j, cy_isa_nchan;
Jiri Slaby02f11752006-12-08 02:39:28 -08003299 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
Jiri Slaby02f11752006-12-08 02:39:28 -08003301 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003304 for (i = 0; i < NR_CARDS; i++) {
3305 if (maddr[i] || i) {
3306 isparam = 1;
3307 cy_isa_addresses[i] = maddr[i];
3308 }
3309 if (!maddr[i])
3310 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
Jiri Slaby02f11752006-12-08 02:39:28 -08003313 /* scan the address table probing for Cyclom-Y/ISA boards */
3314 for (i = 0; i < NR_ISA_ADDRS; i++) {
3315 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003316 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003317 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
Jiri Slaby02f11752006-12-08 02:39:28 -08003319 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003320 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003321 if (cy_isa_address == NULL) {
3322 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3323 "address\n");
3324 continue;
3325 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003326 cy_isa_nchan = CyPORTS_PER_CHIP *
3327 cyy_init_card(cy_isa_address, 0);
3328 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003329 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003330 continue;
3331 }
Bartlomiej Zolnierkiewicz20904362009-12-09 12:34:14 -08003332
Roel Kluin196b3162009-10-01 15:44:24 -07003333 if (isparam && i < NR_CARDS && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003334 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 else
Jiri Slaby02f11752006-12-08 02:39:28 -08003336 /* find out the board's irq by probing */
3337 cy_isa_irq = detect_isa_irq(cy_isa_address);
3338 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003339 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3340 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003341 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003342 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003343 continue;
3344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
Jiri Slaby02f11752006-12-08 02:39:28 -08003346 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003347 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3348 "more channels are available. Change NR_PORTS "
3349 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003350 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003351 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003352 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003353 }
3354 /* fill the next cy_card structure available */
3355 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003356 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003357 break;
3358 }
3359 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003360 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3361 "more cards can be used. Change NR_CARDS in "
3362 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003363 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003364 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003365 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
Jiri Slaby02f11752006-12-08 02:39:28 -08003368 /* allocate IRQ */
3369 if (request_irq(cy_isa_irq, cyy_interrupt,
Yong Zhang9cfb5c02011-09-22 16:59:15 +08003370 0, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003371 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3372 "could not allocate IRQ#%d.\n",
3373 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003374 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003375 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
Jiri Slaby02f11752006-12-08 02:39:28 -08003378 /* set cy_card */
3379 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003380 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003381 cy_card[j].irq = (int)cy_isa_irq;
3382 cy_card[j].bus_index = 0;
3383 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003384 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3385 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003386 if (cy_init_card(&cy_card[j])) {
3387 cy_card[j].base_addr = NULL;
3388 free_irq(cy_isa_irq, &cy_card[j]);
3389 iounmap(cy_isa_address);
3390 continue;
3391 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003392 nboard++;
3393
Jiri Slaby21719192007-05-08 00:36:42 -07003394 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3395 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003396 j + 1, (unsigned long)cy_isa_address,
3397 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003398 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3399
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003400 for (j = cy_next_channel;
3401 j < cy_next_channel + cy_isa_nchan; j++)
3402 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003403 cy_next_channel += cy_isa_nchan;
3404 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003405 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003407 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003408#endif /* CONFIG_ISA */
3409} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410
Jiri Slaby58936d82007-05-08 00:36:13 -07003411#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003412static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3413{
3414 unsigned int a;
3415
3416 for (a = 0; a < size && *str; a++, str++)
3417 if (*str & 0x80)
3418 return -EINVAL;
3419
3420 for (; a < size; a++, str++)
3421 if (*str)
3422 return -EINVAL;
3423
3424 return 0;
3425}
3426
David Woodhousef61e7612008-05-23 23:57:19 +01003427static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003428 unsigned int size)
3429{
3430 for (; size > 0; size--) {
3431 cy_writel(fpga, *data++);
3432 udelay(10);
3433 }
3434}
3435
3436static void __devinit plx_init(struct pci_dev *pdev, int irq,
3437 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438{
Jiri Slaby02f11752006-12-08 02:39:28 -08003439 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003440 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
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) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Jiri Slaby02f11752006-12-08 02:39:28 -08003444 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003445 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003446 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003447 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3448
3449 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3450 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3451 * registers. This will remain here until we find a permanent fix.
3452 */
3453 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3454}
3455
3456static int __devinit __cyz_load_fw(const struct firmware *fw,
3457 const char *name, const u32 mailbox, void __iomem *base,
3458 void __iomem *fpga)
3459{
David Woodhousef61e7612008-05-23 23:57:19 +01003460 const void *ptr = fw->data;
3461 const struct zfile_header *h = ptr;
3462 const struct zfile_config *c, *cs;
3463 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003464 unsigned int a, tmp, len = fw->size;
3465#define BAD_FW KERN_ERR "Bad firmware: "
3466 if (len < sizeof(*h)) {
3467 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3468 return -EINVAL;
3469 }
3470
3471 cs = ptr + h->config_offset;
3472 bs = ptr + h->block_offset;
3473
3474 if ((void *)(cs + h->n_config) > ptr + len ||
3475 (void *)(bs + h->n_blocks) > ptr + len) {
3476 printk(BAD_FW "too short");
3477 return -EINVAL;
3478 }
3479
3480 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3481 cyc_isfwstr(h->date, sizeof(h->date))) {
3482 printk(BAD_FW "bad formatted header string\n");
3483 return -EINVAL;
3484 }
3485
3486 if (strncmp(name, h->name, sizeof(h->name))) {
3487 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3488 return -EINVAL;
3489 }
3490
3491 tmp = 0;
3492 for (c = cs; c < cs + h->n_config; c++) {
3493 for (a = 0; a < c->n_blocks; a++)
3494 if (c->block_list[a] > h->n_blocks) {
3495 printk(BAD_FW "bad block ref number in cfgs\n");
3496 return -EINVAL;
3497 }
3498 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3499 tmp++;
3500 }
3501 if (!tmp) {
3502 printk(BAD_FW "nothing appropriate\n");
3503 return -EINVAL;
3504 }
3505
3506 for (b = bs; b < bs + h->n_blocks; b++)
3507 if (b->file_offset + b->size > len) {
3508 printk(BAD_FW "bad block data offset\n");
3509 return -EINVAL;
3510 }
3511
3512 /* everything is OK, let's seek'n'load it */
3513 for (c = cs; c < cs + h->n_config; c++)
3514 if (c->mailbox == mailbox && c->function == 0)
3515 break;
3516
3517 for (a = 0; a < c->n_blocks; a++) {
3518 b = &bs[c->block_list[a]];
3519 if (b->type == ZBLOCK_FPGA) {
3520 if (fpga != NULL)
3521 cyz_fpga_copy(fpga, ptr + b->file_offset,
3522 b->size);
3523 } else {
3524 if (base != NULL)
3525 memcpy_toio(base + b->ram_offset,
3526 ptr + b->file_offset, b->size);
3527 }
3528 }
3529#undef BAD_FW
3530 return 0;
3531}
3532
3533static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3534 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3535{
3536 const struct firmware *fw;
3537 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3538 struct CUSTOM_REG __iomem *cust = base_addr;
3539 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003540 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003541 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003542 unsigned int i;
3543 int retval;
3544
3545 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3546 if (retval) {
3547 dev_err(&pdev->dev, "can't get firmware\n");
3548 goto err;
3549 }
3550
3551 /* Check whether the firmware is already loaded and running. If
3552 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003553 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003554 u32 cntval = readl(base_addr + 0x190);
3555
3556 udelay(100);
3557 if (cntval != readl(base_addr + 0x190)) {
3558 /* FW counter is working, FW is running */
3559 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3560 "Skipping board.\n");
3561 retval = 0;
3562 goto err_rel;
3563 }
3564 }
3565
3566 /* start boot */
3567 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3568 ~0x00030800UL);
3569
3570 mailbox = readl(&ctl_addr->mail_box_0);
3571
Jiri Slaby2693f482009-06-11 12:31:06 +01003572 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003573 /* stops CPU and set window to beginning of RAM */
3574 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3575 cy_writel(&cust->cpu_stop, 0);
3576 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3577 udelay(100);
3578 }
3579
3580 plx_init(pdev, irq, ctl_addr);
3581
3582 if (mailbox != 0) {
3583 /* load FPGA */
3584 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3585 base_addr);
3586 if (retval)
3587 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003588 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003589 dev_err(&pdev->dev, "fw upload successful, but fw is "
3590 "not loaded\n");
3591 goto err_rel;
3592 }
3593 }
3594
3595 /* stops CPU and set window to beginning of RAM */
3596 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3597 cy_writel(&cust->cpu_stop, 0);
3598 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3599 udelay(100);
3600
3601 /* clear memory */
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 if (mailbox != 0) {
3605 /* set window to last 512K of RAM */
3606 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003607 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003608 cy_writeb(tmp, 255);
3609 /* set window to beginning of RAM */
3610 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003611 }
3612
3613 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3614 release_firmware(fw);
3615 if (retval)
3616 goto err;
3617
3618 /* finish boot and start boards */
3619 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3620 cy_writel(&cust->cpu_start, 0);
3621 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3622 i = 0;
3623 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3624 msleep(100);
3625 if (status != ZFIRM_ID) {
3626 if (status == ZFIRM_HLT) {
3627 dev_err(&pdev->dev, "you need an external power supply "
3628 "for this number of ports. Firmware halted and "
3629 "board reset.\n");
3630 retval = -EIO;
3631 goto err;
3632 }
3633 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3634 "some more time\n", status);
3635 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3636 i++ < 200)
3637 msleep(100);
3638 if (status != ZFIRM_ID) {
3639 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3640 "Giving up. (fid->signature = 0x%x)\n",
3641 status);
3642 dev_info(&pdev->dev, "*** Warning ***: if you are "
3643 "upgrading the FW, please power cycle the "
3644 "system before loading the new FW to the "
3645 "Cyclades-Z.\n");
3646
Jiri Slaby2693f482009-06-11 12:31:06 +01003647 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003648 plx_init(pdev, irq, ctl_addr);
3649
3650 retval = -EIO;
3651 goto err;
3652 }
3653 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3654 i / 10);
3655 }
3656 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3657
3658 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3659 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3660 base_addr + readl(&fid->zfwctrl_addr));
3661
Jiri Slaby963118e2009-06-11 12:34:27 +01003662 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003663 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003664 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003665
Jiri Slaby963118e2009-06-11 12:34:27 +01003666 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003667 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3668 "check the connection between the Z host card and the "
3669 "serial expanders.\n");
3670
Jiri Slaby2693f482009-06-11 12:31:06 +01003671 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003672 plx_init(pdev, irq, ctl_addr);
3673
3674 dev_info(&pdev->dev, "Null number of ports detected. Board "
3675 "reset.\n");
3676 retval = 0;
3677 goto err;
3678 }
3679
3680 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3681 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3682
3683 /*
3684 Early firmware failed to start looking for commands.
3685 This enables firmware interrupts for those commands.
3686 */
3687 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3688 (1 << 17));
3689 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3690 0x00030800UL);
3691
Jiri Slaby963118e2009-06-11 12:34:27 +01003692 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003693err_rel:
3694 release_firmware(fw);
3695err:
3696 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697}
3698
Jiri Slaby58936d82007-05-08 00:36:13 -07003699static int __devinit cy_pci_probe(struct pci_dev *pdev,
3700 const struct pci_device_id *ent)
3701{
Jiri Slaby31375532007-05-08 00:37:04 -07003702 void __iomem *addr0 = NULL, *addr2 = NULL;
3703 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003704 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003705 unsigned int device_id, nchan = 0, card_no, i;
3706 unsigned char plx_ver;
3707 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003708
3709 retval = pci_enable_device(pdev);
3710 if (retval) {
3711 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003712 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003713 }
3714
3715 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003716 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003717 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3718
Jiri Slaby31375532007-05-08 00:37:04 -07003719#if defined(__alpha__)
3720 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3721 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3722 "addresses on Alpha systems.\n");
3723 retval = -EIO;
3724 goto err_dis;
3725 }
3726#endif
3727 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3728 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3729 "addresses\n");
3730 retval = -EIO;
3731 goto err_dis;
3732 }
3733
3734 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3735 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3736 "it...\n");
3737 pdev->resource[2].flags &= ~IORESOURCE_IO;
3738 }
3739
3740 retval = pci_request_regions(pdev, "cyclades");
3741 if (retval) {
3742 dev_err(&pdev->dev, "failed to reserve resources\n");
3743 goto err_dis;
3744 }
3745
3746 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003747 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3748 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003749 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003750
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003751 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3752 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003753 if (addr0 == NULL) {
3754 dev_err(&pdev->dev, "can't remap ctl region\n");
3755 goto err_reg;
3756 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003757 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3758 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003759 if (addr2 == NULL) {
3760 dev_err(&pdev->dev, "can't remap base region\n");
3761 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003762 }
3763
Jiri Slaby31375532007-05-08 00:37:04 -07003764 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3765 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003766 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3767 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003768 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003769 }
Jiri Slaby31375532007-05-08 00:37:04 -07003770 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3771 struct RUNTIME_9060 __iomem *ctl_addr;
3772
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003773 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3774 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003775 if (addr0 == NULL) {
3776 dev_err(&pdev->dev, "can't remap ctl region\n");
3777 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003778 }
3779
Jiri Slaby31375532007-05-08 00:37:04 -07003780 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003781 cy_writew(&ctl_addr->intr_ctrl_stat,
3782 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003783
Jiri Slaby054f5b02007-07-17 04:05:16 -07003784 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003785
Jiri Slaby101b8152009-06-11 12:30:10 +01003786 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003787
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003788 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3789 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003790 if (addr2 == NULL) {
3791 dev_err(&pdev->dev, "can't remap base region\n");
3792 goto err_unmap;
3793 }
3794
3795 if (mailbox == ZE_V1) {
3796 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003797 } else {
3798 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003799#ifdef CY_PCI_DEBUG
3800 if (mailbox == ZO_V1) {
3801 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3802 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3803 "id %lx, ver %lx\n", (ulong)(0xff &
3804 readl(&((struct CUSTOM_REG *)addr2)->
3805 fpga_id)), (ulong)(0xff &
3806 readl(&((struct CUSTOM_REG *)addr2)->
3807 fpga_version)));
3808 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3809 } else {
3810 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3811 "Cyclades-Z board. FPGA not loaded\n");
3812 }
3813#endif
3814 /* The following clears the firmware id word. This
3815 ensures that the driver will not attempt to talk to
3816 the board until it has been properly initialized.
3817 */
3818 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3819 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003820 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003821
3822 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003823 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003824 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003825 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003826 }
3827
3828 if ((cy_next_channel + nchan) > NR_PORTS) {
3829 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3830 "channels are available. Change NR_PORTS in "
3831 "cyclades.c and recompile kernel.\n");
3832 goto err_unmap;
3833 }
3834 /* fill the next cy_card structure available */
3835 for (card_no = 0; card_no < NR_CARDS; card_no++) {
3836 if (cy_card[card_no].base_addr == NULL)
3837 break;
3838 }
3839 if (card_no == NR_CARDS) { /* no more cy_cards available */
3840 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3841 "more cards can be used. Change NR_CARDS in "
3842 "cyclades.c and recompile kernel.\n");
3843 goto err_unmap;
3844 }
3845
3846 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3847 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003848 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07003849 retval = request_irq(irq, cyy_interrupt,
3850 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07003851 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07003852 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003853 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003854 }
Jiri Slaby963118e2009-06-11 12:34:27 +01003855 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07003856 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003857 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3858 struct ZFW_CTRL __iomem *zfw_ctrl;
3859
3860 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3861
Jiri Slaby101b8152009-06-11 12:30:10 +01003862 cy_card[card_no].hw_ver = mailbox;
3863 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003864 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07003865#ifdef CONFIG_CYZ_INTR
3866 /* allocate IRQ only if board has an IRQ */
3867 if (irq != 0 && irq != 255) {
3868 retval = request_irq(irq, cyz_interrupt,
3869 IRQF_SHARED, "Cyclades-Z",
3870 &cy_card[card_no]);
3871 if (retval) {
3872 dev_err(&pdev->dev, "could not allocate IRQ\n");
3873 goto err_unmap;
3874 }
3875 }
3876#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07003877 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003878
Jiri Slaby31375532007-05-08 00:37:04 -07003879 /* set cy_card */
3880 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003881 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07003882 cy_card[card_no].irq = irq;
3883 cy_card[card_no].bus_index = 1;
3884 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003885 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003886 retval = cy_init_card(&cy_card[card_no]);
3887 if (retval)
3888 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07003889
Jiri Slaby31375532007-05-08 00:37:04 -07003890 pci_set_drvdata(pdev, &cy_card[card_no]);
3891
3892 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3893 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003894 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07003895 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07003896 switch (plx_ver) {
3897 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07003898 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07003899 break;
3900
3901 case PLX_9060:
3902 case PLX_9080:
3903 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003904 {
3905 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3906 plx_init(pdev, irq, ctl_addr);
3907 cy_writew(&ctl_addr->intr_ctrl_stat,
3908 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07003909 break;
3910 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01003911 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003912 }
3913
Jiri Slaby31375532007-05-08 00:37:04 -07003914 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3915 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
3916 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
3917 tty_register_device(cy_serial_driver, i, &pdev->dev);
3918 cy_next_channel += nchan;
3919
Jiri Slaby58936d82007-05-08 00:36:13 -07003920 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07003921err_null:
3922 cy_card[card_no].base_addr = NULL;
3923 free_irq(irq, &cy_card[card_no]);
3924err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003925 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003926 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003927 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07003928err_reg:
3929 pci_release_regions(pdev);
3930err_dis:
3931 pci_disable_device(pdev);
3932err:
3933 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07003934}
Jiri Slaby58936d82007-05-08 00:36:13 -07003935
Jiri Slaby6747cd92007-05-08 00:36:34 -07003936static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937{
Jiri Slaby38d09092007-05-08 00:36:10 -07003938 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07003939 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07003940
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003941 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01003942 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07003943 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01003944 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003945 else
3946#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003947 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003948#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01003949 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3950 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3951 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003952
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003953 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01003954 if (cinfo->ctl_addr.p9050)
3955 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07003956 if (cinfo->irq
3957#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003958 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07003959#endif /* CONFIG_CYZ_INTR */
3960 )
3961 free_irq(cinfo->irq, cinfo);
3962 pci_release_regions(pdev);
3963
3964 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003965 for (i = cinfo->first_line; i < cinfo->first_line +
3966 cinfo->nports; i++)
3967 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07003968 cinfo->nports = 0;
3969 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07003970}
3971
Jiri Slaby6747cd92007-05-08 00:36:34 -07003972static struct pci_driver cy_pci_driver = {
3973 .name = "cyclades",
3974 .id_table = cy_pci_dev_id,
3975 .probe = cy_pci_probe,
3976 .remove = __devexit_p(cy_pci_remove)
3977};
3978#endif
3979
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003980static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981{
Jiri Slaby02f11752006-12-08 02:39:28 -08003982 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07003983 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08003984 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003986 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08003987 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988
Jiri Slaby02f11752006-12-08 02:39:28 -08003989 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07003990 for (i = 0; i < NR_CARDS; i++)
3991 for (j = 0; j < cy_card[i].nports; j++) {
3992 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08003993
Jiri Slabyd13549f2009-09-19 13:13:12 -07003994 if (info->port.count) {
3995 /* XXX is the ldisc num worth this? */
3996 struct tty_struct *tty;
3997 struct tty_ldisc *ld;
3998 int num = 0;
3999 tty = tty_port_tty_get(&info->port);
4000 if (tty) {
4001 ld = tty_ldisc_ref(tty);
4002 if (ld) {
4003 num = ld->ops->num;
4004 tty_ldisc_deref(ld);
4005 }
4006 tty_kref_put(tty);
4007 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004008 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004009 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004010 (cur_jifs - info->idle_stats.in_use) /
4011 HZ, info->idle_stats.xmit_bytes,
4012 (cur_jifs - info->idle_stats.xmit_idle)/
4013 HZ, info->idle_stats.recv_bytes,
4014 (cur_jifs - info->idle_stats.recv_idle)/
4015 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004016 num);
4017 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004018 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004019 "%10lu %8lu %9lu %6ld\n",
4020 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004021 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004022 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023}
4024
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004025static int cyclades_proc_open(struct inode *inode, struct file *file)
4026{
4027 return single_open(file, cyclades_proc_show, NULL);
4028}
4029
4030static const struct file_operations cyclades_proc_fops = {
4031 .owner = THIS_MODULE,
4032 .open = cyclades_proc_open,
4033 .read = seq_read,
4034 .llseek = seq_lseek,
4035 .release = single_release,
4036};
4037
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038/* The serial driver boot-time initialization code!
4039 Hardware I/O ports are mapped to character special devices on a
4040 first found, first allocated manner. That is, this code searches
4041 for Cyclom cards in the system. As each is found, it is probed
4042 to discover how many chips (and thus how many ports) are present.
4043 These ports are mapped to the tty ports 32 and upward in monotonic
4044 fashion. If an 8-port card is replaced with a 16-port card, the
4045 port mapping on a following card will shift.
4046
4047 This approach is different from what is used in the other serial
4048 device driver because the Cyclom is more properly a multiplexer,
4049 not just an aggregation of serial ports on one card.
4050
4051 If there are more cards with more ports than have been
4052 statically allocated above, a warning is printed and the
4053 extra ports are ignored.
4054 */
4055
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004056static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004057 .open = cy_open,
4058 .close = cy_close,
4059 .write = cy_write,
4060 .put_char = cy_put_char,
4061 .flush_chars = cy_flush_chars,
4062 .write_room = cy_write_room,
4063 .chars_in_buffer = cy_chars_in_buffer,
4064 .flush_buffer = cy_flush_buffer,
4065 .ioctl = cy_ioctl,
4066 .throttle = cy_throttle,
4067 .unthrottle = cy_unthrottle,
4068 .set_termios = cy_set_termios,
4069 .stop = cy_stop,
4070 .start = cy_start,
4071 .hangup = cy_hangup,
4072 .break_ctl = cy_break,
4073 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004074 .tiocmget = cy_tiocmget,
4075 .tiocmset = cy_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +01004076 .get_icount = cy_get_icount,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004077 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078};
4079
Jiri Slaby02f11752006-12-08 02:39:28 -08004080static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081{
Jiri Slabydd025c02007-05-08 00:37:02 -07004082 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004083 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084
Jiri Slaby02f11752006-12-08 02:39:28 -08004085 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4086 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004087 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004088
Michal Marek64a14b52011-04-01 12:41:20 +02004089 printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
Jiri Slaby02f11752006-12-08 02:39:28 -08004091 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
Jiri Slaby02f11752006-12-08 02:39:28 -08004093 cy_serial_driver->owner = THIS_MODULE;
4094 cy_serial_driver->driver_name = "cyclades";
4095 cy_serial_driver->name = "ttyC";
4096 cy_serial_driver->major = CYCLADES_MAJOR;
4097 cy_serial_driver->minor_start = 0;
4098 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4099 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4100 cy_serial_driver->init_termios = tty_std_termios;
4101 cy_serial_driver->init_termios.c_cflag =
4102 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004103 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004104 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004106 retval = tty_register_driver(cy_serial_driver);
4107 if (retval) {
4108 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4109 goto err_frtty;
4110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
Jiri Slaby02f11752006-12-08 02:39:28 -08004112 /* the code below is responsible to find the boards. Each different
4113 type of board has its own detection routine. If a board is found,
4114 the next cy_card structure available is set by the detection
4115 routine. These functions are responsible for checking the
4116 availability of cy_card and cy_port data structures and updating
4117 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
Jiri Slaby02f11752006-12-08 02:39:28 -08004119 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004120 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Jiri Slaby6747cd92007-05-08 00:36:34 -07004122#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004123 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004124 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004125 if (retval && !nboards) {
4126 tty_unregister_driver(cy_serial_driver);
4127 goto err_frtty;
4128 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004129#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004130
4131 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004132err_frtty:
4133 put_tty_driver(cy_serial_driver);
4134err:
4135 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004136} /* cy_init */
4137
4138static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139{
Jiri Slabydd025c02007-05-08 00:37:02 -07004140 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004141 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004144 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145#endif /* CONFIG_CYZ_INTR */
4146
Alan Cox15ed6cc2008-04-30 00:53:55 -07004147 e1 = tty_unregister_driver(cy_serial_driver);
4148 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004149 printk(KERN_ERR "failed to unregister Cyclades serial "
4150 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151
Jiri Slaby6747cd92007-05-08 00:36:34 -07004152#ifdef CONFIG_PCI
4153 pci_unregister_driver(&cy_pci_driver);
4154#endif
4155
Jiri Slaby02f11752006-12-08 02:39:28 -08004156 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004157 card = &cy_card[i];
4158 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004159 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004160 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4161 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004162 if (card->ctl_addr.p9050)
4163 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004164 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004166 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004168 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004169 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004170 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004171 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004172 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004173 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004174 }
4175 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004176
4177 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178} /* cy_cleanup_module */
4179
4180module_init(cy_init);
4181module_exit(cy_cleanup_module);
4182
4183MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004184MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad2009-04-06 17:33:04 +01004185MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00004186MODULE_FIRMWARE("cyzfirm.bin");