blob: e61cabdd69df36d56ea0c0cd27fcaeadc488f8de [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#undef BLOCKMOVE
2#define Z_WAKE
3#undef Z_EXT_CHARS_IN_BUFFER
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * This file contains the driver for the Cyclades async multiport
7 * serial boards.
8 *
9 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
10 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Jiri Slabyebdb5132009-09-19 13:13:14 -070012 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 * Much of the design and some of the code came from serial.c
15 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
16 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
17 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070018 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21
Jiri Slabyebdb5132009-09-19 13:13:14 -070022#define CY_VERSION "2.6"
Jiri Slaby096dcfc2006-12-08 02:39:30 -080023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024/* If you need to install more boards than NR_CARDS, change the constant
25 in the definition below. No other change is necessary to support up to
26 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
27
Jiri Slaby02f11752006-12-08 02:39:28 -080028#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30/*
31 If the total number of ports is larger than NR_PORTS, change this
32 constant in the definition below. No other change is necessary to
33 support more boards/ports. */
34
Jiri Slaby02f11752006-12-08 02:39:28 -080035#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define ZO_V1 0
38#define ZO_V2 1
39#define ZE_V1 2
40
41#define SERIAL_PARANOIA_CHECK
42#undef CY_DEBUG_OPEN
43#undef CY_DEBUG_THROTTLE
44#undef CY_DEBUG_OTHER
45#undef CY_DEBUG_IO
46#undef CY_DEBUG_COUNT
47#undef CY_DEBUG_DTR
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#undef CY_DEBUG_INTERRUPTS
49#undef CY_16Y_HACK
50#undef CY_ENABLE_MONITORING
51#undef CY_PCI_DEBUG
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053/*
Alan Cox15ed6cc2008-04-30 00:53:55 -070054 * Include section
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/module.h>
57#include <linux/errno.h>
58#include <linux/signal.h>
59#include <linux/sched.h>
60#include <linux/timer.h>
61#include <linux/interrupt.h>
62#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -080063#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <linux/serial.h>
65#include <linux/major.h>
66#include <linux/string.h>
67#include <linux/fcntl.h>
68#include <linux/ptrace.h>
69#include <linux/cyclades.h>
70#include <linux/mm.h>
71#include <linux/ioport.h>
72#include <linux/init.h>
73#include <linux/delay.h>
74#include <linux/spinlock.h>
75#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -070076#include <linux/firmware.h>
Scott James Remnant9f56fad72009-04-06 17:33:04 +010077#include <linux/device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090078#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Alan Cox15ed6cc2008-04-30 00:53:55 -070080#include <linux/io.h>
Alan Cox15ed6cc2008-04-30 00:53:55 -070081#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/kernel.h>
84#include <linux/pci.h>
85
86#include <linux/stat.h>
87#include <linux/proc_fs.h>
Alexey Dobriyan444697d2009-03-31 15:19:15 -070088#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Jiri Slaby02f11752006-12-08 02:39:28 -080090static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092#ifndef SERIAL_XMIT_SIZE
93#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
94#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96#define STD_COM_FLAGS (0)
97
Jiri Slaby054f5b02007-07-17 04:05:16 -070098/* firmware stuff */
99#define ZL_MAX_BLOCKS 16
100#define DRIVER_VERSION 0x02010203
101#define RAM_SIZE 0x80000
102
Jiri Slaby054f5b02007-07-17 04:05:16 -0700103enum zblock_type {
104 ZBLOCK_PRG = 0,
105 ZBLOCK_FPGA = 1
106};
107
108struct zfile_header {
109 char name[64];
110 char date[32];
111 char aux[32];
112 u32 n_config;
113 u32 config_offset;
114 u32 n_blocks;
115 u32 block_offset;
116 u32 reserved[9];
117} __attribute__ ((packed));
118
119struct zfile_config {
120 char name[64];
121 u32 mailbox;
122 u32 function;
123 u32 n_blocks;
124 u32 block_list[ZL_MAX_BLOCKS];
125} __attribute__ ((packed));
126
127struct zfile_block {
128 u32 type;
129 u32 file_offset;
130 u32 ram_offset;
131 u32 size;
132} __attribute__ ((packed));
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static struct tty_driver *cy_serial_driver;
135
136#ifdef CONFIG_ISA
137/* This is the address lookup table. The driver will probe for
138 Cyclom-Y/ISA boards at all addresses in here. If you want the
139 driver to probe addresses at a different address, add it to
140 this table. If the driver is probing some other board and
141 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142*/
143
144static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800145 0xD0000,
146 0xD2000,
147 0xD4000,
148 0xD6000,
149 0xD8000,
150 0xDA000,
151 0xDC000,
152 0xDE000,
153 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154};
Jiri Slaby02f11752006-12-08 02:39:28 -0800155
Tobias Klauserfe971072006-01-09 20:54:02 -0800156#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Jiri Slaby3046d502007-05-08 00:36:46 -0700158static long maddr[NR_CARDS];
159static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161module_param_array(maddr, long, NULL, 0);
162module_param_array(irq, int, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Jiri Slaby02f11752006-12-08 02:39:28 -0800164#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166/* This is the per-card data structure containing address, irq, number of
167 channels, etc. This driver supports a maximum of NR_CARDS cards.
168*/
169static struct cyclades_card cy_card[NR_CARDS];
170
Jiri Slaby02f11752006-12-08 02:39:28 -0800171static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 * This is used to look up the divisor speeds and the timeouts
175 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100176 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
178 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
179 * HI VHI
180 * 20
181 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700182static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800183 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
184 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
185 230400, 0
186};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Jiri Slabyebdb5132009-09-19 13:13:14 -0700188static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800189 /* value => 00 01 02 03 04 */
190 /* divide by 8 32 128 512 2048 */
191 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
192 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
193};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Jiri Slabyebdb5132009-09-19 13:13:14 -0700195static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800196 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
197 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
198};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Jiri Slabyebdb5132009-09-19 13:13:14 -0700200static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800201 /* value => 00 01 02 03 04 */
202 /* divide by 8 32 128 512 2048 */
203 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
204 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00
206};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Jiri Slabyebdb5132009-09-19 13:13:14 -0700208static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800209 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
210 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
211 0x21
212};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Jiri Slabyebdb5132009-09-19 13:13:14 -0700214static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800215 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
216 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
217 0x07
218};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/*
221 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700222 * The cyclades_port structure member rflow and the vector rflow_thr
223 * allows us to take advantage of a special feature in the CD1400 to avoid
224 * data loss even when the system interrupt latency is too high. These flags
225 * are to be used only with very special applications. Setting these flags
226 * requires the use of a special cable (DTR and RTS reversed). In the new
227 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 * cables.
229 */
230
Jiri Slabyebdb5132009-09-19 13:13:14 -0700231static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
234 0x0a
235};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237/* The Cyclom-Ye has placed the sequential chips in non-sequential
238 * address order. This look-up table overcomes that problem.
239 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700240static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800241 0x0400,
242 0x0800,
243 0x0C00,
244 0x0200,
245 0x0600,
246 0x0A00,
247 0x0E00
248};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250/* PCI related definitions */
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700253static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700254 /* PCI < 1Mb */
255 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
256 /* PCI > 1Mb */
257 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
258 /* 4Y PCI < 1Mb */
259 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
260 /* 4Y PCI > 1Mb */
261 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
262 /* 8Y PCI < 1Mb */
263 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
264 /* 8Y PCI > 1Mb */
265 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
266 /* Z PCI < 1Mb */
267 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
268 /* Z PCI > 1Mb */
269 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800270 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800271};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800272MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273#endif
274
275static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700276static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700277static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278#ifdef CONFIG_ISA
279static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800280#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282#ifndef CONFIG_CYZ_INTR
283static void cyz_poll(unsigned long);
284
285/* The Cyclades-Z polling cycle is defined by this variable */
286static long cyz_polling_cycle = CZ_DEF_POLL;
287
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700288static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Jiri Slaby02f11752006-12-08 02:39:28 -0800290#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291static void cyz_rx_restart(unsigned long);
292static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800293#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700295static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
296{
297 struct cyclades_card *card = port->card;
298
299 cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
300}
301
302static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
303{
304 struct cyclades_card *card = port->card;
305
306 return readb(port->u.cyy.base_addr + (reg << card->bus_index));
307}
308
Jiri Slaby2693f482009-06-11 12:31:06 +0100309static inline bool cy_is_Z(struct cyclades_card *card)
310{
311 return card->num_chips == (unsigned int)-1;
312}
313
314static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
315{
316 return readl(&ctl_addr->init_ctrl) & (1 << 17);
317}
318
319static inline bool cyz_fpga_loaded(struct cyclades_card *card)
320{
321 return __cyz_fpga_loaded(card->ctl_addr.p9060);
322}
323
324static inline bool cyz_is_loaded(struct cyclades_card *card)
325{
326 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
327
328 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
329 readl(&fw_id->signature) == ZFIRM_ID;
330}
331
Jiri Slaby02f11752006-12-08 02:39:28 -0800332static inline int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700333 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800336 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700337 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
338 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800339 return 1;
340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jiri Slaby02f11752006-12-08 02:39:28 -0800342 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700343 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
344 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800345 return 1;
346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800348 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700349}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/***********************************************************/
352/********* Start of block of Cyclom-Y specific code ********/
353
354/* This routine waits up to 1000 micro-seconds for the previous
355 command to the Cirrus chip to complete and then issues the
356 new command. An error is returned if the previous command
357 didn't finish within the time limit.
358
359 This function is only called from inside spinlock-protected code.
360 */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700361static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700363 void __iomem *ccr = base_addr + (CyCCR << index);
Jiri Slabyad39c302007-05-08 00:35:49 -0700364 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Jiri Slaby02f11752006-12-08 02:39:28 -0800366 /* Check to see that the previous command has completed */
367 for (i = 0; i < 100; i++) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700368 if (readb(ccr) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800369 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800370 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800372 /* if the CCR never cleared, the previous command
373 didn't finish within the "reasonable time" */
374 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800375 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Jiri Slaby02f11752006-12-08 02:39:28 -0800377 /* Issue the new command */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700378 cy_writeb(ccr, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800380 return 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700381}
382
383static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
384{
385 return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
386 port->card->bus_index);
387}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389#ifdef CONFIG_ISA
390/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700391static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
Jiri Slaby02f11752006-12-08 02:39:28 -0800393 int irq;
394 unsigned long irqs, flags;
395 int save_xir, save_car;
396 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Jiri Slaby02f11752006-12-08 02:39:28 -0800398 /* forget possible initially masked and pending IRQ */
399 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Jiri Slaby02f11752006-12-08 02:39:28 -0800401 /* Clear interrupts on the board first */
402 cy_writeb(address + (Cy_ClrIntr << index), 0);
403 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Jiri Slaby02f11752006-12-08 02:39:28 -0800405 irqs = probe_irq_on();
406 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700407 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Jiri Slaby02f11752006-12-08 02:39:28 -0800409 /* Enable the Tx interrupts on the CD1400 */
410 local_irq_save(flags);
411 cy_writeb(address + (CyCAR << index), 0);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700412 __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Jiri Slaby02f11752006-12-08 02:39:28 -0800414 cy_writeb(address + (CyCAR << index), 0);
415 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700416 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800417 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Jiri Slaby02f11752006-12-08 02:39:28 -0800419 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700420 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Jiri Slaby02f11752006-12-08 02:39:28 -0800422 /* Check which interrupt is in use */
423 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Jiri Slaby02f11752006-12-08 02:39:28 -0800425 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700426 save_xir = (u_char) readb(address + (CyTIR << index));
427 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800428 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
429 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700430 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800431 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
432 cy_writeb(address + (CyCAR << index), (save_car));
433 cy_writeb(address + (Cy_ClrIntr << index), 0);
434 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Jiri Slaby02f11752006-12-08 02:39:28 -0800436 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437}
Jiri Slaby02f11752006-12-08 02:39:28 -0800438#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Jiri Slabyce97a092007-10-18 03:06:21 -0700440static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
441 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800442{
443 struct cyclades_port *info;
444 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700445 int len, index = cinfo->bus_index;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700446 u8 ivr, save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800447
Jiri Slabye9410272006-12-08 02:39:28 -0800448#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700449 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800450#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700451 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700452 save_xir = readb(base_addr + (CyRIR << index));
453 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700454 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700455 save_car = cyy_readb(info, CyCAR);
456 cyy_writeb(info, CyCAR, save_xir);
457 ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
Jiri Slabye9410272006-12-08 02:39:28 -0800458
Jiri Slabyd13549f2009-09-19 13:13:12 -0700459 tty = tty_port_tty_get(&info->port);
Jiri Slabyce97a092007-10-18 03:06:21 -0700460 /* if there is nowhere to put the data, discard it */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700461 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700462 if (ivr == CyIVRRxEx) { /* exception */
463 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700464 } else { /* normal character reception */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700465 char_count = cyy_readb(info, CyRDCR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700466 while (char_count--)
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700467 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700468 }
469 goto end;
470 }
471 /* there is an open port for this data */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700472 if (ivr == CyIVRRxEx) { /* exception */
473 data = cyy_readb(info, CyRDSR);
Jiri Slaby02f11752006-12-08 02:39:28 -0800474
Jiri Slabyce97a092007-10-18 03:06:21 -0700475 /* For statistics only */
476 if (data & CyBREAK)
477 info->icount.brk++;
478 else if (data & CyFRAME)
479 info->icount.frame++;
480 else if (data & CyPARITY)
481 info->icount.parity++;
482 else if (data & CyOVERRUN)
483 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800484
Jiri Slabyce97a092007-10-18 03:06:21 -0700485 if (data & info->ignore_status_mask) {
486 info->icount.rx++;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700487 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700488 return;
489 }
490 if (tty_buffer_request_room(tty, 1)) {
491 if (data & info->read_status_mask) {
492 if (data & CyBREAK) {
493 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700494 cyy_readb(info, CyRDSR),
495 TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800496 info->icount.rx++;
Alan Cox77451e52008-07-16 21:57:02 +0100497 if (info->port.flags & ASYNC_SAK)
Jiri Slabyce97a092007-10-18 03:06:21 -0700498 do_SAK(tty);
499 } else if (data & CyFRAME) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700500 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700501 cyy_readb(info, CyRDSR),
502 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700503 info->icount.rx++;
504 info->idle_stats.frame_errs++;
505 } else if (data & CyPARITY) {
506 /* Pieces of seven... */
507 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700508 cyy_readb(info, CyRDSR),
509 TTY_PARITY);
Jiri Slabyce97a092007-10-18 03:06:21 -0700510 info->icount.rx++;
511 info->idle_stats.parity_errs++;
512 } else if (data & CyOVERRUN) {
513 tty_insert_flip_char(tty, 0,
514 TTY_OVERRUN);
515 info->icount.rx++;
516 /* If the flip buffer itself is
517 overflowing, we still lose
518 the next incoming character.
519 */
520 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700521 cyy_readb(info, CyRDSR),
522 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700523 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800524 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700525 /* These two conditions may imply */
526 /* a normal read should be done. */
527 /* } else if(data & CyTIMEOUT) { */
528 /* } else if(data & CySPECHAR) { */
529 } else {
530 tty_insert_flip_char(tty, 0,
531 TTY_NORMAL);
532 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800533 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700534 } else {
535 tty_insert_flip_char(tty, 0, TTY_NORMAL);
536 info->icount.rx++;
537 }
538 } else {
539 /* there was a software buffer overrun and nothing
540 * could be done about it!!! */
541 info->icount.buf_overrun++;
542 info->idle_stats.overruns++;
543 }
544 } else { /* normal character reception */
545 /* load # chars available from the chip */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700546 char_count = cyy_readb(info, CyRDCR);
Jiri Slabye9410272006-12-08 02:39:28 -0800547
548#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700549 ++info->mon.int_count;
550 info->mon.char_count += char_count;
551 if (char_count > info->mon.char_max)
552 info->mon.char_max = char_count;
553 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800554#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700555 len = tty_buffer_request_room(tty, char_count);
556 while (len--) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700557 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700558 tty_insert_flip_char(tty, data, TTY_NORMAL);
559 info->idle_stats.recv_bytes++;
560 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800561#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700562 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800563#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800564 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700565 info->idle_stats.recv_idle = jiffies;
566 }
567 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700568 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700569end:
570 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700571 cyy_writeb(info, CyRIR, save_xir & 0x3f);
572 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700573}
574
Jiri Slaby65f76a82007-10-18 03:06:22 -0700575static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700576 void __iomem *base_addr)
577{
578 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700579 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700580 int char_count, index = cinfo->bus_index;
581 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700582
583 /* Since we only get here when the transmit buffer
584 is empty, we know we can always stuff a dozen
585 characters. */
586#ifdef CY_DEBUG_INTERRUPTS
587 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
588#endif
589
590 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700591 save_xir = readb(base_addr + (CyTIR << index));
592 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700593 save_car = readb(base_addr + (CyCAR << index));
594 cy_writeb(base_addr + (CyCAR << index), save_xir);
595
Jiri Slabyce97a092007-10-18 03:06:21 -0700596 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700597 tty = tty_port_tty_get(&info->port);
598 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700599 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700600 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800601 }
602
Jiri Slabyce97a092007-10-18 03:06:21 -0700603 /* load the on-chip space for outbound data */
604 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800605
Jiri Slabyce97a092007-10-18 03:06:21 -0700606 if (info->x_char) { /* send special char */
607 outch = info->x_char;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700608 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700609 char_count--;
610 info->icount.tx++;
611 info->x_char = 0;
612 }
Jiri Slabye9410272006-12-08 02:39:28 -0800613
Jiri Slabyce97a092007-10-18 03:06:21 -0700614 if (info->breakon || info->breakoff) {
615 if (info->breakon) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700616 cyy_writeb(info, CyTDR, 0);
617 cyy_writeb(info, CyTDR, 0x81);
Jiri Slabyce97a092007-10-18 03:06:21 -0700618 info->breakon = 0;
619 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800620 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700621 if (info->breakoff) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700622 cyy_writeb(info, CyTDR, 0);
623 cyy_writeb(info, CyTDR, 0x83);
Jiri Slabyce97a092007-10-18 03:06:21 -0700624 info->breakoff = 0;
625 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800626 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700627 }
Jiri Slabye9410272006-12-08 02:39:28 -0800628
Jiri Slabyce97a092007-10-18 03:06:21 -0700629 while (char_count-- > 0) {
630 if (!info->xmit_cnt) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700631 if (cyy_readb(info, CySRER) & CyTxMpty) {
632 cyy_writeb(info, CySRER,
633 cyy_readb(info, CySRER) & ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700634 } else {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700635 cyy_writeb(info, CySRER, CyTxMpty |
636 (cyy_readb(info, CySRER) & ~CyTxRdy));
Jiri Slaby02f11752006-12-08 02:39:28 -0800637 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700638 goto done;
639 }
Alan Cox77451e52008-07-16 21:57:02 +0100640 if (info->port.xmit_buf == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700641 cyy_writeb(info, CySRER,
642 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700643 goto done;
644 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700645 if (tty->stopped || tty->hw_stopped) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700646 cyy_writeb(info, CySRER,
647 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700648 goto done;
649 }
650 /* Because the Embedded Transmit Commands have been enabled,
651 * we must check to see if the escape character, NULL, is being
652 * sent. If it is, we must ensure that there is room for it to
653 * be doubled in the output stream. Therefore we no longer
654 * advance the pointer when the character is fetched, but
655 * rather wait until after the check for a NULL output
656 * character. This is necessary because there may not be room
657 * for the two chars needed to send a NULL.)
658 */
Alan Cox77451e52008-07-16 21:57:02 +0100659 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700660 if (outch) {
661 info->xmit_cnt--;
662 info->xmit_tail = (info->xmit_tail + 1) &
663 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700664 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700665 info->icount.tx++;
666 } else {
667 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800668 info->xmit_cnt--;
669 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700670 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700671 cyy_writeb(info, CyTDR, outch);
672 cyy_writeb(info, CyTDR, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800673 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700674 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800675 }
676 }
Jiri Slabye9410272006-12-08 02:39:28 -0800677 }
678
Jiri Slabyce97a092007-10-18 03:06:21 -0700679done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700680 tty_wakeup(tty);
681 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700682end:
683 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700684 cyy_writeb(info, CyTIR, save_xir & 0x3f);
685 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700686}
Jiri Slabye9410272006-12-08 02:39:28 -0800687
Jiri Slabyce97a092007-10-18 03:06:21 -0700688static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
689 void __iomem *base_addr)
690{
691 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700692 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700693 int index = cinfo->bus_index;
694 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800695
Jiri Slabyce97a092007-10-18 03:06:21 -0700696 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700697 save_xir = readb(base_addr + (CyMIR << index));
698 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700699 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700700 save_car = cyy_readb(info, CyCAR);
701 cyy_writeb(info, CyCAR, save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800702
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700703 mdm_change = cyy_readb(info, CyMISR);
704 mdm_status = cyy_readb(info, CyMSVR1);
Jiri Slabye9410272006-12-08 02:39:28 -0800705
Jiri Slabyd13549f2009-09-19 13:13:12 -0700706 tty = tty_port_tty_get(&info->port);
707 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700708 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800709
Jiri Slabyce97a092007-10-18 03:06:21 -0700710 if (mdm_change & CyANY_DELTA) {
711 /* For statistics only */
712 if (mdm_change & CyDCD)
713 info->icount.dcd++;
714 if (mdm_change & CyCTS)
715 info->icount.cts++;
716 if (mdm_change & CyDSR)
717 info->icount.dsr++;
718 if (mdm_change & CyRI)
719 info->icount.rng++;
720
Alan Coxbdc04e32009-09-19 13:13:31 -0700721 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slabyce97a092007-10-18 03:06:21 -0700722 }
723
Alan Cox77451e52008-07-16 21:57:02 +0100724 if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700725 if (mdm_status & CyDCD)
726 wake_up_interruptible(&info->port.open_wait);
727 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700728 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800729 }
Alan Cox77451e52008-07-16 21:57:02 +0100730 if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700731 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700732 if (mdm_status & CyCTS) {
733 /* cy_start isn't used
734 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700735 tty->hw_stopped = 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700736 cyy_writeb(info, CySRER,
737 cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700738 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700739 }
740 } else {
741 if (!(mdm_status & CyCTS)) {
742 /* cy_stop isn't used
743 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700744 tty->hw_stopped = 1;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700745 cyy_writeb(info, CySRER,
746 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700747 }
748 }
749 }
750/* if (mdm_change & CyDSR) {
751 }
752 if (mdm_change & CyRI) {
753 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700754 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700755end:
756 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700757 cyy_writeb(info, CyMIR, save_xir & 0x3f);
758 cyy_writeb(info, CyCAR, save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761/* The real interrupt service routine is called
762 whenever the card wants its hand held--chars
763 received, out buffer empty, modem change, etc.
764 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800765static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Jiri Slaby02f11752006-12-08 02:39:28 -0800767 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700768 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800769 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700770 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800771 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800772
Jiri Slabyf7429032007-05-08 00:36:59 -0700773 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700775 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
776 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800778 return IRQ_NONE; /* spurious interrupt */
779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Jiri Slaby02f11752006-12-08 02:39:28 -0800781 card_base_addr = cinfo->base_addr;
782 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700784 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
785 if (unlikely(card_base_addr == NULL))
786 return IRQ_HANDLED;
787
Jiri Slaby02f11752006-12-08 02:39:28 -0800788 /* This loop checks all chips in the card. Make a note whenever
789 _any_ chip had some work to do, as this is considered an
790 indication that there will be more to do. Only when no chip
791 has any work does this outermost loop exit.
792 */
793 do {
794 had_work = 0;
795 for (chip = 0; chip < cinfo->num_chips; chip++) {
796 base_addr = cinfo->base_addr +
797 (cy_chip_offset[chip] << index);
798 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700799 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800800 (CySVRR << index))) != 0x00) {
801 had_work++;
802 /* The purpose of the following test is to ensure that
803 no chip can monopolize the driver. This forces the
804 chips to be checked in a round-robin fashion (after
805 draining each of a bunch (1000) of characters).
806 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700807 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800808 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700809 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700810 if (status & CySRReceive) /* rx intr */
811 cyy_chip_rx(cinfo, chip, base_addr);
812 if (status & CySRTransmit) /* tx intr */
813 cyy_chip_tx(cinfo, chip, base_addr);
814 if (status & CySRModem) /* modem intr */
815 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700816 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800817 }
818 }
819 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Jiri Slaby02f11752006-12-08 02:39:28 -0800821 /* clear interrupts */
822 spin_lock(&cinfo->card_lock);
823 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
824 /* Cy_ClrIntr is 0x1800 */
825 spin_unlock(&cinfo->card_lock);
826 return IRQ_HANDLED;
827} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Jiri Slaby4d768202009-09-19 13:13:15 -0700829static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
830 unsigned int clear)
831{
832 struct cyclades_card *card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700833 int channel = info->line - card->first_line;
Jiri Slaby0d348722009-09-19 13:13:16 -0700834 u32 rts, dtr, msvrr, msvrd;
Jiri Slaby4d768202009-09-19 13:13:15 -0700835
Jiri Slaby4d768202009-09-19 13:13:15 -0700836 channel &= 0x03;
Jiri Slaby4d768202009-09-19 13:13:15 -0700837
Jiri Slaby0d348722009-09-19 13:13:16 -0700838 if (info->rtsdtr_inv) {
839 msvrr = CyMSVR2;
840 msvrd = CyMSVR1;
841 rts = CyDTR;
842 dtr = CyRTS;
843 } else {
844 msvrr = CyMSVR1;
845 msvrd = CyMSVR2;
846 rts = CyRTS;
847 dtr = CyDTR;
848 }
Jiri Slaby4d768202009-09-19 13:13:15 -0700849 if (set & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700850 cyy_writeb(info, CyCAR, channel);
851 cyy_writeb(info, msvrr, rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700852 }
853 if (clear & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700854 cyy_writeb(info, CyCAR, channel);
855 cyy_writeb(info, msvrr, ~rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700856 }
857 if (set & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700858 cyy_writeb(info, CyCAR, channel);
859 cyy_writeb(info, msvrd, dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700860#ifdef CY_DEBUG_DTR
861 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
862 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700863 cyy_readb(info, CyMSVR1),
864 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700865#endif
866 }
867 if (clear & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700868 cyy_writeb(info, CyCAR, channel);
869 cyy_writeb(info, msvrd, ~dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700870#ifdef CY_DEBUG_DTR
871 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
872 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700873 cyy_readb(info, CyMSVR1),
874 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700875#endif
876 }
877}
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879/***********************************************************/
880/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700881/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882/***********************************************************/
883
884static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800885cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700886 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700888 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800889 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Jiri Slaby97e87f82009-06-11 12:29:27 +0100891 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800892 if (loc_doorbell) {
893 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700894 *channel = readl(&board_ctrl->fwcmd_channel);
895 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100896 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800897 return 1;
898 }
899 return 0;
900} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800903cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700904 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700906 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700907 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700908 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Jiri Slaby2693f482009-06-11 12:31:06 +0100910 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800911 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700912
Jiri Slaby02f11752006-12-08 02:39:28 -0800913 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100914 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700915 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700916 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700917 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800918 udelay(50L);
919 }
920 cy_writel(&board_ctrl->hcmd_channel, channel);
921 cy_writel(&board_ctrl->hcmd_param, param);
922 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800924 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800925} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700927static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700929 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700930 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700931 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800932 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700934 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800936 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700938 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700940 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
941 rx_put = readl(&buf_ctrl->rx_put);
942 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
943 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800944 if (rx_put >= rx_get)
945 char_count = rx_put - rx_get;
946 else
947 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Jiri Slaby02f11752006-12-08 02:39:28 -0800949 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800951 info->mon.int_count++;
952 info->mon.char_count += char_count;
953 if (char_count > info->mon.char_max)
954 info->mon.char_max = char_count;
955 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700957 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800958 /* flush received characters */
959 new_rx_get = (new_rx_get + char_count) &
960 (rx_bufsize - 1);
961 info->rflush_count++;
962 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800964 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
965 for performance, but because of buffer boundaries, there
966 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700967 while (1) {
968 len = tty_prepare_flip_string(tty, &buf,
969 char_count);
970 if (!len)
971 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700973 len = min_t(unsigned int, min(len, char_count),
974 rx_bufsize - new_rx_get);
975
976 memcpy_fromio(buf, cinfo->base_addr +
977 rx_bufaddr + new_rx_get, len);
978
979 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800980 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700981 char_count -= len;
982 info->icount.rx += len;
983 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800986 len = tty_buffer_request_room(tty, char_count);
987 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700988 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800989 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700990 new_rx_get = (new_rx_get + 1) &
991 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800992 tty_insert_flip_char(tty, data, TTY_NORMAL);
993 info->idle_stats.recv_bytes++;
994 info->icount.rx++;
995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996#endif
997#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -0800998 /* Recalculate the number of chars in the RX buffer and issue
999 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001000 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001001 if (rx_put >= rx_get)
1002 char_count = rx_put - rx_get;
1003 else
1004 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001005 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -07001006 !timer_pending(&cyz_rx_full_timer[
1007 info->line]))
1008 mod_timer(&cyz_rx_full_timer[info->line],
1009 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001011 info->idle_stats.recv_idle = jiffies;
1012 tty_schedule_flip(tty);
1013 }
1014 /* Update rx_get */
1015 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017}
1018
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001019static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001021 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001022 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001023 u8 data;
1024 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001026 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001028 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Jiri Slaby02f11752006-12-08 02:39:28 -08001030 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1031 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001033 tx_get = readl(&buf_ctrl->tx_get);
1034 tx_put = readl(&buf_ctrl->tx_put);
1035 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1036 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001037 if (tx_put >= tx_get)
1038 char_count = tx_get - tx_put - 1 + tx_bufsize;
1039 else
1040 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Jiri Slaby02f11752006-12-08 02:39:28 -08001042 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Jiri Slabyf7429032007-05-08 00:36:59 -07001044 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001045 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001046
1047 if (info->x_char) { /* send special char */
1048 data = info->x_char;
1049
1050 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1051 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1052 info->x_char = 0;
1053 char_count--;
1054 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001055 }
1056#ifdef BLOCKMOVE
1057 while (0 < (small_count = min_t(unsigned int,
1058 tx_bufsize - tx_put, min_t(unsigned int,
1059 (SERIAL_XMIT_SIZE - info->xmit_tail),
1060 min_t(unsigned int, info->xmit_cnt,
1061 char_count))))) {
1062
1063 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1064 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001065 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001066 small_count);
1067
1068 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1069 char_count -= small_count;
1070 info->icount.tx += small_count;
1071 info->xmit_cnt -= small_count;
1072 info->xmit_tail = (info->xmit_tail + small_count) &
1073 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001074 }
1075#else
1076 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001077 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001078 info->xmit_cnt--;
1079 info->xmit_tail = (info->xmit_tail + 1) &
1080 (SERIAL_XMIT_SIZE - 1);
1081
1082 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1083 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1084 char_count--;
1085 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001088 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001089ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001090 /* Update tx_put */
1091 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
1094
Jiri Slaby02f11752006-12-08 02:39:28 -08001095static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001097 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001098 struct tty_struct *tty;
1099 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001100 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001101 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001102 int special_count;
1103 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001105 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Jiri Slaby02f11752006-12-08 02:39:28 -08001107 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1108 special_count = 0;
1109 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001110 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001111 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001112 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001113 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001114
Jiri Slaby02f11752006-12-08 02:39:28 -08001115 switch (cmd) {
1116 case C_CM_PR_ERROR:
1117 tty_insert_flip_char(tty, 0, TTY_PARITY);
1118 info->icount.rx++;
1119 special_count++;
1120 break;
1121 case C_CM_FR_ERROR:
1122 tty_insert_flip_char(tty, 0, TTY_FRAME);
1123 info->icount.rx++;
1124 special_count++;
1125 break;
1126 case C_CM_RXBRK:
1127 tty_insert_flip_char(tty, 0, TTY_BREAK);
1128 info->icount.rx++;
1129 special_count++;
1130 break;
1131 case C_CM_MDCD:
1132 info->icount.dcd++;
1133 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001134 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001135 u32 dcd = fw_ver > 241 ? param :
1136 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001137 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001138 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001139 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001140 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001141 }
1142 break;
1143 case C_CM_MCTS:
1144 info->icount.cts++;
1145 delta_count++;
1146 break;
1147 case C_CM_MRI:
1148 info->icount.rng++;
1149 delta_count++;
1150 break;
1151 case C_CM_MDSR:
1152 info->icount.dsr++;
1153 delta_count++;
1154 break;
1155#ifdef Z_WAKE
1156 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001157 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001158 break;
1159#endif
1160#ifdef CONFIG_CYZ_INTR
1161 case C_CM_RXHIWM:
1162 case C_CM_RXNNDT:
1163 case C_CM_INTBACK2:
1164 /* Reception Interrupt */
1165#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001166 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1167 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001168#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001169 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001170 break;
1171 case C_CM_TXBEMPTY:
1172 case C_CM_TXLOWWM:
1173 case C_CM_INTBACK:
1174 /* Transmission Interrupt */
1175#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001176 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1177 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001178#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001179 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001180 break;
1181#endif /* CONFIG_CYZ_INTR */
1182 case C_CM_FATAL:
1183 /* should do something with this !!! */
1184 break;
1185 default:
1186 break;
1187 }
1188 if (delta_count)
Alan Coxbdc04e32009-09-19 13:13:31 -07001189 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001190 if (special_count)
1191 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001192 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001193 }
1194}
1195
1196#ifdef CONFIG_CYZ_INTR
1197static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1198{
Jiri Slabyf7429032007-05-08 00:36:59 -07001199 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001200
Jiri Slaby2693f482009-06-11 12:31:06 +01001201 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001202#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001203 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1204 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001205#endif
1206 return IRQ_NONE;
1207 }
1208
1209 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 cyz_handle_cmd(cinfo);
1211
Jiri Slaby02f11752006-12-08 02:39:28 -08001212 return IRQ_HANDLED;
1213} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
Jiri Slaby02f11752006-12-08 02:39:28 -08001215static void cyz_rx_restart(unsigned long arg)
1216{
1217 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001218 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001219 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001220 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001221 unsigned long flags;
1222
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001223 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001224 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001225 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001226 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001227 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001229 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001230}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Jiri Slaby02f11752006-12-08 02:39:28 -08001232#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Jiri Slaby02f11752006-12-08 02:39:28 -08001234static void cyz_poll(unsigned long arg)
1235{
1236 struct cyclades_card *cinfo;
1237 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001238 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001239 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001240
Jiri Slaby02f11752006-12-08 02:39:28 -08001241 for (card = 0; card < NR_CARDS; card++) {
1242 cinfo = &cy_card[card];
1243
Jiri Slaby2693f482009-06-11 12:31:06 +01001244 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001245 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001246 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001247 continue;
1248
Jiri Slaby02f11752006-12-08 02:39:28 -08001249 /* Skip first polling cycle to avoid racing conditions with the FW */
1250 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001251 cinfo->intr_enabled = 1;
1252 continue;
1253 }
1254
1255 cyz_handle_cmd(cinfo);
1256
1257 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001258 struct tty_struct *tty;
1259
Jiri Slabydd025c02007-05-08 00:37:02 -07001260 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001261 tty = tty_port_tty_get(&info->port);
1262 /* OK to pass NULL to the handle functions below.
1263 They need to drop the data in that case. */
1264
Jiri Slaby02f11752006-12-08 02:39:28 -08001265 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001266 cyz_handle_rx(info, tty);
1267 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001268 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001269 }
1270 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001271 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001272 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001273 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001274} /* cyz_poll */
1275
1276#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278/********** End of block of Cyclades-Z specific code *********/
1279/***********************************************************/
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281/* This is called whenever a port becomes active;
1282 interrupts are enabled and DTR & RTS are turned on.
1283 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001284static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
Jiri Slaby875b2062007-05-08 00:36:49 -07001286 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001287 unsigned long flags;
1288 int retval = 0;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001289 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001290 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
Jiri Slaby02f11752006-12-08 02:39:28 -08001292 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001293 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Jiri Slaby02f11752006-12-08 02:39:28 -08001295 page = get_zeroed_page(GFP_KERNEL);
1296 if (!page)
1297 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001299 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001301 if (info->port.flags & ASYNC_INITIALIZED)
Jiri Slaby02f11752006-12-08 02:39:28 -08001302 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001303
1304 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001305 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001306 goto errout;
1307 }
1308
Alan Cox77451e52008-07-16 21:57:02 +01001309 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001310 free_page(page);
1311 else
Alan Cox77451e52008-07-16 21:57:02 +01001312 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001314 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Jiri Slabyd13549f2009-09-19 13:13:12 -07001316 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Jiri Slaby2693f482009-06-11 12:31:06 +01001318 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001319 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001321 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001322
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001323 cyy_writeb(info, CyCAR, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001324
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001325 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08001326 (info->default_timeout ? info->default_timeout : 0x02));
1327 /* 10ms rx timeout */
1328
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001329 cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001330
Jiri Slaby4d768202009-09-19 13:13:15 -07001331 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001333 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001334 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001335 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001336
Jiri Slaby2693f482009-06-11 12:31:06 +01001337 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001338 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001339
Jiri Slaby02f11752006-12-08 02:39:28 -08001340#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001341 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001342 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001343#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001344 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001345
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001346 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347#ifdef Z_WAKE
1348#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001349 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001350 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1351 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001353 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001354 C_IN_IOCTLW | C_IN_MDCD);
1355#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356#else
1357#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001358 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001359 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1360 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001362 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001363#endif /* CONFIG_CYZ_INTR */
1364#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Jiri Slaby875b2062007-05-08 00:36:49 -07001366 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001367 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001368 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1369 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Jiri Slaby02f11752006-12-08 02:39:28 -08001372 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001373 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001374 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001375 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1376 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Jiri Slaby02f11752006-12-08 02:39:28 -08001379 /* set timeout !!! */
1380 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001381 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
Jiri Slaby02f11752006-12-08 02:39:28 -08001383 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001386 info->port.flags |= ASYNC_INITIALIZED;
1387
1388 clear_bit(TTY_IO_ERROR, &tty->flags);
1389 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1390 info->breakon = info->breakoff = 0;
1391 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1392 info->idle_stats.in_use =
1393 info->idle_stats.recv_idle =
1394 info->idle_stats.xmit_idle = jiffies;
1395
1396 spin_unlock_irqrestore(&card->card_lock, flags);
1397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001399 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400#endif
1401 return 0;
1402
1403errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001404 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001405 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001407} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Jiri Slaby02f11752006-12-08 02:39:28 -08001409static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001411 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001412 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001413 int channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Jiri Slaby2693f482009-06-11 12:31:06 +01001415 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001416 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001417 cyy_writeb(info, CyCAR, channel & 0x03);
1418 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001419 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001420 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001422 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001424 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001425 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001426 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001427 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1428 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001429 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001430 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001431#else /* CONFIG_CYZ_INTR */
1432 /* Don't have to do anything at this time */
1433#endif /* CONFIG_CYZ_INTR */
1434 }
1435} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437/*
1438 * This routine shuts down a serial port; interrupts are disabled,
1439 * and DTR is dropped if the hangup on close termio flag is on.
1440 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001441static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442{
Jiri Slaby875b2062007-05-08 00:36:49 -07001443 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001444 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Alan Cox77451e52008-07-16 21:57:02 +01001446 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001447 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Jiri Slaby02f11752006-12-08 02:39:28 -08001449 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001450 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001451 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001452
1453 /* Clear delta_msr_wait queue to avoid mem leaks. */
Alan Coxbdc04e32009-09-19 13:13:31 -07001454 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001455
Alan Cox77451e52008-07-16 21:57:02 +01001456 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001457 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001458 temp = info->port.xmit_buf;
1459 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001460 free_page((unsigned long)temp);
1461 }
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 Slaby9fa1b3b182007-05-08 00:36:57 -07001471 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001472 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001473#ifdef CY_DEBUG_OPEN
Jiri Slaby0e7f4192011-03-23 09:49:56 +01001474 int channel = info->line - card->first_line;
Jiri Slaby21719192007-05-08 00:36:42 -07001475 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001476 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001477#endif
1478
Jiri Slaby2693f482009-06-11 12:31:06 +01001479 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001480 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001481
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001482 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001483
Alan Cox77451e52008-07-16 21:57:02 +01001484 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001485 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001486 temp = info->port.xmit_buf;
1487 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001488 free_page((unsigned long)temp);
1489 }
1490
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 Slaby9fa1b3b182007-05-08 00:36:57 -07001497 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001498 }
1499
1500#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001501 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001502#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001503} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505/*
1506 * ------------------------------------------------------------
1507 * cy_open() and friends
1508 * ------------------------------------------------------------
1509 */
1510
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511/*
1512 * This routine is called whenever a serial port is opened. It
1513 * performs the serial-specific initialization for the tty structure.
1514 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001515static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
Jiri Slaby02f11752006-12-08 02:39:28 -08001517 struct cyclades_port *info;
Jiri Slaby410235f2012-03-05 14:52:01 +01001518 unsigned int i, line = tty->index;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001519 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Jiri Slabydd025c02007-05-08 00:37:02 -07001521 for (i = 0; i < NR_CARDS; i++)
1522 if (line < cy_card[i].first_line + cy_card[i].nports &&
1523 line >= cy_card[i].first_line)
1524 break;
1525 if (i >= NR_CARDS)
1526 return -ENODEV;
1527 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001528 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001529 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001530
1531 /* If the card's firmware hasn't been loaded,
1532 treat it as absent from the system. This
1533 will make the user pay attention.
1534 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001535 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001536 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001537 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1538
Jiri Slaby2693f482009-06-11 12:31:06 +01001539 if (!cyz_is_loaded(cinfo)) {
1540 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001541 readl(&firm_id->signature) ==
1542 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001543 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1544 "need an external power supply for "
1545 "this number of ports.\nFirmware "
1546 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001547 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001548 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1549 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001550 }
1551 return -ENODEV;
1552 }
1553#ifdef CONFIG_CYZ_INTR
1554 else {
1555 /* In case this Z board is operating in interrupt mode, its
1556 interrupts should be enabled as soon as the first open
1557 happens to one of its ports. */
1558 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001559 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001560
Jiri Slaby02f11752006-12-08 02:39:28 -08001561 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001562 intr = readw(&cinfo->ctl_addr.p9060->
1563 intr_ctrl_stat) | 0x0900;
1564 cy_writew(&cinfo->ctl_addr.p9060->
1565 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001566 /* Enable interrupts on the FW */
1567 retval = cyz_issue_cmd(cinfo, 0,
1568 C_CM_IRQ_ENBL, 0L);
1569 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001570 printk(KERN_ERR "cyc:IRQ enable retval "
1571 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001572 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001573 cinfo->intr_enabled = 1;
1574 }
1575 }
1576#endif /* CONFIG_CYZ_INTR */
1577 /* Make sure this Z port really exists in hardware */
1578 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1579 return -ENODEV;
1580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001582 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001584 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001585 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001586 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001589 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001590 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591#endif
Alan Cox77451e52008-07-16 21:57:02 +01001592 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001594 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001595 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
Jiri Slaby02f11752006-12-08 02:39:28 -08001598 /*
1599 * If the port is the middle of closing, bail out now
1600 */
Alan Cox77451e52008-07-16 21:57:02 +01001601 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
Arnd Bergmannbe1bc282010-06-01 22:53:05 +02001602 wait_event_interruptible_tty(info->port.close_wait,
Alan Cox77451e52008-07-16 21:57:02 +01001603 !(info->port.flags & ASYNC_CLOSING));
1604 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Jiri Slaby02f11752006-12-08 02:39:28 -08001607 /*
1608 * Start up serial port
1609 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001610 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001611 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
Jiri Slabyf0737572009-09-19 13:13:12 -07001614 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001615 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001617 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1618 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001620 return retval;
1621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Jiri Slaby02f11752006-12-08 02:39:28 -08001623 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001624 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
1626#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001627 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001629 return 0;
1630} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632/*
1633 * cy_wait_until_sent() --- wait until the transmitter is empty
1634 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001635static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
Jiri Slaby875b2062007-05-08 00:36:49 -07001637 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001638 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001639 unsigned long orig_jiffies;
1640 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Jiri Slaby02f11752006-12-08 02:39:28 -08001642 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1643 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
Jiri Slaby02f11752006-12-08 02:39:28 -08001645 if (info->xmit_fifo_size == 0)
1646 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Jiri Slaby02f11752006-12-08 02:39:28 -08001648 orig_jiffies = jiffies;
1649 /*
1650 * Set the check interval to be 1/5 of the estimated time to
1651 * send a single character, and make it at least 1. The check
1652 * interval should also be less than the timeout.
1653 *
1654 * Note: we have to use pretty tight timings here to satisfy
1655 * the NIST-PCTS.
1656 */
1657 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1658 char_time = char_time / 5;
1659 if (char_time <= 0)
1660 char_time = 1;
1661 if (timeout < 0)
1662 timeout = 0;
1663 if (timeout)
1664 char_time = min(char_time, timeout);
1665 /*
1666 * If the transmitter hasn't cleared in twice the approximate
1667 * amount of time to send the entire FIFO, it probably won't
1668 * ever clear. This assumes the UART isn't doing flow
1669 * control, which is currently the case. Hence, if it ever
1670 * takes longer than info->timeout, this is probably due to a
1671 * UART bug of some kind. So, we clamp the timeout parameter at
1672 * 2*info->timeout.
1673 */
1674 if (!timeout || timeout > 2 * info->timeout)
1675 timeout = 2 * info->timeout;
Jiri Slaby8bab5342011-07-14 14:35:15 +02001676
Jiri Slaby02f11752006-12-08 02:39:28 -08001677 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001678 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001679 while (cyy_readb(info, CySRER) & CyTxRdy) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001680 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1681 break;
1682 if (timeout && time_after(jiffies, orig_jiffies +
1683 timeout))
1684 break;
1685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001687 /* Run one more char cycle */
1688 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689}
1690
Alan Cox978e5952008-04-30 00:53:59 -07001691static void cy_flush_buffer(struct tty_struct *tty)
1692{
1693 struct cyclades_port *info = tty->driver_data;
1694 struct cyclades_card *card;
1695 int channel, retval;
1696 unsigned long flags;
1697
1698#ifdef CY_DEBUG_IO
1699 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1700#endif
1701
1702 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1703 return;
1704
1705 card = info->card;
1706 channel = info->line - card->first_line;
1707
1708 spin_lock_irqsave(&card->card_lock, flags);
1709 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1710 spin_unlock_irqrestore(&card->card_lock, flags);
1711
Jiri Slaby2693f482009-06-11 12:31:06 +01001712 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001713 buffers as well */
1714 spin_lock_irqsave(&card->card_lock, flags);
1715 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1716 if (retval != 0) {
1717 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1718 "was %x\n", info->line, retval);
1719 }
1720 spin_unlock_irqrestore(&card->card_lock, flags);
1721 }
1722 tty_wakeup(tty);
1723} /* cy_flush_buffer */
1724
1725
Alan Coxe936ffd2009-09-19 13:13:22 -07001726static void cy_do_close(struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727{
Alan Coxe936ffd2009-09-19 13:13:22 -07001728 struct cyclades_port *info = container_of(port, struct cyclades_port,
1729 port);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001730 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001731 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001732 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001734 card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001735 channel = info->line - card->first_line;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001736 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001737
Jiri Slaby2693f482009-06-11 12:31:06 +01001738 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001739 /* Stop accepting input */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001740 cyy_writeb(info, CyCAR, channel & 0x03);
1741 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001742 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001743 /* Waiting for on-board buffers to be empty before
1744 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001745 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001746 cy_wait_until_sent(port->tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001747 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001748 }
1749 } else {
1750#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001751 /* Waiting for on-board buffers to be empty before closing
1752 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001753 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001754 int retval;
1755
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001756 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001757 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001758 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001759 printk(KERN_DEBUG "cyc:cy_close retval on "
1760 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001761 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001762 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001763 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001764 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001765 }
1766#endif
1767 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001768 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001769 cy_shutdown(info, port->tty);
1770}
Jiri Slaby02f11752006-12-08 02:39:28 -08001771
Alan Coxe936ffd2009-09-19 13:13:22 -07001772/*
1773 * This routine is called when a particular tty device is closed.
1774 */
1775static void cy_close(struct tty_struct *tty, struct file *filp)
1776{
1777 struct cyclades_port *info = tty->driver_data;
1778 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1779 return;
1780 tty_port_close(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001781} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
1783/* This routine gets called when tty_write has put something into
1784 * the write_queue. The characters may come from user space or
1785 * kernel space.
1786 *
1787 * This routine will return the number of characters actually
1788 * accepted for writing.
1789 *
1790 * If the port is not already transmitting stuff, start it off by
1791 * enabling interrupts. The interrupt service routine will then
1792 * ensure that the characters are sent.
1793 * If the port is already active, there is no need to kick it.
1794 *
1795 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001796static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001798 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001799 unsigned long flags;
1800 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001803 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804#endif
1805
Alan Cox15ed6cc2008-04-30 00:53:55 -07001806 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001807 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Alan Cox77451e52008-07-16 21:57:02 +01001809 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001810 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001812 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001814 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1815 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
Jiri Slaby02f11752006-12-08 02:39:28 -08001817 if (c <= 0)
1818 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Alan Cox77451e52008-07-16 21:57:02 +01001820 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001821 info->xmit_head = (info->xmit_head + c) &
1822 (SERIAL_XMIT_SIZE - 1);
1823 info->xmit_cnt += c;
1824 buf += c;
1825 count -= c;
1826 ret += c;
1827 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001828 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Jiri Slaby02f11752006-12-08 02:39:28 -08001830 info->idle_stats.xmit_bytes += ret;
1831 info->idle_stats.xmit_idle = jiffies;
1832
Alan Cox15ed6cc2008-04-30 00:53:55 -07001833 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001834 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001835
Jiri Slaby02f11752006-12-08 02:39:28 -08001836 return ret;
1837} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838
1839/*
1840 * This routine is called by the kernel to write a single
1841 * character to the tty device. If the kernel uses this routine,
1842 * it must call the flush_chars() routine (if defined) when it is
1843 * done stuffing characters into the driver. If there is no room
1844 * in the queue, the character is ignored.
1845 */
Alan Cox76b25a52008-04-30 00:54:03 -07001846static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001848 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001849 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001852 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853#endif
1854
Jiri Slaby02f11752006-12-08 02:39:28 -08001855 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001856 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
Alan Cox77451e52008-07-16 21:57:02 +01001858 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001861 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001862 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001863 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001864 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Alan Cox77451e52008-07-16 21:57:02 +01001867 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001868 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1869 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 info->idle_stats.xmit_bytes++;
1871 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001872 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001873 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001874} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876/*
1877 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001878 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001880static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001882 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001883
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001885 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886#endif
1887
Jiri Slaby02f11752006-12-08 02:39:28 -08001888 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1889 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Jiri Slaby02f11752006-12-08 02:39:28 -08001891 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001892 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001893 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Jiri Slaby02f11752006-12-08 02:39:28 -08001895 start_xmit(info);
1896} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898/*
1899 * This routine returns the numbers of characters the tty driver
1900 * will accept for queuing to be written. This number is subject
1901 * to change as output buffers get emptied, or if the output flow
1902 * control is activated.
1903 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001904static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001906 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 int ret;
1908
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001910 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911#endif
1912
Jiri Slaby02f11752006-12-08 02:39:28 -08001913 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1914 return 0;
1915 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1916 if (ret < 0)
1917 ret = 0;
1918 return ret;
1919} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Jiri Slaby02f11752006-12-08 02:39:28 -08001921static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001923 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
Jiri Slaby02f11752006-12-08 02:39:28 -08001925 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1926 return 0;
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001929 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001930#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001932 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1933 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001935 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08001937 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001938 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001939 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07001940 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001942 tx_get = readl(&buf_ctrl->tx_get);
1943 tx_put = readl(&buf_ctrl->tx_put);
1944 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08001945 if (tx_put >= tx_get)
1946 char_count = tx_put - tx_get;
1947 else
1948 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001950 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1951 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952#endif
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001953 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08001954 }
1955#endif /* Z_EXT_CHARS_IN_BUFFER */
1956} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
1958/*
1959 * ------------------------------------------------------------
1960 * cy_ioctl() and friends
1961 * ------------------------------------------------------------
1962 */
1963
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001964static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965{
Jiri Slaby02f11752006-12-08 02:39:28 -08001966 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001967 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08001968 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
Jiri Slaby02f11752006-12-08 02:39:28 -08001970 if (baud == 0) {
1971 info->tbpr = info->tco = info->rbpr = info->rco = 0;
1972 return;
1973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
Jiri Slaby02f11752006-12-08 02:39:28 -08001975 /* determine which prescaler to use */
1976 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
1977 if (cy_clock / co_val / baud > 63)
1978 break;
1979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Jiri Slaby02f11752006-12-08 02:39:28 -08001981 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
1982 if (bpr > 255)
1983 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Jiri Slaby02f11752006-12-08 02:39:28 -08001985 info->tbpr = info->rbpr = bpr;
1986 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987}
1988
1989/*
1990 * This routine finds or computes the various line characteristics.
1991 * It used to be called config_setup
1992 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001993static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994{
Jiri Slaby875b2062007-05-08 00:36:49 -07001995 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001996 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001997 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001998 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 int baud, baud_rate = 0;
2000 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
Jiri Slabyd13549f2009-09-19 13:13:12 -07002002 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002003 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002004
2005 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002006 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002007
Jiri Slabyd13549f2009-09-19 13:13:12 -07002008 cflag = tty->termios->c_cflag;
2009 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Jiri Slaby02f11752006-12-08 02:39:28 -08002011 /*
2012 * Set up the tty->alt_speed kludge
2013 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002014 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2015 tty->alt_speed = 57600;
2016 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2017 tty->alt_speed = 115200;
2018 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2019 tty->alt_speed = 230400;
2020 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2021 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
Jiri Slaby02f11752006-12-08 02:39:28 -08002023 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002024 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002025
Jiri Slaby2693f482009-06-11 12:31:06 +01002026 if (!cy_is_Z(card)) {
Jiri Slaby46fb7822009-09-19 13:13:17 -07002027 u32 cflags;
2028
Jiri Slaby02f11752006-12-08 02:39:28 -08002029 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002030 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002031 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002032 ASYNC_SPD_CUST) {
2033 if (info->custom_divisor)
2034 baud_rate = info->baud / info->custom_divisor;
2035 else
2036 baud_rate = info->baud;
2037 } else if (baud > CD1400_MAX_SPEED) {
2038 baud = CD1400_MAX_SPEED;
2039 }
2040 /* find the baud index */
2041 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002042 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002043 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002044 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002045 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002046 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002047
Alan Cox77451e52008-07-16 21:57:02 +01002048 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002049 ASYNC_SPD_CUST) {
2050 cyy_baud_calc(info, baud_rate);
2051 } else {
2052 if (info->chip_rev >= CD1400_REV_J) {
2053 /* It is a CD1400 rev. J or later */
2054 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2055 info->tco = baud_co_60[i]; /* Tx CO */
2056 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2057 info->rco = baud_co_60[i]; /* Rx CO */
2058 } else {
2059 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2060 info->tco = baud_co_25[i]; /* Tx CO */
2061 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2062 info->rco = baud_co_25[i]; /* Rx CO */
2063 }
2064 }
2065 if (baud_table[i] == 134) {
2066 /* get it right for 134.5 baud */
2067 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2068 2;
Alan Cox77451e52008-07-16 21:57:02 +01002069 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002070 ASYNC_SPD_CUST) {
2071 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2072 baud_rate) + 2;
2073 } else if (baud_table[i]) {
2074 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2075 baud_table[i]) + 2;
2076 /* this needs to be propagated into the card info */
2077 } else {
2078 info->timeout = 0;
2079 }
2080 /* By tradition (is it a standard?) a baud rate of zero
2081 implies the line should be/has been closed. A bit
2082 later in this routine such a test is performed. */
2083
2084 /* byte size and parity */
2085 info->cor5 = 0;
2086 info->cor4 = 0;
2087 /* receive threshold */
2088 info->cor3 = (info->default_threshold ?
2089 info->default_threshold : baud_cor3[i]);
2090 info->cor2 = CyETC;
2091 switch (cflag & CSIZE) {
2092 case CS5:
2093 info->cor1 = Cy_5_BITS;
2094 break;
2095 case CS6:
2096 info->cor1 = Cy_6_BITS;
2097 break;
2098 case CS7:
2099 info->cor1 = Cy_7_BITS;
2100 break;
2101 case CS8:
2102 info->cor1 = Cy_8_BITS;
2103 break;
2104 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002105 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002106 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002107
Jiri Slaby02f11752006-12-08 02:39:28 -08002108 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002109 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002110 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002111 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002112 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002113 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002114 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002115
2116 /* CTS flow control flag */
2117 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002118 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002119 info->cor2 |= CyCtsAE;
2120 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002121 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002122 info->cor2 &= ~CyCtsAE;
2123 }
2124 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002125 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002126 else
Alan Cox77451e52008-07-16 21:57:02 +01002127 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
2129 /***********************************************
2130 The hardware option, CyRtsAO, presents RTS when
2131 the chip has characters to send. Since most modems
2132 use RTS as reverse (inbound) flow control, this
2133 option is not used. If inbound flow control is
2134 necessary, DTR can be programmed to provide the
2135 appropriate signals for use with a non-standard
2136 cable. Contact Marcio Saito for details.
2137 ***********************************************/
2138
Jiri Slaby02f11752006-12-08 02:39:28 -08002139 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002141 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002142 cyy_writeb(info, CyCAR, channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Jiri Slaby02f11752006-12-08 02:39:28 -08002144 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002146 cyy_writeb(info, CyTCOR, info->tco);
2147 cyy_writeb(info, CyTBPR, info->tbpr);
2148 cyy_writeb(info, CyRCOR, info->rco);
2149 cyy_writeb(info, CyRBPR, info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150
Jiri Slaby02f11752006-12-08 02:39:28 -08002151 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002153 cyy_writeb(info, CySCHR1, START_CHAR(tty));
2154 cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2155 cyy_writeb(info, CyCOR1, info->cor1);
2156 cyy_writeb(info, CyCOR2, info->cor2);
2157 cyy_writeb(info, CyCOR3, info->cor3);
2158 cyy_writeb(info, CyCOR4, info->cor4);
2159 cyy_writeb(info, CyCOR5, info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002161 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2162 CyCOR3ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
Alan Cox15ed6cc2008-04-30 00:53:55 -07002164 /* !!! Is this needed? */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002165 cyy_writeb(info, CyCAR, channel);
2166 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08002167 (info->default_timeout ? info->default_timeout : 0x02));
2168 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
Jiri Slaby46fb7822009-09-19 13:13:17 -07002170 cflags = CyCTS;
2171 if (!C_CLOCAL(tty))
2172 cflags |= CyDSR | CyRI | CyDCD;
2173 /* without modem intr */
2174 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2175 /* act on 1->0 modem transitions */
2176 if ((cflag & CRTSCTS) && info->rflow)
2177 cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2178 else
2179 cyy_writeb(info, CyMCOR1, cflags);
2180 /* act on 0->1 modem transitions */
2181 cyy_writeb(info, CyMCOR2, cflags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002182
Jiri Slaby4d768202009-09-19 13:13:15 -07002183 if (i == 0) /* baud rate is zero, turn off line */
2184 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2185 else
2186 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
Jiri Slabyd13549f2009-09-19 13:13:12 -07002188 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002189 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002192 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002193 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002194 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
Jiri Slaby2693f482009-06-11 12:31:06 +01002196 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002197 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Jiri Slaby02f11752006-12-08 02:39:28 -08002199 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002200 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002201 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002202 ASYNC_SPD_CUST) {
2203 if (info->custom_divisor)
2204 baud_rate = info->baud / info->custom_divisor;
2205 else
2206 baud_rate = info->baud;
2207 } else if (baud > CYZ_MAX_SPEED) {
2208 baud = CYZ_MAX_SPEED;
2209 }
2210 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
Jiri Slaby02f11752006-12-08 02:39:28 -08002212 if (baud == 134) {
2213 /* get it right for 134.5 baud */
2214 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2215 2;
Alan Cox77451e52008-07-16 21:57:02 +01002216 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002217 ASYNC_SPD_CUST) {
2218 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2219 baud_rate) + 2;
2220 } else if (baud) {
2221 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2222 baud) + 2;
2223 /* this needs to be propagated into the card info */
2224 } else {
2225 info->timeout = 0;
2226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Jiri Slaby02f11752006-12-08 02:39:28 -08002228 /* byte size and parity */
2229 switch (cflag & CSIZE) {
2230 case CS5:
2231 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2232 break;
2233 case CS6:
2234 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2235 break;
2236 case CS7:
2237 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2238 break;
2239 case CS8:
2240 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2241 break;
2242 }
2243 if (cflag & CSTOPB) {
2244 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002245 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002246 } else {
2247 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002248 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002249 }
2250 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002251 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002252 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002253 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002254 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002255 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002256 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Jiri Slaby02f11752006-12-08 02:39:28 -08002258 /* CTS flow control flag */
2259 if (cflag & CRTSCTS) {
2260 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002261 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002262 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002263 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2264 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002265 }
2266 /* As the HW flow control is done in firmware, the driver
2267 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002268 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002269
2270 /* XON/XOFF/XANY flow control flags */
2271 sw_flow = 0;
2272 if (iflag & IXON) {
2273 sw_flow |= C_FL_OXX;
2274 if (iflag & IXANY)
2275 sw_flow |= C_FL_OIXANY;
2276 }
2277 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2278
Jiri Slaby875b2062007-05-08 00:36:49 -07002279 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002280 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002281 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2282 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002283 }
2284
2285 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002286 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002287 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002288 else
Alan Cox77451e52008-07-16 21:57:02 +01002289 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002290
2291 if (baud == 0) { /* baud rate is zero, turn off line */
2292 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002293 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002295 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002297 } else {
2298 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002299 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002301 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Alan Cox15ed6cc2008-04-30 00:53:55 -07002305 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002306 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002307 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2308 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Jiri Slabyd13549f2009-09-19 13:13:12 -07002311 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002313} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Jiri Slaby6c281812009-09-19 13:13:15 -07002315static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002316 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317{
Jiri Slaby875b2062007-05-08 00:36:49 -07002318 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002319 struct serial_struct tmp = {
2320 .type = info->type,
2321 .line = info->line,
2322 .port = (info->card - cy_card) * 0x100 + info->line -
2323 cinfo->first_line,
2324 .irq = cinfo->irq,
2325 .flags = info->port.flags,
2326 .close_delay = info->port.close_delay,
2327 .closing_wait = info->port.closing_wait,
2328 .baud_base = info->baud,
2329 .custom_divisor = info->custom_divisor,
2330 .hub6 = 0, /*!!! */
2331 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002332 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002333}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334
2335static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002336cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002337 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338{
Jiri Slaby02f11752006-12-08 02:39:28 -08002339 struct serial_struct new_serial;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002340 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
Jiri Slaby02f11752006-12-08 02:39:28 -08002342 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2343 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Alan Cox25c3cdf2010-06-01 22:52:47 +02002345 mutex_lock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002346 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002347 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002348 new_serial.baud_base != info->baud ||
2349 (new_serial.flags & ASYNC_FLAGS &
2350 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002351 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Alan Cox25c3cdf2010-06-01 22:52:47 +02002352 {
2353 mutex_unlock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002354 return -EPERM;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002355 }
Alan Cox77451e52008-07-16 21:57:02 +01002356 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002357 (new_serial.flags & ASYNC_USR_MASK);
2358 info->baud = new_serial.baud_base;
2359 info->custom_divisor = new_serial.custom_divisor;
2360 goto check_and_exit;
2361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
Jiri Slaby02f11752006-12-08 02:39:28 -08002363 /*
2364 * OK, past this point, all the error checking has been done.
2365 * At this point, we start making changes.....
2366 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Jiri Slaby02f11752006-12-08 02:39:28 -08002368 info->baud = new_serial.baud_base;
2369 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002370 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002371 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002372 info->port.close_delay = new_serial.close_delay * HZ / 100;
2373 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002376 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002377 cy_set_line_char(info, tty);
Alan Cox25c3cdf2010-06-01 22:52:47 +02002378 ret = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002379 } else {
Alan Cox25c3cdf2010-06-01 22:52:47 +02002380 ret = cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002381 }
Alan Cox25c3cdf2010-06-01 22:52:47 +02002382 mutex_unlock(&info->port.mutex);
2383 return ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002384} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
2386/*
2387 * get_lsr_info - get line status register info
2388 *
2389 * Purpose: Let user call ioctl() to get info when the UART physically
2390 * is emptied. On bus types like RS485, the transmitter must
2391 * release the bus after transmitting. This must be done when
2392 * the transmit shift register is empty, not be done when the
2393 * transmit holding register is empty. This functionality
2394 * allows an RS485 driver to be written in user space.
2395 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002396static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002398 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002399 unsigned int result;
2400 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002401 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
Jiri Slaby2693f482009-06-11 12:31:06 +01002403 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002404 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002405 status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002406 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002407 result = (status ? 0 : TIOCSER_TEMT);
2408 } else {
2409 /* Not supported yet */
2410 return -EINVAL;
2411 }
Dan Carpenterdbca36e2012-03-05 21:07:11 +03002412 return put_user(result, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413}
2414
Alan Cox60b33c12011-02-14 16:26:14 +00002415static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002417 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002418 struct cyclades_card *card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002419 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002421 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002422 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
Jiri Slaby02f11752006-12-08 02:39:28 -08002424 card = info->card;
Jiri Slaby0d348722009-09-19 13:13:16 -07002425
Jiri Slaby2693f482009-06-11 12:31:06 +01002426 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002427 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002428 int channel = info->line - card->first_line;
2429 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002431 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002432 cyy_writeb(info, CyCAR, channel & 0x03);
2433 status = cyy_readb(info, CyMSVR1);
2434 status |= cyy_readb(info, CyMSVR2);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002435 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Jiri Slaby02f11752006-12-08 02:39:28 -08002437 if (info->rtsdtr_inv) {
2438 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2439 ((status & CyDTR) ? TIOCM_RTS : 0);
2440 } else {
2441 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2442 ((status & CyDTR) ? TIOCM_DTR : 0);
2443 }
2444 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2445 ((status & CyRI) ? TIOCM_RNG : 0) |
2446 ((status & CyDSR) ? TIOCM_DSR : 0) |
2447 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002449 u32 lstatus;
2450
2451 if (!cyz_is_loaded(card)) {
2452 result = -ENODEV;
2453 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002454 }
2455
Jiri Slaby0d348722009-09-19 13:13:16 -07002456 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2457 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2458 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2459 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2460 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2461 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2462 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002464end:
Jiri Slaby02f11752006-12-08 02:39:28 -08002465 return result;
2466} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468static int
Alan Cox20b9d172011-02-14 16:26:50 +00002469cy_tiocmset(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002470 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002472 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002473 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002474 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002476 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002477 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
Jiri Slaby02f11752006-12-08 02:39:28 -08002479 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002480 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002481 spin_lock_irqsave(&card->card_lock, flags);
2482 cyy_change_rts_dtr(info, set, clear);
2483 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002484 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002485 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2486 int retval, channel = info->line - card->first_line;
2487 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002488
Jiri Slaby0d348722009-09-19 13:13:16 -07002489 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002490 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002491
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002492 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002493 rs = readl(&ch_ctrl->rs_control);
2494 if (set & TIOCM_RTS)
2495 rs |= C_RS_RTS;
2496 if (clear & TIOCM_RTS)
2497 rs &= ~C_RS_RTS;
2498 if (set & TIOCM_DTR) {
2499 rs |= C_RS_DTR;
2500#ifdef CY_DEBUG_DTR
2501 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2502#endif
2503 }
2504 if (clear & TIOCM_DTR) {
2505 rs &= ~C_RS_DTR;
2506#ifdef CY_DEBUG_DTR
2507 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2508 "Z DTR\n");
2509#endif
2510 }
2511 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002512 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002513 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002514 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002515 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2516 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002519 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002520}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
2522/*
2523 * cy_break() --- routine which turns the break handling on or off
2524 */
Alan Cox9e989662008-07-22 11:18:03 +01002525static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002527 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002528 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002529 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002530 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Jiri Slaby02f11752006-12-08 02:39:28 -08002532 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002533 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002535 card = info->card;
2536
2537 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002538 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002539 /* Let the transmit ISR take care of this (since it
2540 requires stuffing characters into the output stream).
2541 */
2542 if (break_state == -1) {
2543 if (!info->breakon) {
2544 info->breakon = 1;
2545 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002546 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002547 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002548 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002549 }
2550 }
2551 } else {
2552 if (!info->breakoff) {
2553 info->breakoff = 1;
2554 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002555 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002556 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002557 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002558 }
2559 }
2560 }
2561 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002562 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002563 retval = cyz_issue_cmd(card,
2564 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002565 C_CM_SET_BREAK, 0L);
2566 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002567 printk(KERN_ERR "cyc:cy_break (set) retval on "
2568 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002569 }
2570 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002571 retval = cyz_issue_cmd(card,
2572 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002573 C_CM_CLR_BREAK, 0L);
2574 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002575 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2576 "on ttyC%d was %x\n", info->line,
2577 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002578 }
2579 }
2580 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002581 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002582 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002583} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
Jiri Slaby02f11752006-12-08 02:39:28 -08002585static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002587 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002588 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
Jiri Slaby2693f482009-06-11 12:31:06 +01002590 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002591 info->cor3 &= ~CyREC_FIFO;
2592 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002594 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002595 cyy_writeb(info, CyCOR3, info->cor3);
2596 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002597 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002600} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
Alan Cox15ed6cc2008-04-30 00:53:55 -07002602static int get_threshold(struct cyclades_port *info,
2603 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002605 struct cyclades_card *card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Jiri Slaby2693f482009-06-11 12:31:06 +01002607 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002608 u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002609 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002610 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002611 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002612} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
Jiri Slaby02f11752006-12-08 02:39:28 -08002614static int set_timeout(struct cyclades_port *info, unsigned long value)
2615{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002616 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002617 unsigned long flags;
2618
Jiri Slaby2693f482009-06-11 12:31:06 +01002619 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002620 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002621 cyy_writeb(info, CyRTPR, value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002622 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002623 }
2624 return 0;
2625} /* set_timeout */
2626
Alan Cox15ed6cc2008-04-30 00:53:55 -07002627static int get_timeout(struct cyclades_port *info,
2628 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002629{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002630 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002631
Jiri Slaby2693f482009-06-11 12:31:06 +01002632 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002633 u8 tmp = cyy_readb(info, CyRTPR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002634 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002635 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002636 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002637} /* get_timeout */
2638
Jiri Slaby6c281812009-09-19 13:13:15 -07002639static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2640 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002641{
Jiri Slaby6c281812009-09-19 13:13:15 -07002642 struct cyclades_icount cnow;
2643 unsigned long flags;
2644 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002645
Jiri Slaby6c281812009-09-19 13:13:15 -07002646 spin_lock_irqsave(&info->card->card_lock, flags);
2647 cnow = info->icount; /* atomic copy */
2648 spin_unlock_irqrestore(&info->card->card_lock, flags);
2649
2650 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2651 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2652 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2653 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2654
2655 *cprev = cnow;
2656
2657 return ret;
2658}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
2660/*
2661 * This routine allows the tty driver to implement device-
2662 * specific ioctl's. If the ioctl number passed in cmd is
2663 * not recognized by the driver, it should return ENOIOCTLCMD.
2664 */
2665static int
Alan Cox6caa76b2011-02-14 16:27:22 +00002666cy_ioctl(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002667 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002669 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002670 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002671 int ret_val = 0;
2672 unsigned long flags;
2673 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
Jiri Slaby02f11752006-12-08 02:39:28 -08002675 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2676 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
2678#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002679 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2680 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681#endif
2682
Jiri Slaby02f11752006-12-08 02:39:28 -08002683 switch (cmd) {
2684 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002685 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2686 ret_val = -EFAULT;
2687 break;
2688 }
2689 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002691 case CYGETTHRESH:
2692 ret_val = get_threshold(info, argp);
2693 break;
2694 case CYSETTHRESH:
2695 ret_val = set_threshold(info, arg);
2696 break;
2697 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002698 ret_val = put_user(info->default_threshold,
2699 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002700 break;
2701 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002702 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002703 break;
2704 case CYGETTIMEOUT:
2705 ret_val = get_timeout(info, argp);
2706 break;
2707 case CYSETTIMEOUT:
2708 ret_val = set_timeout(info, arg);
2709 break;
2710 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002711 ret_val = put_user(info->default_timeout,
2712 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002713 break;
2714 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002715 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002716 break;
2717 case CYSETRFLOW:
2718 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002719 break;
2720 case CYGETRFLOW:
2721 ret_val = info->rflow;
2722 break;
2723 case CYSETRTSDTR_INV:
2724 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002725 break;
2726 case CYGETRTSDTR_INV:
2727 ret_val = info->rtsdtr_inv;
2728 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002730 ret_val = info->chip_rev;
2731 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732#ifndef CONFIG_CYZ_INTR
2733 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002735 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002737 ret_val = (cyz_polling_cycle * 1000) / HZ;
2738 break;
2739#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002741 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002742 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002744 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002745 break;
2746 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002747 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002748 break;
2749 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002750 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002751 break;
2752 case TIOCSERGETLSR: /* Get line status register */
2753 ret_val = get_lsr_info(info, argp);
2754 break;
2755 /*
2756 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2757 * - mask passed in arg for lines of interest
2758 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2759 * Caller should use TIOCGICOUNT to see which one it was
2760 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002762 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002763 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002764 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002765 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Coxbdc04e32009-09-19 13:13:31 -07002766 ret_val = wait_event_interruptible(info->port.delta_msr_wait,
Jiri Slaby6c281812009-09-19 13:13:15 -07002767 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002768 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002769
2770 /*
2771 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2772 * Return: write counters to the user passed counter struct
2773 * NB: both 1->0 and 0->1 transitions are counted except for
2774 * RI where only 0->1 is counted.
2775 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002776 default:
2777 ret_val = -ENOIOCTLCMD;
2778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
2780#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002781 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002783 return ret_val;
2784} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Alan Cox05871022010-09-16 18:21:52 +01002786static int cy_get_icount(struct tty_struct *tty,
2787 struct serial_icounter_struct *sic)
2788{
2789 struct cyclades_port *info = tty->driver_data;
2790 struct cyclades_icount cnow; /* Used to snapshot */
2791 unsigned long flags;
2792
2793 spin_lock_irqsave(&info->card->card_lock, flags);
2794 cnow = info->icount;
2795 spin_unlock_irqrestore(&info->card->card_lock, flags);
2796
2797 sic->cts = cnow.cts;
2798 sic->dsr = cnow.dsr;
2799 sic->rng = cnow.rng;
2800 sic->dcd = cnow.dcd;
2801 sic->rx = cnow.rx;
2802 sic->tx = cnow.tx;
2803 sic->frame = cnow.frame;
2804 sic->overrun = cnow.overrun;
2805 sic->parity = cnow.parity;
2806 sic->brk = cnow.brk;
2807 sic->buf_overrun = cnow.buf_overrun;
2808 return 0;
2809}
2810
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811/*
2812 * This routine allows the tty driver to be notified when
2813 * device's termios settings have changed. Note that a
2814 * well-designed tty driver should be prepared to accept the case
2815 * where old == NULL, and try to do something rational.
2816 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002817static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002819 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
2821#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002822 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823#endif
2824
Jiri Slabyd13549f2009-09-19 13:13:12 -07002825 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
Jiri Slaby02f11752006-12-08 02:39:28 -08002827 if ((old_termios->c_cflag & CRTSCTS) &&
2828 !(tty->termios->c_cflag & CRTSCTS)) {
2829 tty->hw_stopped = 0;
2830 cy_start(tty);
2831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002833 /*
2834 * No need to wake up processes in open wait, since they
2835 * sample the CLOCAL flag once, and don't recheck it.
2836 * XXX It's not clear whether the current behavior is correct
2837 * or not. Hence, this may change.....
2838 */
2839 if (!(old_termios->c_cflag & CLOCAL) &&
2840 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01002841 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002843} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
2845/* This function is used to send a high-priority XON/XOFF character to
2846 the device.
2847*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002848static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002850 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002851 struct cyclades_card *card;
2852 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853
Jiri Slaby02f11752006-12-08 02:39:28 -08002854 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 return;
2856
Jiri Slaby02f11752006-12-08 02:39:28 -08002857 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08002860 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002863 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864
Jiri Slaby2693f482009-06-11 12:31:06 +01002865 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002866 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002867 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002868 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002869 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 }
2871}
2872
2873/* This routine is called by the upper-layer tty layer to signal
2874 that incoming characters should be throttled because the input
2875 buffers are close to full.
2876 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002877static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002879 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002880 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002881 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
2883#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002884 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
Jiri Slaby21719192007-05-08 00:36:42 -07002886 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08002887 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888#endif
2889
Alan Cox15ed6cc2008-04-30 00:53:55 -07002890 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002891 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892
Jiri Slaby02f11752006-12-08 02:39:28 -08002893 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
Jiri Slaby02f11752006-12-08 02:39:28 -08002895 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002896 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002897 cy_send_xchar(tty, STOP_CHAR(tty));
2898 else
2899 info->throttle = 1;
2900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Jiri Slaby02f11752006-12-08 02:39:28 -08002902 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002903 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002904 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002905 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002906 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002907 } else {
2908 info->throttle = 1;
2909 }
2910 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002911} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913/*
2914 * This routine notifies the tty driver that it should signal
2915 * that characters can now be sent to the tty without fear of
2916 * overrunning the input buffers of the line disciplines.
2917 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002918static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002920 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002921 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002922 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
2924#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002925 char buf[64];
2926
Jiri Slaby21719192007-05-08 00:36:42 -07002927 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07002928 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929#endif
2930
Alan Cox15ed6cc2008-04-30 00:53:55 -07002931 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002932 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
Jiri Slaby02f11752006-12-08 02:39:28 -08002934 if (I_IXOFF(tty)) {
2935 if (info->x_char)
2936 info->x_char = 0;
2937 else
2938 cy_send_xchar(tty, START_CHAR(tty));
2939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940
Jiri Slaby02f11752006-12-08 02:39:28 -08002941 if (tty->termios->c_cflag & CRTSCTS) {
2942 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002943 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002944 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002945 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002946 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002947 } else {
2948 info->throttle = 0;
2949 }
2950 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002951} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
2953/* cy_start and cy_stop provide software output flow control as a
2954 function of XON/XOFF, software CTS, and other such stuff.
2955*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002956static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957{
Jiri Slaby02f11752006-12-08 02:39:28 -08002958 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002959 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002960 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002961 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002964 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965#endif
2966
Jiri Slaby02f11752006-12-08 02:39:28 -08002967 if (serial_paranoia_check(info, tty->name, "cy_stop"))
2968 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969
Jiri Slaby875b2062007-05-08 00:36:49 -07002970 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002971 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002972 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002973 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002974 cyy_writeb(info, CyCAR, channel & 0x03);
2975 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002976 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002978} /* cy_stop */
2979
2980static void cy_start(struct tty_struct *tty)
2981{
2982 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002983 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002984 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002985 unsigned long flags;
2986
2987#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002988 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08002989#endif
2990
2991 if (serial_paranoia_check(info, tty->name, "cy_start"))
2992 return;
2993
Jiri Slaby875b2062007-05-08 00:36:49 -07002994 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002995 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002996 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002997 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002998 cyy_writeb(info, CyCAR, channel & 0x03);
2999 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003000 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003001 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003002} /* cy_start */
3003
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004/*
3005 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3006 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003007static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003009 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003010
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003012 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013#endif
3014
Jiri Slaby02f11752006-12-08 02:39:28 -08003015 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3016 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
Jiri Slaby02f11752006-12-08 02:39:28 -08003018 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003019 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003020 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003021} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022
Jiri Slabyf0737572009-09-19 13:13:12 -07003023static int cyy_carrier_raised(struct tty_port *port)
3024{
3025 struct cyclades_port *info = container_of(port, struct cyclades_port,
3026 port);
3027 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003028 unsigned long flags;
3029 int channel = info->line - cinfo->first_line;
Jiri Slabyf0737572009-09-19 13:13:12 -07003030 u32 cd;
3031
Jiri Slabyf0737572009-09-19 13:13:12 -07003032 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003033 cyy_writeb(info, CyCAR, channel & 0x03);
3034 cd = cyy_readb(info, CyMSVR1) & CyDCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003035 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3036
3037 return cd;
3038}
3039
3040static void cyy_dtr_rts(struct tty_port *port, int raise)
3041{
3042 struct cyclades_port *info = container_of(port, struct cyclades_port,
3043 port);
3044 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003045 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003046
3047 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003048 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3049 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003050 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3051}
3052
3053static int cyz_carrier_raised(struct tty_port *port)
3054{
3055 struct cyclades_port *info = container_of(port, struct cyclades_port,
3056 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003057
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003058 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003059}
3060
3061static void cyz_dtr_rts(struct tty_port *port, int raise)
3062{
3063 struct cyclades_port *info = container_of(port, struct cyclades_port,
3064 port);
3065 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003066 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003067 int ret, channel = info->line - cinfo->first_line;
3068 u32 rs;
3069
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003070 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003071 if (raise)
3072 rs |= C_RS_RTS | C_RS_DTR;
3073 else
3074 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003075 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003076 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3077 if (ret != 0)
3078 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3079 __func__, info->line, ret);
3080#ifdef CY_DEBUG_DTR
3081 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3082#endif
3083}
3084
3085static const struct tty_port_operations cyy_port_ops = {
3086 .carrier_raised = cyy_carrier_raised,
3087 .dtr_rts = cyy_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003088 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003089};
3090
3091static const struct tty_port_operations cyz_port_ops = {
3092 .carrier_raised = cyz_carrier_raised,
3093 .dtr_rts = cyz_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003094 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003095};
3096
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097/*
3098 * ---------------------------------------------------------------------
3099 * cy_init() and friends
3100 *
3101 * cy_init() is called at boot-time to initialize the serial driver.
3102 * ---------------------------------------------------------------------
3103 */
3104
Jiri Slabydd025c02007-05-08 00:37:02 -07003105static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003106{
3107 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003108 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003109
Jiri Slaby3046d502007-05-08 00:36:46 -07003110 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003111 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003112
Jiri Slaby963118e2009-06-11 12:34:27 +01003113 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3114 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003115 if (cinfo->ports == NULL) {
3116 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3117 return -ENOMEM;
3118 }
3119
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003120 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3121 channel++, port++) {
3122 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003123 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003124 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003125 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003126 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003127
Alan Cox44b7d1b2008-07-16 21:57:18 +01003128 info->port.closing_wait = CLOSING_WAIT_DELAY;
3129 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003130 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003131 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003132
Jiri Slaby2693f482009-06-11 12:31:06 +01003133 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003134 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3135 struct ZFW_CTRL *zfw_ctrl;
3136
Jiri Slabyf0737572009-09-19 13:13:12 -07003137 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003138 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003139
3140 zfw_ctrl = cinfo->base_addr +
3141 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3142 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3143 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3144
Jiri Slaby101b8152009-06-11 12:30:10 +01003145 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003146 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3147 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003148 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003149#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003150 setup_timer(&cyz_rx_full_timer[port],
3151 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003152#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003153 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003154 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003155 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003156
Jiri Slabyf0737572009-09-19 13:13:12 -07003157 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003158 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003159 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003160 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003161 info->cor2 = CyETC;
3162 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003163
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003164 chip_number = channel / CyPORTS_PER_CHIP;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003165 info->u.cyy.base_addr = cinfo->base_addr +
3166 (cy_chip_offset[chip_number] << index);
3167 info->chip_rev = cyy_readb(info, CyGFRCR);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003168
3169 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003170 /* It is a CD1400 rev. J or later */
3171 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3172 info->tco = baud_co_60[13]; /* Tx CO */
3173 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3174 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003175 info->rtsdtr_inv = 1;
3176 } else {
3177 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3178 info->tco = baud_co_25[13]; /* Tx CO */
3179 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3180 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003181 info->rtsdtr_inv = 0;
3182 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003183 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3184 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003185 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003186
Jiri Slaby0809e262007-05-08 00:36:14 -07003187 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003188
3189#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003190 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003191 mod_timer(&cyz_timerlist, jiffies + 1);
3192#ifdef CY_PCI_DEBUG
3193 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3194#endif
3195 }
3196#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003197 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003198}
3199
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200/* initialize chips on Cyclom-Y card -- return number of valid
3201 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003202static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3203 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204{
Jiri Slaby02f11752006-12-08 02:39:28 -08003205 unsigned int chip_number;
3206 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Jiri Slaby02f11752006-12-08 02:39:28 -08003208 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3209 /* Cy_HwReset is 0x1400 */
3210 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3211 /* Cy_ClrIntr is 0x1800 */
3212 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
Alan Cox15ed6cc2008-04-30 00:53:55 -07003214 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3215 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003216 base_addr =
3217 true_base_addr + (cy_chip_offset[chip_number] << index);
3218 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003219 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003220 /*************
3221 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3222 chip_number, (unsigned long)base_addr);
3223 *************/
3224 return chip_number;
3225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226
Jiri Slaby02f11752006-12-08 02:39:28 -08003227 cy_writeb(base_addr + (CyGFRCR << index), 0);
3228 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
Jiri Slaby02f11752006-12-08 02:39:28 -08003230 /* The Cyclom-16Y does not decode address bit 9 and therefore
3231 cannot distinguish between references to chip 0 and a non-
3232 existent chip 4. If the preceding clearing of the supposed
3233 chip 4 GFRCR register appears at chip 0, there is no chip 4
3234 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3235 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003236 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003237 (cy_chip_offset[0] << index) +
3238 (CyGFRCR << index)) == 0) {
3239 return chip_number;
3240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
Jiri Slaby02f11752006-12-08 02:39:28 -08003242 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3243 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003245 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003246 /*
3247 printk(" chip #%d at %#6lx is not responding ",
3248 chip_number, (unsigned long)base_addr);
3249 printk("(GFRCR stayed 0)\n",
3250 */
3251 return chip_number;
3252 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003253 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003254 0x40) {
3255 /*
3256 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3257 "%#2x)\n",
3258 chip_number, (unsigned long)base_addr,
3259 base_addr[CyGFRCR<<index]);
3260 */
3261 return chip_number;
3262 }
3263 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003264 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003265 /* It is a CD1400 rev. J or later */
3266 /* Impossible to reach 5ms with this chip.
3267 Changed to 2ms instead (f = 500 Hz). */
3268 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3269 } else {
3270 /* f = 200 Hz */
3271 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3272 }
3273
3274 /*
3275 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3276 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003277 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003278 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003280 return chip_number;
3281} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
3283/*
3284 * ---------------------------------------------------------------------
3285 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3286 * sets global variables and return the number of ISA boards found.
3287 * ---------------------------------------------------------------------
3288 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003289static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290{
3291#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003292 unsigned short cy_isa_irq, nboard;
3293 void __iomem *cy_isa_address;
3294 unsigned short i, j, cy_isa_nchan;
Jiri Slaby02f11752006-12-08 02:39:28 -08003295 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
Jiri Slaby02f11752006-12-08 02:39:28 -08003297 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003300 for (i = 0; i < NR_CARDS; i++) {
3301 if (maddr[i] || i) {
3302 isparam = 1;
3303 cy_isa_addresses[i] = maddr[i];
3304 }
3305 if (!maddr[i])
3306 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308
Jiri Slaby02f11752006-12-08 02:39:28 -08003309 /* scan the address table probing for Cyclom-Y/ISA boards */
3310 for (i = 0; i < NR_ISA_ADDRS; i++) {
3311 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003312 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003313 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
Jiri Slaby02f11752006-12-08 02:39:28 -08003315 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003316 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003317 if (cy_isa_address == NULL) {
3318 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3319 "address\n");
3320 continue;
3321 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003322 cy_isa_nchan = CyPORTS_PER_CHIP *
3323 cyy_init_card(cy_isa_address, 0);
3324 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003325 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003326 continue;
3327 }
Bartlomiej Zolnierkiewicz20904362009-12-09 12:34:14 -08003328
Roel Kluin196b3162009-10-01 15:44:24 -07003329 if (isparam && i < NR_CARDS && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003330 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 else
Jiri Slaby02f11752006-12-08 02:39:28 -08003332 /* find out the board's irq by probing */
3333 cy_isa_irq = detect_isa_irq(cy_isa_address);
3334 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003335 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3336 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003337 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003338 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003339 continue;
3340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
Jiri Slaby02f11752006-12-08 02:39:28 -08003342 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003343 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3344 "more channels are available. Change NR_PORTS "
3345 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003346 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003347 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003348 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003349 }
3350 /* fill the next cy_card structure available */
3351 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003352 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003353 break;
3354 }
3355 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003356 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3357 "more cards can be used. Change NR_CARDS in "
3358 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003359 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003360 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003361 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
Jiri Slaby02f11752006-12-08 02:39:28 -08003364 /* allocate IRQ */
3365 if (request_irq(cy_isa_irq, cyy_interrupt,
Yong Zhang9cfb5c02011-09-22 16:59:15 +08003366 0, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003367 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3368 "could not allocate IRQ#%d.\n",
3369 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003370 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003371 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373
Jiri Slaby02f11752006-12-08 02:39:28 -08003374 /* set cy_card */
3375 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003376 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003377 cy_card[j].irq = (int)cy_isa_irq;
3378 cy_card[j].bus_index = 0;
3379 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003380 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3381 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003382 if (cy_init_card(&cy_card[j])) {
3383 cy_card[j].base_addr = NULL;
3384 free_irq(cy_isa_irq, &cy_card[j]);
3385 iounmap(cy_isa_address);
3386 continue;
3387 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003388 nboard++;
3389
Jiri Slaby21719192007-05-08 00:36:42 -07003390 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3391 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003392 j + 1, (unsigned long)cy_isa_address,
3393 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003394 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3395
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003396 for (j = cy_next_channel;
3397 j < cy_next_channel + cy_isa_nchan; j++)
3398 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003399 cy_next_channel += cy_isa_nchan;
3400 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003401 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003403 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003404#endif /* CONFIG_ISA */
3405} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
Jiri Slaby58936d82007-05-08 00:36:13 -07003407#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003408static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3409{
3410 unsigned int a;
3411
3412 for (a = 0; a < size && *str; a++, str++)
3413 if (*str & 0x80)
3414 return -EINVAL;
3415
3416 for (; a < size; a++, str++)
3417 if (*str)
3418 return -EINVAL;
3419
3420 return 0;
3421}
3422
David Woodhousef61e7612008-05-23 23:57:19 +01003423static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003424 unsigned int size)
3425{
3426 for (; size > 0; size--) {
3427 cy_writel(fpga, *data++);
3428 udelay(10);
3429 }
3430}
3431
3432static void __devinit plx_init(struct pci_dev *pdev, int irq,
3433 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434{
Jiri Slaby02f11752006-12-08 02:39:28 -08003435 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003436 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003437 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003438 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
Jiri Slaby02f11752006-12-08 02:39:28 -08003440 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003441 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003442 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003443 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3444
3445 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3446 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3447 * registers. This will remain here until we find a permanent fix.
3448 */
3449 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3450}
3451
3452static int __devinit __cyz_load_fw(const struct firmware *fw,
3453 const char *name, const u32 mailbox, void __iomem *base,
3454 void __iomem *fpga)
3455{
David Woodhousef61e7612008-05-23 23:57:19 +01003456 const void *ptr = fw->data;
3457 const struct zfile_header *h = ptr;
3458 const struct zfile_config *c, *cs;
3459 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003460 unsigned int a, tmp, len = fw->size;
3461#define BAD_FW KERN_ERR "Bad firmware: "
3462 if (len < sizeof(*h)) {
3463 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3464 return -EINVAL;
3465 }
3466
3467 cs = ptr + h->config_offset;
3468 bs = ptr + h->block_offset;
3469
3470 if ((void *)(cs + h->n_config) > ptr + len ||
3471 (void *)(bs + h->n_blocks) > ptr + len) {
3472 printk(BAD_FW "too short");
3473 return -EINVAL;
3474 }
3475
3476 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3477 cyc_isfwstr(h->date, sizeof(h->date))) {
3478 printk(BAD_FW "bad formatted header string\n");
3479 return -EINVAL;
3480 }
3481
3482 if (strncmp(name, h->name, sizeof(h->name))) {
3483 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3484 return -EINVAL;
3485 }
3486
3487 tmp = 0;
3488 for (c = cs; c < cs + h->n_config; c++) {
3489 for (a = 0; a < c->n_blocks; a++)
3490 if (c->block_list[a] > h->n_blocks) {
3491 printk(BAD_FW "bad block ref number in cfgs\n");
3492 return -EINVAL;
3493 }
3494 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3495 tmp++;
3496 }
3497 if (!tmp) {
3498 printk(BAD_FW "nothing appropriate\n");
3499 return -EINVAL;
3500 }
3501
3502 for (b = bs; b < bs + h->n_blocks; b++)
3503 if (b->file_offset + b->size > len) {
3504 printk(BAD_FW "bad block data offset\n");
3505 return -EINVAL;
3506 }
3507
3508 /* everything is OK, let's seek'n'load it */
3509 for (c = cs; c < cs + h->n_config; c++)
3510 if (c->mailbox == mailbox && c->function == 0)
3511 break;
3512
3513 for (a = 0; a < c->n_blocks; a++) {
3514 b = &bs[c->block_list[a]];
3515 if (b->type == ZBLOCK_FPGA) {
3516 if (fpga != NULL)
3517 cyz_fpga_copy(fpga, ptr + b->file_offset,
3518 b->size);
3519 } else {
3520 if (base != NULL)
3521 memcpy_toio(base + b->ram_offset,
3522 ptr + b->file_offset, b->size);
3523 }
3524 }
3525#undef BAD_FW
3526 return 0;
3527}
3528
3529static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3530 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3531{
3532 const struct firmware *fw;
3533 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3534 struct CUSTOM_REG __iomem *cust = base_addr;
3535 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003536 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003537 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003538 unsigned int i;
3539 int retval;
3540
3541 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3542 if (retval) {
3543 dev_err(&pdev->dev, "can't get firmware\n");
3544 goto err;
3545 }
3546
3547 /* Check whether the firmware is already loaded and running. If
3548 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003549 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003550 u32 cntval = readl(base_addr + 0x190);
3551
3552 udelay(100);
3553 if (cntval != readl(base_addr + 0x190)) {
3554 /* FW counter is working, FW is running */
3555 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3556 "Skipping board.\n");
3557 retval = 0;
3558 goto err_rel;
3559 }
3560 }
3561
3562 /* start boot */
3563 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3564 ~0x00030800UL);
3565
3566 mailbox = readl(&ctl_addr->mail_box_0);
3567
Jiri Slaby2693f482009-06-11 12:31:06 +01003568 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003569 /* stops CPU and set window to beginning of RAM */
3570 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3571 cy_writel(&cust->cpu_stop, 0);
3572 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3573 udelay(100);
3574 }
3575
3576 plx_init(pdev, irq, ctl_addr);
3577
3578 if (mailbox != 0) {
3579 /* load FPGA */
3580 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3581 base_addr);
3582 if (retval)
3583 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003584 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003585 dev_err(&pdev->dev, "fw upload successful, but fw is "
3586 "not loaded\n");
3587 goto err_rel;
3588 }
3589 }
3590
3591 /* stops CPU and set window to beginning of RAM */
3592 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3593 cy_writel(&cust->cpu_stop, 0);
3594 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3595 udelay(100);
3596
3597 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003598 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003599 cy_writeb(tmp, 255);
3600 if (mailbox != 0) {
3601 /* set window to last 512K of RAM */
3602 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003603 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003604 cy_writeb(tmp, 255);
3605 /* set window to beginning of RAM */
3606 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003607 }
3608
3609 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3610 release_firmware(fw);
3611 if (retval)
3612 goto err;
3613
3614 /* finish boot and start boards */
3615 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3616 cy_writel(&cust->cpu_start, 0);
3617 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3618 i = 0;
3619 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3620 msleep(100);
3621 if (status != ZFIRM_ID) {
3622 if (status == ZFIRM_HLT) {
3623 dev_err(&pdev->dev, "you need an external power supply "
3624 "for this number of ports. Firmware halted and "
3625 "board reset.\n");
3626 retval = -EIO;
3627 goto err;
3628 }
3629 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3630 "some more time\n", status);
3631 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3632 i++ < 200)
3633 msleep(100);
3634 if (status != ZFIRM_ID) {
3635 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3636 "Giving up. (fid->signature = 0x%x)\n",
3637 status);
3638 dev_info(&pdev->dev, "*** Warning ***: if you are "
3639 "upgrading the FW, please power cycle the "
3640 "system before loading the new FW to the "
3641 "Cyclades-Z.\n");
3642
Jiri Slaby2693f482009-06-11 12:31:06 +01003643 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003644 plx_init(pdev, irq, ctl_addr);
3645
3646 retval = -EIO;
3647 goto err;
3648 }
3649 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3650 i / 10);
3651 }
3652 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3653
3654 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3655 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3656 base_addr + readl(&fid->zfwctrl_addr));
3657
Jiri Slaby963118e2009-06-11 12:34:27 +01003658 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003659 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003660 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003661
Jiri Slaby963118e2009-06-11 12:34:27 +01003662 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003663 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3664 "check the connection between the Z host card and the "
3665 "serial expanders.\n");
3666
Jiri Slaby2693f482009-06-11 12:31:06 +01003667 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003668 plx_init(pdev, irq, ctl_addr);
3669
3670 dev_info(&pdev->dev, "Null number of ports detected. Board "
3671 "reset.\n");
3672 retval = 0;
3673 goto err;
3674 }
3675
3676 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3677 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3678
3679 /*
3680 Early firmware failed to start looking for commands.
3681 This enables firmware interrupts for those commands.
3682 */
3683 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3684 (1 << 17));
3685 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3686 0x00030800UL);
3687
Jiri Slaby963118e2009-06-11 12:34:27 +01003688 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003689err_rel:
3690 release_firmware(fw);
3691err:
3692 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693}
3694
Jiri Slaby58936d82007-05-08 00:36:13 -07003695static int __devinit cy_pci_probe(struct pci_dev *pdev,
3696 const struct pci_device_id *ent)
3697{
Jiri Slaby31375532007-05-08 00:37:04 -07003698 void __iomem *addr0 = NULL, *addr2 = NULL;
3699 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003700 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003701 unsigned int device_id, nchan = 0, card_no, i;
3702 unsigned char plx_ver;
3703 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003704
3705 retval = pci_enable_device(pdev);
3706 if (retval) {
3707 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003708 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003709 }
3710
3711 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003712 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003713 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3714
Jiri Slaby31375532007-05-08 00:37:04 -07003715#if defined(__alpha__)
3716 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3717 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3718 "addresses on Alpha systems.\n");
3719 retval = -EIO;
3720 goto err_dis;
3721 }
3722#endif
3723 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3724 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3725 "addresses\n");
3726 retval = -EIO;
3727 goto err_dis;
3728 }
3729
3730 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3731 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3732 "it...\n");
3733 pdev->resource[2].flags &= ~IORESOURCE_IO;
3734 }
3735
3736 retval = pci_request_regions(pdev, "cyclades");
3737 if (retval) {
3738 dev_err(&pdev->dev, "failed to reserve resources\n");
3739 goto err_dis;
3740 }
3741
3742 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003743 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3744 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003745 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003746
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003747 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3748 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003749 if (addr0 == NULL) {
3750 dev_err(&pdev->dev, "can't remap ctl region\n");
3751 goto err_reg;
3752 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003753 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3754 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003755 if (addr2 == NULL) {
3756 dev_err(&pdev->dev, "can't remap base region\n");
3757 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003758 }
3759
Jiri Slaby31375532007-05-08 00:37:04 -07003760 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3761 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003762 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3763 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003764 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003765 }
Jiri Slaby31375532007-05-08 00:37:04 -07003766 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3767 struct RUNTIME_9060 __iomem *ctl_addr;
3768
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003769 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3770 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003771 if (addr0 == NULL) {
3772 dev_err(&pdev->dev, "can't remap ctl region\n");
3773 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003774 }
3775
Jiri Slaby31375532007-05-08 00:37:04 -07003776 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003777 cy_writew(&ctl_addr->intr_ctrl_stat,
3778 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003779
Jiri Slaby054f5b02007-07-17 04:05:16 -07003780 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003781
Jiri Slaby101b8152009-06-11 12:30:10 +01003782 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003783
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003784 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3785 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003786 if (addr2 == NULL) {
3787 dev_err(&pdev->dev, "can't remap base region\n");
3788 goto err_unmap;
3789 }
3790
3791 if (mailbox == ZE_V1) {
3792 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003793 } else {
3794 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003795#ifdef CY_PCI_DEBUG
3796 if (mailbox == ZO_V1) {
3797 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3798 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3799 "id %lx, ver %lx\n", (ulong)(0xff &
3800 readl(&((struct CUSTOM_REG *)addr2)->
3801 fpga_id)), (ulong)(0xff &
3802 readl(&((struct CUSTOM_REG *)addr2)->
3803 fpga_version)));
3804 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3805 } else {
3806 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3807 "Cyclades-Z board. FPGA not loaded\n");
3808 }
3809#endif
3810 /* The following clears the firmware id word. This
3811 ensures that the driver will not attempt to talk to
3812 the board until it has been properly initialized.
3813 */
3814 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3815 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003816 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003817
3818 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003819 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003820 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003821 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003822 }
3823
3824 if ((cy_next_channel + nchan) > NR_PORTS) {
3825 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3826 "channels are available. Change NR_PORTS in "
3827 "cyclades.c and recompile kernel.\n");
3828 goto err_unmap;
3829 }
3830 /* fill the next cy_card structure available */
3831 for (card_no = 0; card_no < NR_CARDS; card_no++) {
3832 if (cy_card[card_no].base_addr == NULL)
3833 break;
3834 }
3835 if (card_no == NR_CARDS) { /* no more cy_cards available */
3836 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3837 "more cards can be used. Change NR_CARDS in "
3838 "cyclades.c and recompile kernel.\n");
3839 goto err_unmap;
3840 }
3841
3842 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3843 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003844 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07003845 retval = request_irq(irq, cyy_interrupt,
3846 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07003847 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07003848 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003849 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003850 }
Jiri Slaby963118e2009-06-11 12:34:27 +01003851 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07003852 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003853 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3854 struct ZFW_CTRL __iomem *zfw_ctrl;
3855
3856 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3857
Jiri Slaby101b8152009-06-11 12:30:10 +01003858 cy_card[card_no].hw_ver = mailbox;
3859 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003860 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07003861#ifdef CONFIG_CYZ_INTR
3862 /* allocate IRQ only if board has an IRQ */
3863 if (irq != 0 && irq != 255) {
3864 retval = request_irq(irq, cyz_interrupt,
3865 IRQF_SHARED, "Cyclades-Z",
3866 &cy_card[card_no]);
3867 if (retval) {
3868 dev_err(&pdev->dev, "could not allocate IRQ\n");
3869 goto err_unmap;
3870 }
3871 }
3872#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07003873 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003874
Jiri Slaby31375532007-05-08 00:37:04 -07003875 /* set cy_card */
3876 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003877 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07003878 cy_card[card_no].irq = irq;
3879 cy_card[card_no].bus_index = 1;
3880 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003881 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003882 retval = cy_init_card(&cy_card[card_no]);
3883 if (retval)
3884 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07003885
Jiri Slaby31375532007-05-08 00:37:04 -07003886 pci_set_drvdata(pdev, &cy_card[card_no]);
3887
3888 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3889 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003890 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07003891 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07003892 switch (plx_ver) {
3893 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07003894 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07003895 break;
3896
3897 case PLX_9060:
3898 case PLX_9080:
3899 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003900 {
3901 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3902 plx_init(pdev, irq, ctl_addr);
3903 cy_writew(&ctl_addr->intr_ctrl_stat,
3904 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07003905 break;
3906 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01003907 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003908 }
3909
Jiri Slaby31375532007-05-08 00:37:04 -07003910 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3911 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
3912 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
3913 tty_register_device(cy_serial_driver, i, &pdev->dev);
3914 cy_next_channel += nchan;
3915
Jiri Slaby58936d82007-05-08 00:36:13 -07003916 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07003917err_null:
3918 cy_card[card_no].base_addr = NULL;
3919 free_irq(irq, &cy_card[card_no]);
3920err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003921 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003922 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003923 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07003924err_reg:
3925 pci_release_regions(pdev);
3926err_dis:
3927 pci_disable_device(pdev);
3928err:
3929 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07003930}
Jiri Slaby58936d82007-05-08 00:36:13 -07003931
Jiri Slaby6747cd92007-05-08 00:36:34 -07003932static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933{
Jiri Slaby38d09092007-05-08 00:36:10 -07003934 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07003935 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07003936
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003937 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01003938 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07003939 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01003940 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003941 else
3942#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003943 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003944#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01003945 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3946 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3947 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003948
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003949 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01003950 if (cinfo->ctl_addr.p9050)
3951 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07003952 if (cinfo->irq
3953#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003954 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07003955#endif /* CONFIG_CYZ_INTR */
3956 )
3957 free_irq(cinfo->irq, cinfo);
3958 pci_release_regions(pdev);
3959
3960 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003961 for (i = cinfo->first_line; i < cinfo->first_line +
3962 cinfo->nports; i++)
3963 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07003964 cinfo->nports = 0;
3965 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07003966}
3967
Jiri Slaby6747cd92007-05-08 00:36:34 -07003968static struct pci_driver cy_pci_driver = {
3969 .name = "cyclades",
3970 .id_table = cy_pci_dev_id,
3971 .probe = cy_pci_probe,
3972 .remove = __devexit_p(cy_pci_remove)
3973};
3974#endif
3975
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003976static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977{
Jiri Slaby02f11752006-12-08 02:39:28 -08003978 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07003979 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08003980 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003982 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08003983 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
Jiri Slaby02f11752006-12-08 02:39:28 -08003985 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07003986 for (i = 0; i < NR_CARDS; i++)
3987 for (j = 0; j < cy_card[i].nports; j++) {
3988 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08003989
Jiri Slabyd13549f2009-09-19 13:13:12 -07003990 if (info->port.count) {
3991 /* XXX is the ldisc num worth this? */
3992 struct tty_struct *tty;
3993 struct tty_ldisc *ld;
3994 int num = 0;
3995 tty = tty_port_tty_get(&info->port);
3996 if (tty) {
3997 ld = tty_ldisc_ref(tty);
3998 if (ld) {
3999 num = ld->ops->num;
4000 tty_ldisc_deref(ld);
4001 }
4002 tty_kref_put(tty);
4003 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004004 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004005 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004006 (cur_jifs - info->idle_stats.in_use) /
4007 HZ, info->idle_stats.xmit_bytes,
4008 (cur_jifs - info->idle_stats.xmit_idle)/
4009 HZ, info->idle_stats.recv_bytes,
4010 (cur_jifs - info->idle_stats.recv_idle)/
4011 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004012 num);
4013 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004014 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004015 "%10lu %8lu %9lu %6ld\n",
4016 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004017 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004018 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019}
4020
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004021static int cyclades_proc_open(struct inode *inode, struct file *file)
4022{
4023 return single_open(file, cyclades_proc_show, NULL);
4024}
4025
4026static const struct file_operations cyclades_proc_fops = {
4027 .owner = THIS_MODULE,
4028 .open = cyclades_proc_open,
4029 .read = seq_read,
4030 .llseek = seq_lseek,
4031 .release = single_release,
4032};
4033
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034/* The serial driver boot-time initialization code!
4035 Hardware I/O ports are mapped to character special devices on a
4036 first found, first allocated manner. That is, this code searches
4037 for Cyclom cards in the system. As each is found, it is probed
4038 to discover how many chips (and thus how many ports) are present.
4039 These ports are mapped to the tty ports 32 and upward in monotonic
4040 fashion. If an 8-port card is replaced with a 16-port card, the
4041 port mapping on a following card will shift.
4042
4043 This approach is different from what is used in the other serial
4044 device driver because the Cyclom is more properly a multiplexer,
4045 not just an aggregation of serial ports on one card.
4046
4047 If there are more cards with more ports than have been
4048 statically allocated above, a warning is printed and the
4049 extra ports are ignored.
4050 */
4051
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004052static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004053 .open = cy_open,
4054 .close = cy_close,
4055 .write = cy_write,
4056 .put_char = cy_put_char,
4057 .flush_chars = cy_flush_chars,
4058 .write_room = cy_write_room,
4059 .chars_in_buffer = cy_chars_in_buffer,
4060 .flush_buffer = cy_flush_buffer,
4061 .ioctl = cy_ioctl,
4062 .throttle = cy_throttle,
4063 .unthrottle = cy_unthrottle,
4064 .set_termios = cy_set_termios,
4065 .stop = cy_stop,
4066 .start = cy_start,
4067 .hangup = cy_hangup,
4068 .break_ctl = cy_break,
4069 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004070 .tiocmget = cy_tiocmget,
4071 .tiocmset = cy_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +01004072 .get_icount = cy_get_icount,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004073 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074};
4075
Jiri Slaby02f11752006-12-08 02:39:28 -08004076static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077{
Jiri Slabydd025c02007-05-08 00:37:02 -07004078 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004079 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
Jiri Slaby02f11752006-12-08 02:39:28 -08004081 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4082 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004083 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004084
Michal Marek64a14b52011-04-01 12:41:20 +02004085 printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
Jiri Slaby02f11752006-12-08 02:39:28 -08004087 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
Jiri Slaby02f11752006-12-08 02:39:28 -08004089 cy_serial_driver->driver_name = "cyclades";
4090 cy_serial_driver->name = "ttyC";
4091 cy_serial_driver->major = CYCLADES_MAJOR;
4092 cy_serial_driver->minor_start = 0;
4093 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4094 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4095 cy_serial_driver->init_termios = tty_std_termios;
4096 cy_serial_driver->init_termios.c_cflag =
4097 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004098 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004099 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004101 retval = tty_register_driver(cy_serial_driver);
4102 if (retval) {
4103 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4104 goto err_frtty;
4105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Jiri Slaby02f11752006-12-08 02:39:28 -08004107 /* the code below is responsible to find the boards. Each different
4108 type of board has its own detection routine. If a board is found,
4109 the next cy_card structure available is set by the detection
4110 routine. These functions are responsible for checking the
4111 availability of cy_card and cy_port data structures and updating
4112 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
Jiri Slaby02f11752006-12-08 02:39:28 -08004114 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004115 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116
Jiri Slaby6747cd92007-05-08 00:36:34 -07004117#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004118 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004119 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004120 if (retval && !nboards) {
4121 tty_unregister_driver(cy_serial_driver);
4122 goto err_frtty;
4123 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004124#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004125
4126 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004127err_frtty:
4128 put_tty_driver(cy_serial_driver);
4129err:
4130 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004131} /* cy_init */
4132
4133static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134{
Jiri Slabydd025c02007-05-08 00:37:02 -07004135 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004136 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004139 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140#endif /* CONFIG_CYZ_INTR */
4141
Alan Cox15ed6cc2008-04-30 00:53:55 -07004142 e1 = tty_unregister_driver(cy_serial_driver);
4143 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004144 printk(KERN_ERR "failed to unregister Cyclades serial "
4145 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
Jiri Slaby6747cd92007-05-08 00:36:34 -07004147#ifdef CONFIG_PCI
4148 pci_unregister_driver(&cy_pci_driver);
4149#endif
4150
Jiri Slaby02f11752006-12-08 02:39:28 -08004151 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004152 card = &cy_card[i];
4153 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004154 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004155 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4156 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004157 if (card->ctl_addr.p9050)
4158 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004159 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004161 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004163 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004164 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004165 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004166 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004167 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004168 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004169 }
4170 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004171
4172 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173} /* cy_cleanup_module */
4174
4175module_init(cy_init);
4176module_exit(cy_cleanup_module);
4177
4178MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004179MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad72009-04-06 17:33:04 +01004180MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00004181MODULE_FIRMWARE("cyzfirm.bin");