blob: e1637ad9390e1c0ade1736cc9a5fac414f9ed4e9 [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/*
6 * linux/drivers/char/cyclades.c
7 *
8 * This file contains the driver for the Cyclades async multiport
9 * serial boards.
10 *
11 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
12 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Jiri Slabyebdb5132009-09-19 13:13:14 -070014 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
16 * Much of the design and some of the code came from serial.c
17 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
18 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
19 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070020 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 */
23
Jiri Slabyebdb5132009-09-19 13:13:14 -070024#define CY_VERSION "2.6"
Jiri Slaby096dcfc2006-12-08 02:39:30 -080025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026/* If you need to install more boards than NR_CARDS, change the constant
27 in the definition below. No other change is necessary to support up to
28 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
29
Jiri Slaby02f11752006-12-08 02:39:28 -080030#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32/*
33 If the total number of ports is larger than NR_PORTS, change this
34 constant in the definition below. No other change is necessary to
35 support more boards/ports. */
36
Jiri Slaby02f11752006-12-08 02:39:28 -080037#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define ZO_V1 0
40#define ZO_V2 1
41#define ZE_V1 2
42
43#define SERIAL_PARANOIA_CHECK
44#undef CY_DEBUG_OPEN
45#undef CY_DEBUG_THROTTLE
46#undef CY_DEBUG_OTHER
47#undef CY_DEBUG_IO
48#undef CY_DEBUG_COUNT
49#undef CY_DEBUG_DTR
50#undef CY_DEBUG_WAIT_UNTIL_SENT
51#undef CY_DEBUG_INTERRUPTS
52#undef CY_16Y_HACK
53#undef CY_ENABLE_MONITORING
54#undef CY_PCI_DEBUG
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/*
Alan Cox15ed6cc2008-04-30 00:53:55 -070057 * Include section
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <linux/module.h>
60#include <linux/errno.h>
61#include <linux/signal.h>
62#include <linux/sched.h>
63#include <linux/timer.h>
64#include <linux/interrupt.h>
65#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -080066#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/serial.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040068#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include <linux/major.h>
70#include <linux/string.h>
71#include <linux/fcntl.h>
72#include <linux/ptrace.h>
73#include <linux/cyclades.h>
74#include <linux/mm.h>
75#include <linux/ioport.h>
76#include <linux/init.h>
77#include <linux/delay.h>
78#include <linux/spinlock.h>
79#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -070080#include <linux/firmware.h>
Scott James Remnant9f56fad72009-04-06 17:33:04 +010081#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Alan Cox15ed6cc2008-04-30 00:53:55 -070083#include <linux/io.h>
Alan Cox15ed6cc2008-04-30 00:53:55 -070084#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#include <linux/kernel.h>
87#include <linux/pci.h>
88
89#include <linux/stat.h>
90#include <linux/proc_fs.h>
Alexey Dobriyan444697d2009-03-31 15:19:15 -070091#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Jiri Slaby02f11752006-12-08 02:39:28 -080093static void cy_throttle(struct tty_struct *tty);
94static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifndef SERIAL_XMIT_SIZE
97#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
98#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100#define STD_COM_FLAGS (0)
101
Jiri Slaby054f5b02007-07-17 04:05:16 -0700102/* firmware stuff */
103#define ZL_MAX_BLOCKS 16
104#define DRIVER_VERSION 0x02010203
105#define RAM_SIZE 0x80000
106
Jiri Slaby054f5b02007-07-17 04:05:16 -0700107enum zblock_type {
108 ZBLOCK_PRG = 0,
109 ZBLOCK_FPGA = 1
110};
111
112struct zfile_header {
113 char name[64];
114 char date[32];
115 char aux[32];
116 u32 n_config;
117 u32 config_offset;
118 u32 n_blocks;
119 u32 block_offset;
120 u32 reserved[9];
121} __attribute__ ((packed));
122
123struct zfile_config {
124 char name[64];
125 u32 mailbox;
126 u32 function;
127 u32 n_blocks;
128 u32 block_list[ZL_MAX_BLOCKS];
129} __attribute__ ((packed));
130
131struct zfile_block {
132 u32 type;
133 u32 file_offset;
134 u32 ram_offset;
135 u32 size;
136} __attribute__ ((packed));
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static struct tty_driver *cy_serial_driver;
139
140#ifdef CONFIG_ISA
141/* This is the address lookup table. The driver will probe for
142 Cyclom-Y/ISA boards at all addresses in here. If you want the
143 driver to probe addresses at a different address, add it to
144 this table. If the driver is probing some other board and
145 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146*/
147
148static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800149 0xD0000,
150 0xD2000,
151 0xD4000,
152 0xD6000,
153 0xD8000,
154 0xDA000,
155 0xDC000,
156 0xDE000,
157 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158};
Jiri Slaby02f11752006-12-08 02:39:28 -0800159
Tobias Klauserfe971072006-01-09 20:54:02 -0800160#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162#ifdef MODULE
Jiri Slaby3046d502007-05-08 00:36:46 -0700163static long maddr[NR_CARDS];
164static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166module_param_array(maddr, long, NULL, 0);
167module_param_array(irq, int, NULL, 0);
168#endif
169
Jiri Slaby02f11752006-12-08 02:39:28 -0800170#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172/* This is the per-card data structure containing address, irq, number of
173 channels, etc. This driver supports a maximum of NR_CARDS cards.
174*/
175static struct cyclades_card cy_card[NR_CARDS];
176
Jiri Slaby02f11752006-12-08 02:39:28 -0800177static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 * This is used to look up the divisor speeds and the timeouts
181 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100182 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
184 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
185 * HI VHI
186 * 20
187 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700188static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800189 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
190 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
191 230400, 0
192};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Jiri Slabyebdb5132009-09-19 13:13:14 -0700194static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800195 /* value => 00 01 02 03 04 */
196 /* divide by 8 32 128 512 2048 */
197 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
198 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
199};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Jiri Slabyebdb5132009-09-19 13:13:14 -0700201static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800202 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
203 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
204};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Jiri Slabyebdb5132009-09-19 13:13:14 -0700206static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800207 /* value => 00 01 02 03 04 */
208 /* divide by 8 32 128 512 2048 */
209 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
210 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00
212};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Jiri Slabyebdb5132009-09-19 13:13:14 -0700214static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800215 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
216 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
217 0x21
218};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Jiri Slabyebdb5132009-09-19 13:13:14 -0700220static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800221 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
222 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
223 0x07
224};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226/*
227 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700228 * The cyclades_port structure member rflow and the vector rflow_thr
229 * allows us to take advantage of a special feature in the CD1400 to avoid
230 * data loss even when the system interrupt latency is too high. These flags
231 * are to be used only with very special applications. Setting these flags
232 * requires the use of a special cable (DTR and RTS reversed). In the new
233 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 * cables.
235 */
236
Jiri Slabyebdb5132009-09-19 13:13:14 -0700237static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
240 0x0a
241};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243/* The Cyclom-Ye has placed the sequential chips in non-sequential
244 * address order. This look-up table overcomes that problem.
245 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700246static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800247 0x0400,
248 0x0800,
249 0x0C00,
250 0x0200,
251 0x0600,
252 0x0A00,
253 0x0E00
254};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256/* PCI related definitions */
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700259static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700260 /* PCI < 1Mb */
261 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
262 /* PCI > 1Mb */
263 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
264 /* 4Y PCI < 1Mb */
265 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
266 /* 4Y PCI > 1Mb */
267 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
268 /* 8Y PCI < 1Mb */
269 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
270 /* 8Y PCI > 1Mb */
271 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
272 /* Z PCI < 1Mb */
273 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
274 /* Z PCI > 1Mb */
275 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800276 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800277};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800278MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#endif
280
281static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700282static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700283static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284#ifdef CONFIG_ISA
285static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800286#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288#ifndef CONFIG_CYZ_INTR
289static void cyz_poll(unsigned long);
290
291/* The Cyclades-Z polling cycle is defined by this variable */
292static long cyz_polling_cycle = CZ_DEF_POLL;
293
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700294static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Jiri Slaby02f11752006-12-08 02:39:28 -0800296#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297static void cyz_rx_restart(unsigned long);
298static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800299#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Jiri Slaby2693f482009-06-11 12:31:06 +0100301static inline bool cy_is_Z(struct cyclades_card *card)
302{
303 return card->num_chips == (unsigned int)-1;
304}
305
306static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
307{
308 return readl(&ctl_addr->init_ctrl) & (1 << 17);
309}
310
311static inline bool cyz_fpga_loaded(struct cyclades_card *card)
312{
313 return __cyz_fpga_loaded(card->ctl_addr.p9060);
314}
315
316static inline bool cyz_is_loaded(struct cyclades_card *card)
317{
318 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
319
320 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
321 readl(&fw_id->signature) == ZFIRM_ID;
322}
323
Jiri Slaby02f11752006-12-08 02:39:28 -0800324static inline int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700325 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800328 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700329 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
330 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800331 return 1;
332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jiri Slaby02f11752006-12-08 02:39:28 -0800334 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700335 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
336 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800337 return 1;
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800340 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700341}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343/***********************************************************/
344/********* Start of block of Cyclom-Y specific code ********/
345
346/* This routine waits up to 1000 micro-seconds for the previous
347 command to the Cirrus chip to complete and then issues the
348 new command. An error is returned if the previous command
349 didn't finish within the time limit.
350
351 This function is only called from inside spinlock-protected code.
352 */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700353static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Jiri Slabyad39c302007-05-08 00:35:49 -0700355 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Jiri Slaby02f11752006-12-08 02:39:28 -0800357 /* Check to see that the previous command has completed */
358 for (i = 0; i < 100; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700359 if (readb(base_addr + (CyCCR << index)) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800360 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800361 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800363 /* if the CCR never cleared, the previous command
364 didn't finish within the "reasonable time" */
365 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800366 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Jiri Slaby02f11752006-12-08 02:39:28 -0800368 /* Issue the new command */
369 cy_writeb(base_addr + (CyCCR << index), cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800371 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800372} /* cyy_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374#ifdef CONFIG_ISA
375/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700376static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
Jiri Slaby02f11752006-12-08 02:39:28 -0800378 int irq;
379 unsigned long irqs, flags;
380 int save_xir, save_car;
381 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Jiri Slaby02f11752006-12-08 02:39:28 -0800383 /* forget possible initially masked and pending IRQ */
384 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Jiri Slaby02f11752006-12-08 02:39:28 -0800386 /* Clear interrupts on the board first */
387 cy_writeb(address + (Cy_ClrIntr << index), 0);
388 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Jiri Slaby02f11752006-12-08 02:39:28 -0800390 irqs = probe_irq_on();
391 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700392 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Jiri Slaby02f11752006-12-08 02:39:28 -0800394 /* Enable the Tx interrupts on the CD1400 */
395 local_irq_save(flags);
396 cy_writeb(address + (CyCAR << index), 0);
397 cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Jiri Slaby02f11752006-12-08 02:39:28 -0800399 cy_writeb(address + (CyCAR << index), 0);
400 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700401 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800402 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Jiri Slaby02f11752006-12-08 02:39:28 -0800404 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700405 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Jiri Slaby02f11752006-12-08 02:39:28 -0800407 /* Check which interrupt is in use */
408 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Jiri Slaby02f11752006-12-08 02:39:28 -0800410 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700411 save_xir = (u_char) readb(address + (CyTIR << index));
412 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800413 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
414 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700415 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800416 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
417 cy_writeb(address + (CyCAR << index), (save_car));
418 cy_writeb(address + (Cy_ClrIntr << index), 0);
419 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Jiri Slaby02f11752006-12-08 02:39:28 -0800421 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
Jiri Slaby02f11752006-12-08 02:39:28 -0800423#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Jiri Slabyce97a092007-10-18 03:06:21 -0700425static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
426 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800427{
428 struct cyclades_port *info;
429 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700430 int len, index = cinfo->bus_index;
431 u8 save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800432
Jiri Slabye9410272006-12-08 02:39:28 -0800433#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700434 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800435#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700436 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700437 save_xir = readb(base_addr + (CyRIR << index));
438 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700439 info = &cinfo->ports[channel + chip * 4];
440 save_car = readb(base_addr + (CyCAR << index));
441 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800442
Jiri Slabyd13549f2009-09-19 13:13:12 -0700443 tty = tty_port_tty_get(&info->port);
Jiri Slabyce97a092007-10-18 03:06:21 -0700444 /* if there is nowhere to put the data, discard it */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700445 if (tty == NULL) {
Jiri Slaby65f76a82007-10-18 03:06:22 -0700446 if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
447 CyIVRRxEx) { /* exception */
Jiri Slabyce97a092007-10-18 03:06:21 -0700448 data = readb(base_addr + (CyRDSR << index));
449 } else { /* normal character reception */
450 char_count = readb(base_addr + (CyRDCR << index));
451 while (char_count--)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700452 data = readb(base_addr + (CyRDSR << index));
Jiri Slabyce97a092007-10-18 03:06:21 -0700453 }
454 goto end;
455 }
456 /* there is an open port for this data */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700457 if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
458 CyIVRRxEx) { /* exception */
Jiri Slabyce97a092007-10-18 03:06:21 -0700459 data = readb(base_addr + (CyRDSR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800460
Jiri Slabyce97a092007-10-18 03:06:21 -0700461 /* For statistics only */
462 if (data & CyBREAK)
463 info->icount.brk++;
464 else if (data & CyFRAME)
465 info->icount.frame++;
466 else if (data & CyPARITY)
467 info->icount.parity++;
468 else if (data & CyOVERRUN)
469 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800470
Jiri Slabyce97a092007-10-18 03:06:21 -0700471 if (data & info->ignore_status_mask) {
472 info->icount.rx++;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700473 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700474 return;
475 }
476 if (tty_buffer_request_room(tty, 1)) {
477 if (data & info->read_status_mask) {
478 if (data & CyBREAK) {
479 tty_insert_flip_char(tty,
480 readb(base_addr + (CyRDSR <<
481 index)), TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800482 info->icount.rx++;
Alan Cox77451e52008-07-16 21:57:02 +0100483 if (info->port.flags & ASYNC_SAK)
Jiri Slabyce97a092007-10-18 03:06:21 -0700484 do_SAK(tty);
485 } else if (data & CyFRAME) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700486 tty_insert_flip_char(tty,
Jiri Slabyce97a092007-10-18 03:06:21 -0700487 readb(base_addr + (CyRDSR <<
488 index)), TTY_FRAME);
489 info->icount.rx++;
490 info->idle_stats.frame_errs++;
491 } else if (data & CyPARITY) {
492 /* Pieces of seven... */
493 tty_insert_flip_char(tty,
494 readb(base_addr + (CyRDSR <<
495 index)), TTY_PARITY);
496 info->icount.rx++;
497 info->idle_stats.parity_errs++;
498 } else if (data & CyOVERRUN) {
499 tty_insert_flip_char(tty, 0,
500 TTY_OVERRUN);
501 info->icount.rx++;
502 /* If the flip buffer itself is
503 overflowing, we still lose
504 the next incoming character.
505 */
506 tty_insert_flip_char(tty,
507 readb(base_addr + (CyRDSR <<
508 index)), TTY_FRAME);
509 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800510 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700511 /* These two conditions may imply */
512 /* a normal read should be done. */
513 /* } else if(data & CyTIMEOUT) { */
514 /* } else if(data & CySPECHAR) { */
515 } else {
516 tty_insert_flip_char(tty, 0,
517 TTY_NORMAL);
518 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800519 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700520 } else {
521 tty_insert_flip_char(tty, 0, TTY_NORMAL);
522 info->icount.rx++;
523 }
524 } else {
525 /* there was a software buffer overrun and nothing
526 * could be done about it!!! */
527 info->icount.buf_overrun++;
528 info->idle_stats.overruns++;
529 }
530 } else { /* normal character reception */
531 /* load # chars available from the chip */
532 char_count = readb(base_addr + (CyRDCR << index));
Jiri Slabye9410272006-12-08 02:39:28 -0800533
534#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700535 ++info->mon.int_count;
536 info->mon.char_count += char_count;
537 if (char_count > info->mon.char_max)
538 info->mon.char_max = char_count;
539 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800540#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700541 len = tty_buffer_request_room(tty, char_count);
542 while (len--) {
543 data = readb(base_addr + (CyRDSR << index));
544 tty_insert_flip_char(tty, data, TTY_NORMAL);
545 info->idle_stats.recv_bytes++;
546 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800547#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700548 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800549#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800550 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700551 info->idle_stats.recv_idle = jiffies;
552 }
553 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700554 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700555end:
556 /* end of service */
557 cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
558 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700559}
560
Jiri Slaby65f76a82007-10-18 03:06:22 -0700561static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700562 void __iomem *base_addr)
563{
564 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700565 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700566 int char_count, index = cinfo->bus_index;
567 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700568
569 /* Since we only get here when the transmit buffer
570 is empty, we know we can always stuff a dozen
571 characters. */
572#ifdef CY_DEBUG_INTERRUPTS
573 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
574#endif
575
576 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700577 save_xir = readb(base_addr + (CyTIR << index));
578 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700579 save_car = readb(base_addr + (CyCAR << index));
580 cy_writeb(base_addr + (CyCAR << index), save_xir);
581
582 /* validate the port# (as configured and open) */
583 if (channel + chip * 4 >= cinfo->nports) {
584 cy_writeb(base_addr + (CySRER << index),
585 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
586 goto end;
587 }
588 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700589 tty = tty_port_tty_get(&info->port);
590 if (tty == NULL) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700591 cy_writeb(base_addr + (CySRER << index),
592 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
593 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800594 }
595
Jiri Slabyce97a092007-10-18 03:06:21 -0700596 /* load the on-chip space for outbound data */
597 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800598
Jiri Slabyce97a092007-10-18 03:06:21 -0700599 if (info->x_char) { /* send special char */
600 outch = info->x_char;
601 cy_writeb(base_addr + (CyTDR << index), outch);
602 char_count--;
603 info->icount.tx++;
604 info->x_char = 0;
605 }
Jiri Slabye9410272006-12-08 02:39:28 -0800606
Jiri Slabyce97a092007-10-18 03:06:21 -0700607 if (info->breakon || info->breakoff) {
608 if (info->breakon) {
609 cy_writeb(base_addr + (CyTDR << index), 0);
610 cy_writeb(base_addr + (CyTDR << index), 0x81);
611 info->breakon = 0;
612 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800613 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700614 if (info->breakoff) {
615 cy_writeb(base_addr + (CyTDR << index), 0);
616 cy_writeb(base_addr + (CyTDR << index), 0x83);
617 info->breakoff = 0;
618 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800619 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700620 }
Jiri Slabye9410272006-12-08 02:39:28 -0800621
Jiri Slabyce97a092007-10-18 03:06:21 -0700622 while (char_count-- > 0) {
623 if (!info->xmit_cnt) {
624 if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
625 cy_writeb(base_addr + (CySRER << index),
626 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800627 ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700628 } else {
629 cy_writeb(base_addr + (CySRER << index),
630 (readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800631 ~CyTxRdy) | CyTxMpty);
Jiri Slaby02f11752006-12-08 02:39:28 -0800632 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700633 goto done;
634 }
Alan Cox77451e52008-07-16 21:57:02 +0100635 if (info->port.xmit_buf == NULL) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700636 cy_writeb(base_addr + (CySRER << index),
637 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800638 ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700639 goto done;
640 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700641 if (tty->stopped || tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700642 cy_writeb(base_addr + (CySRER << index),
643 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800644 ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700645 goto done;
646 }
647 /* Because the Embedded Transmit Commands have been enabled,
648 * we must check to see if the escape character, NULL, is being
649 * sent. If it is, we must ensure that there is room for it to
650 * be doubled in the output stream. Therefore we no longer
651 * advance the pointer when the character is fetched, but
652 * rather wait until after the check for a NULL output
653 * character. This is necessary because there may not be room
654 * for the two chars needed to send a NULL.)
655 */
Alan Cox77451e52008-07-16 21:57:02 +0100656 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700657 if (outch) {
658 info->xmit_cnt--;
659 info->xmit_tail = (info->xmit_tail + 1) &
660 (SERIAL_XMIT_SIZE - 1);
661 cy_writeb(base_addr + (CyTDR << index), outch);
662 info->icount.tx++;
663 } else {
664 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800665 info->xmit_cnt--;
666 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700667 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800668 cy_writeb(base_addr + (CyTDR << index), outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700669 cy_writeb(base_addr + (CyTDR << index), 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800670 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700671 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800672 }
673 }
Jiri Slabye9410272006-12-08 02:39:28 -0800674 }
675
Jiri Slabyce97a092007-10-18 03:06:21 -0700676done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700677 tty_wakeup(tty);
678 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700679end:
680 /* end of service */
681 cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
682 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700683}
Jiri Slabye9410272006-12-08 02:39:28 -0800684
Jiri Slabyce97a092007-10-18 03:06:21 -0700685static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
686 void __iomem *base_addr)
687{
688 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700689 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700690 int index = cinfo->bus_index;
691 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800692
Jiri Slabyce97a092007-10-18 03:06:21 -0700693 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700694 save_xir = readb(base_addr + (CyMIR << index));
695 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700696 info = &cinfo->ports[channel + chip * 4];
697 save_car = readb(base_addr + (CyCAR << index));
698 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800699
Jiri Slabyce97a092007-10-18 03:06:21 -0700700 mdm_change = readb(base_addr + (CyMISR << index));
701 mdm_status = readb(base_addr + (CyMSVR1 << index));
Jiri Slabye9410272006-12-08 02:39:28 -0800702
Jiri Slabyd13549f2009-09-19 13:13:12 -0700703 tty = tty_port_tty_get(&info->port);
704 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700705 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800706
Jiri Slabyce97a092007-10-18 03:06:21 -0700707 if (mdm_change & CyANY_DELTA) {
708 /* For statistics only */
709 if (mdm_change & CyDCD)
710 info->icount.dcd++;
711 if (mdm_change & CyCTS)
712 info->icount.cts++;
713 if (mdm_change & CyDSR)
714 info->icount.dsr++;
715 if (mdm_change & CyRI)
716 info->icount.rng++;
717
718 wake_up_interruptible(&info->delta_msr_wait);
719 }
720
Alan Cox77451e52008-07-16 21:57:02 +0100721 if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700722 if (mdm_status & CyDCD)
723 wake_up_interruptible(&info->port.open_wait);
724 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700725 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800726 }
Alan Cox77451e52008-07-16 21:57:02 +0100727 if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700728 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700729 if (mdm_status & CyCTS) {
730 /* cy_start isn't used
731 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700732 tty->hw_stopped = 0;
Jiri Slabyce97a092007-10-18 03:06:21 -0700733 cy_writeb(base_addr + (CySRER << index),
734 readb(base_addr + (CySRER << index)) |
735 CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700736 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700737 }
738 } else {
739 if (!(mdm_status & CyCTS)) {
740 /* cy_stop isn't used
741 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700742 tty->hw_stopped = 1;
Jiri Slabyce97a092007-10-18 03:06:21 -0700743 cy_writeb(base_addr + (CySRER << index),
744 readb(base_addr + (CySRER << index)) &
745 ~CyTxRdy);
746 }
747 }
748 }
749/* if (mdm_change & CyDSR) {
750 }
751 if (mdm_change & CyRI) {
752 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700753 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700754end:
755 /* end of service */
756 cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
757 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760/* The real interrupt service routine is called
761 whenever the card wants its hand held--chars
762 received, out buffer empty, modem change, etc.
763 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800764static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Jiri Slaby02f11752006-12-08 02:39:28 -0800766 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700767 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800768 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700769 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800770 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800771
Jiri Slabyf7429032007-05-08 00:36:59 -0700772 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700774 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
775 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800777 return IRQ_NONE; /* spurious interrupt */
778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Jiri Slaby02f11752006-12-08 02:39:28 -0800780 card_base_addr = cinfo->base_addr;
781 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700783 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
784 if (unlikely(card_base_addr == NULL))
785 return IRQ_HANDLED;
786
Jiri Slaby02f11752006-12-08 02:39:28 -0800787 /* This loop checks all chips in the card. Make a note whenever
788 _any_ chip had some work to do, as this is considered an
789 indication that there will be more to do. Only when no chip
790 has any work does this outermost loop exit.
791 */
792 do {
793 had_work = 0;
794 for (chip = 0; chip < cinfo->num_chips; chip++) {
795 base_addr = cinfo->base_addr +
796 (cy_chip_offset[chip] << index);
797 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700798 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800799 (CySVRR << index))) != 0x00) {
800 had_work++;
801 /* The purpose of the following test is to ensure that
802 no chip can monopolize the driver. This forces the
803 chips to be checked in a round-robin fashion (after
804 draining each of a bunch (1000) of characters).
805 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700806 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800807 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700808 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700809 if (status & CySRReceive) /* rx intr */
810 cyy_chip_rx(cinfo, chip, base_addr);
811 if (status & CySRTransmit) /* tx intr */
812 cyy_chip_tx(cinfo, chip, base_addr);
813 if (status & CySRModem) /* modem intr */
814 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700815 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800816 }
817 }
818 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Jiri Slaby02f11752006-12-08 02:39:28 -0800820 /* clear interrupts */
821 spin_lock(&cinfo->card_lock);
822 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
823 /* Cy_ClrIntr is 0x1800 */
824 spin_unlock(&cinfo->card_lock);
825 return IRQ_HANDLED;
826} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Jiri Slaby4d768202009-09-19 13:13:15 -0700828static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
829 unsigned int clear)
830{
831 struct cyclades_card *card = info->card;
832 void __iomem *base_addr;
833 int chip, channel, index;
834
835 channel = info->line - card->first_line;
836 chip = channel >> 2;
837 channel &= 0x03;
838 index = card->bus_index;
839 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
840
841 if (set & TIOCM_RTS) {
842 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
843 if (info->rtsdtr_inv) {
844 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
845 } else {
846 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
847 }
848 }
849 if (clear & TIOCM_RTS) {
850 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
851 if (info->rtsdtr_inv) {
852 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
853 } else {
854 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
855 }
856 }
857 if (set & TIOCM_DTR) {
858 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
859 if (info->rtsdtr_inv) {
860 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
861 } else {
862 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
863 }
864#ifdef CY_DEBUG_DTR
865 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
866 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
867 readb(base_addr + (CyMSVR1 << index)),
868 readb(base_addr + (CyMSVR2 << index)));
869#endif
870 }
871 if (clear & TIOCM_DTR) {
872 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
873 if (info->rtsdtr_inv) {
874 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
875 } else {
876 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
877 }
878
879#ifdef CY_DEBUG_DTR
880 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
881 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
882 readb(base_addr + (CyMSVR1 << index)),
883 readb(base_addr + (CyMSVR2 << index)));
884#endif
885 }
886}
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888/***********************************************************/
889/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700890/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891/***********************************************************/
892
893static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800894cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700895 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700897 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800898 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
Jiri Slaby97e87f82009-06-11 12:29:27 +0100900 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800901 if (loc_doorbell) {
902 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700903 *channel = readl(&board_ctrl->fwcmd_channel);
904 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100905 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800906 return 1;
907 }
908 return 0;
909} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800912cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700913 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700915 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700916 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700917 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Jiri Slaby2693f482009-06-11 12:31:06 +0100919 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800920 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700921
Jiri Slaby02f11752006-12-08 02:39:28 -0800922 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100923 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700924 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700925 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700926 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800927 udelay(50L);
928 }
929 cy_writel(&board_ctrl->hcmd_channel, channel);
930 cy_writel(&board_ctrl->hcmd_param, param);
931 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800933 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800934} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700936static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700938 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700939 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700940 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800941 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700943 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800945 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700947 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700949 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
950 rx_put = readl(&buf_ctrl->rx_put);
951 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
952 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800953 if (rx_put >= rx_get)
954 char_count = rx_put - rx_get;
955 else
956 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Jiri Slaby02f11752006-12-08 02:39:28 -0800958 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800960 info->mon.int_count++;
961 info->mon.char_count += char_count;
962 if (char_count > info->mon.char_max)
963 info->mon.char_max = char_count;
964 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700966 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800967 /* flush received characters */
968 new_rx_get = (new_rx_get + char_count) &
969 (rx_bufsize - 1);
970 info->rflush_count++;
971 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800973 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
974 for performance, but because of buffer boundaries, there
975 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700976 while (1) {
977 len = tty_prepare_flip_string(tty, &buf,
978 char_count);
979 if (!len)
980 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700982 len = min_t(unsigned int, min(len, char_count),
983 rx_bufsize - new_rx_get);
984
985 memcpy_fromio(buf, cinfo->base_addr +
986 rx_bufaddr + new_rx_get, len);
987
988 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800989 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700990 char_count -= len;
991 info->icount.rx += len;
992 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800995 len = tty_buffer_request_room(tty, char_count);
996 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700997 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800998 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700999 new_rx_get = (new_rx_get + 1) &
1000 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001001 tty_insert_flip_char(tty, data, TTY_NORMAL);
1002 info->idle_stats.recv_bytes++;
1003 info->icount.rx++;
1004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005#endif
1006#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001007 /* Recalculate the number of chars in the RX buffer and issue
1008 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001009 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001010 if (rx_put >= rx_get)
1011 char_count = rx_put - rx_get;
1012 else
1013 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001014 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -07001015 !timer_pending(&cyz_rx_full_timer[
1016 info->line]))
1017 mod_timer(&cyz_rx_full_timer[info->line],
1018 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001020 info->idle_stats.recv_idle = jiffies;
1021 tty_schedule_flip(tty);
1022 }
1023 /* Update rx_get */
1024 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026}
1027
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001028static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001030 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001031 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001032 u8 data;
1033 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001035 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001037 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Jiri Slaby02f11752006-12-08 02:39:28 -08001039 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1040 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001042 tx_get = readl(&buf_ctrl->tx_get);
1043 tx_put = readl(&buf_ctrl->tx_put);
1044 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1045 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001046 if (tx_put >= tx_get)
1047 char_count = tx_get - tx_put - 1 + tx_bufsize;
1048 else
1049 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Jiri Slaby02f11752006-12-08 02:39:28 -08001051 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Jiri Slabyf7429032007-05-08 00:36:59 -07001053 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001054 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001055
1056 if (info->x_char) { /* send special char */
1057 data = info->x_char;
1058
1059 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1060 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1061 info->x_char = 0;
1062 char_count--;
1063 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001064 }
1065#ifdef BLOCKMOVE
1066 while (0 < (small_count = min_t(unsigned int,
1067 tx_bufsize - tx_put, min_t(unsigned int,
1068 (SERIAL_XMIT_SIZE - info->xmit_tail),
1069 min_t(unsigned int, info->xmit_cnt,
1070 char_count))))) {
1071
1072 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1073 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001074 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001075 small_count);
1076
1077 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1078 char_count -= small_count;
1079 info->icount.tx += small_count;
1080 info->xmit_cnt -= small_count;
1081 info->xmit_tail = (info->xmit_tail + small_count) &
1082 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001083 }
1084#else
1085 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001086 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001087 info->xmit_cnt--;
1088 info->xmit_tail = (info->xmit_tail + 1) &
1089 (SERIAL_XMIT_SIZE - 1);
1090
1091 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1092 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1093 char_count--;
1094 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001097 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001098ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001099 /* Update tx_put */
1100 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102}
1103
Jiri Slaby02f11752006-12-08 02:39:28 -08001104static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001106 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001107 struct tty_struct *tty;
1108 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001109 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001110 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001111 int special_count;
1112 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001114 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Jiri Slaby02f11752006-12-08 02:39:28 -08001116 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1117 special_count = 0;
1118 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001119 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001120 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001121 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001122 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001123
Jiri Slaby02f11752006-12-08 02:39:28 -08001124 switch (cmd) {
1125 case C_CM_PR_ERROR:
1126 tty_insert_flip_char(tty, 0, TTY_PARITY);
1127 info->icount.rx++;
1128 special_count++;
1129 break;
1130 case C_CM_FR_ERROR:
1131 tty_insert_flip_char(tty, 0, TTY_FRAME);
1132 info->icount.rx++;
1133 special_count++;
1134 break;
1135 case C_CM_RXBRK:
1136 tty_insert_flip_char(tty, 0, TTY_BREAK);
1137 info->icount.rx++;
1138 special_count++;
1139 break;
1140 case C_CM_MDCD:
1141 info->icount.dcd++;
1142 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001143 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001144 u32 dcd = fw_ver > 241 ? param :
1145 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001146 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001147 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001148 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001149 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001150 }
1151 break;
1152 case C_CM_MCTS:
1153 info->icount.cts++;
1154 delta_count++;
1155 break;
1156 case C_CM_MRI:
1157 info->icount.rng++;
1158 delta_count++;
1159 break;
1160 case C_CM_MDSR:
1161 info->icount.dsr++;
1162 delta_count++;
1163 break;
1164#ifdef Z_WAKE
1165 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001166 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001167 break;
1168#endif
1169#ifdef CONFIG_CYZ_INTR
1170 case C_CM_RXHIWM:
1171 case C_CM_RXNNDT:
1172 case C_CM_INTBACK2:
1173 /* Reception Interrupt */
1174#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001175 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1176 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001177#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001178 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001179 break;
1180 case C_CM_TXBEMPTY:
1181 case C_CM_TXLOWWM:
1182 case C_CM_INTBACK:
1183 /* Transmission Interrupt */
1184#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001185 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1186 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001187#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001188 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001189 break;
1190#endif /* CONFIG_CYZ_INTR */
1191 case C_CM_FATAL:
1192 /* should do something with this !!! */
1193 break;
1194 default:
1195 break;
1196 }
1197 if (delta_count)
Jiri Slabyebafeef2007-10-18 03:06:20 -07001198 wake_up_interruptible(&info->delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001199 if (special_count)
1200 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001201 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001202 }
1203}
1204
1205#ifdef CONFIG_CYZ_INTR
1206static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1207{
Jiri Slabyf7429032007-05-08 00:36:59 -07001208 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001209
Jiri Slaby2693f482009-06-11 12:31:06 +01001210 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001211#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001212 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1213 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001214#endif
1215 return IRQ_NONE;
1216 }
1217
1218 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 cyz_handle_cmd(cinfo);
1220
Jiri Slaby02f11752006-12-08 02:39:28 -08001221 return IRQ_HANDLED;
1222} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
Jiri Slaby02f11752006-12-08 02:39:28 -08001224static void cyz_rx_restart(unsigned long arg)
1225{
1226 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001227 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001228 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001229 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001230 unsigned long flags;
1231
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001232 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001233 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001234 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001235 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001236 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001238 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001239}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Jiri Slaby02f11752006-12-08 02:39:28 -08001241#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jiri Slaby02f11752006-12-08 02:39:28 -08001243static void cyz_poll(unsigned long arg)
1244{
1245 struct cyclades_card *cinfo;
1246 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001247 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001248 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001249
Jiri Slaby02f11752006-12-08 02:39:28 -08001250 for (card = 0; card < NR_CARDS; card++) {
1251 cinfo = &cy_card[card];
1252
Jiri Slaby2693f482009-06-11 12:31:06 +01001253 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001254 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001255 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001256 continue;
1257
Jiri Slaby02f11752006-12-08 02:39:28 -08001258 /* Skip first polling cycle to avoid racing conditions with the FW */
1259 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001260 cinfo->intr_enabled = 1;
1261 continue;
1262 }
1263
1264 cyz_handle_cmd(cinfo);
1265
1266 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001267 struct tty_struct *tty;
1268
Jiri Slabydd025c02007-05-08 00:37:02 -07001269 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001270 tty = tty_port_tty_get(&info->port);
1271 /* OK to pass NULL to the handle functions below.
1272 They need to drop the data in that case. */
1273
Jiri Slaby02f11752006-12-08 02:39:28 -08001274 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001275 cyz_handle_rx(info, tty);
1276 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001277 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001278 }
1279 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001280 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001281 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001282 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001283} /* cyz_poll */
1284
1285#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
1287/********** End of block of Cyclades-Z specific code *********/
1288/***********************************************************/
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290/* This is called whenever a port becomes active;
1291 interrupts are enabled and DTR & RTS are turned on.
1292 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001293static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
Jiri Slaby875b2062007-05-08 00:36:49 -07001295 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001296 unsigned long flags;
1297 int retval = 0;
1298 void __iomem *base_addr;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001299 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001300 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Jiri Slaby02f11752006-12-08 02:39:28 -08001302 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001303 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Jiri Slaby02f11752006-12-08 02:39:28 -08001305 page = get_zeroed_page(GFP_KERNEL);
1306 if (!page)
1307 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001309 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001311 if (info->port.flags & ASYNC_INITIALIZED)
Jiri Slaby02f11752006-12-08 02:39:28 -08001312 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001313
1314 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001315 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001316 goto errout;
1317 }
1318
Alan Cox77451e52008-07-16 21:57:02 +01001319 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001320 free_page(page);
1321 else
Alan Cox77451e52008-07-16 21:57:02 +01001322 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001324 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Jiri Slabyd13549f2009-09-19 13:13:12 -07001326 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Jiri Slaby2693f482009-06-11 12:31:06 +01001328 if (!cy_is_Z(card)) {
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001329 int chip = channel >> 2;
1330 int index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001331 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001332 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001335 printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
1336 "base_addr %p\n",
1337 card, chip, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001338#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001339 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001340
1341 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1342
1343 cy_writeb(base_addr + (CyRTPR << index),
1344 (info->default_timeout ? info->default_timeout : 0x02));
1345 /* 10ms rx timeout */
1346
1347 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
1348 index);
1349
Jiri Slaby4d768202009-09-19 13:13:15 -07001350 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jiri Slaby02f11752006-12-08 02:39:28 -08001352 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001353 readb(base_addr + (CySRER << index)) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001354 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001355 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001356
Jiri Slaby2693f482009-06-11 12:31:06 +01001357 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001358 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001359
Jiri Slaby02f11752006-12-08 02:39:28 -08001360#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001361 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001362 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001363#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001364 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001365
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001366 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367#ifdef Z_WAKE
1368#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001369 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001370 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1371 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001373 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001374 C_IN_IOCTLW | C_IN_MDCD);
1375#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376#else
1377#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001378 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001379 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1380 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001382 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001383#endif /* CONFIG_CYZ_INTR */
1384#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Jiri Slaby875b2062007-05-08 00:36:49 -07001386 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001387 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001388 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1389 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Jiri Slaby02f11752006-12-08 02:39:28 -08001392 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001393 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001394 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001395 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1396 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Jiri Slaby02f11752006-12-08 02:39:28 -08001399 /* set timeout !!! */
1400 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001401 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Jiri Slaby02f11752006-12-08 02:39:28 -08001403 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001406 info->port.flags |= ASYNC_INITIALIZED;
1407
1408 clear_bit(TTY_IO_ERROR, &tty->flags);
1409 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1410 info->breakon = info->breakoff = 0;
1411 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1412 info->idle_stats.in_use =
1413 info->idle_stats.recv_idle =
1414 info->idle_stats.xmit_idle = jiffies;
1415
1416 spin_unlock_irqrestore(&card->card_lock, flags);
1417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001419 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420#endif
1421 return 0;
1422
1423errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001424 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001425 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001427} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Jiri Slaby02f11752006-12-08 02:39:28 -08001429static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430{
Jiri Slaby875b2062007-05-08 00:36:49 -07001431 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001432 unsigned long flags;
1433 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001434 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Jiri Slaby02f11752006-12-08 02:39:28 -08001436 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001437 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001438 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001439 chip = channel >> 2;
1440 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001441 index = card->bus_index;
1442 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001444 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001445 cy_writeb(base_addr + (CyCAR << index), channel);
1446 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001447 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001448 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001449 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001451 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001453 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001454 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001455 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001456 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1457 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001458 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001459 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001460#else /* CONFIG_CYZ_INTR */
1461 /* Don't have to do anything at this time */
1462#endif /* CONFIG_CYZ_INTR */
1463 }
1464} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466/*
1467 * This routine shuts down a serial port; interrupts are disabled,
1468 * and DTR is dropped if the hangup on close termio flag is on.
1469 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001470static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
Jiri Slaby875b2062007-05-08 00:36:49 -07001472 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001473 unsigned long flags;
1474 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001475 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Alan Cox77451e52008-07-16 21:57:02 +01001477 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001478 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Jiri Slaby02f11752006-12-08 02:39:28 -08001480 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001481 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001482 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001483 chip = channel >> 2;
1484 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001485 index = card->bus_index;
1486 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001489 printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
1490 "channel %d, base_addr %p\n",
1491 card, chip, channel, base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001494 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001495
1496 /* Clear delta_msr_wait queue to avoid mem leaks. */
1497 wake_up_interruptible(&info->delta_msr_wait);
1498
Alan Cox77451e52008-07-16 21:57:02 +01001499 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001500 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001501 temp = info->port.xmit_buf;
1502 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001503 free_page((unsigned long)temp);
1504 }
Jiri Slaby4d768202009-09-19 13:13:15 -07001505 if (tty->termios->c_cflag & HUPCL)
1506 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1507
Jiri Slaby02f11752006-12-08 02:39:28 -08001508 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
1509 /* it may be appropriate to clear _XMIT at
1510 some later date (after testing)!!! */
1511
Jiri Slabyd13549f2009-09-19 13:13:12 -07001512 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001513 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001514 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001515 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001516#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001517 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001518 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001519#endif
1520
Jiri Slaby2693f482009-06-11 12:31:06 +01001521 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001522 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001523
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001524 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001525
Alan Cox77451e52008-07-16 21:57:02 +01001526 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001527 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001528 temp = info->port.xmit_buf;
1529 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001530 free_page((unsigned long)temp);
1531 }
1532
Jiri Slaby4d768202009-09-19 13:13:15 -07001533 if (tty->termios->c_cflag & HUPCL)
1534 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001535
Jiri Slabyd13549f2009-09-19 13:13:12 -07001536 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001537 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001538
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001539 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001540 }
1541
1542#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001543 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001544#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001545} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547/*
1548 * ------------------------------------------------------------
1549 * cy_open() and friends
1550 * ------------------------------------------------------------
1551 */
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553/*
1554 * This routine is called whenever a serial port is opened. It
1555 * performs the serial-specific initialization for the tty structure.
1556 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001557static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558{
Jiri Slaby02f11752006-12-08 02:39:28 -08001559 struct cyclades_port *info;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001560 unsigned int i, line;
1561 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Jiri Slaby02f11752006-12-08 02:39:28 -08001563 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001564 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001566
Jiri Slabydd025c02007-05-08 00:37:02 -07001567 for (i = 0; i < NR_CARDS; i++)
1568 if (line < cy_card[i].first_line + cy_card[i].nports &&
1569 line >= cy_card[i].first_line)
1570 break;
1571 if (i >= NR_CARDS)
1572 return -ENODEV;
1573 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001574 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001575 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001576
1577 /* If the card's firmware hasn't been loaded,
1578 treat it as absent from the system. This
1579 will make the user pay attention.
1580 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001581 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001582 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001583 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1584
Jiri Slaby2693f482009-06-11 12:31:06 +01001585 if (!cyz_is_loaded(cinfo)) {
1586 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001587 readl(&firm_id->signature) ==
1588 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001589 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1590 "need an external power supply for "
1591 "this number of ports.\nFirmware "
1592 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001593 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001594 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1595 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001596 }
1597 return -ENODEV;
1598 }
1599#ifdef CONFIG_CYZ_INTR
1600 else {
1601 /* In case this Z board is operating in interrupt mode, its
1602 interrupts should be enabled as soon as the first open
1603 happens to one of its ports. */
1604 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001605 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001606
Jiri Slaby02f11752006-12-08 02:39:28 -08001607 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001608 intr = readw(&cinfo->ctl_addr.p9060->
1609 intr_ctrl_stat) | 0x0900;
1610 cy_writew(&cinfo->ctl_addr.p9060->
1611 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 /* Enable interrupts on the FW */
1613 retval = cyz_issue_cmd(cinfo, 0,
1614 C_CM_IRQ_ENBL, 0L);
1615 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001616 printk(KERN_ERR "cyc:IRQ enable retval "
1617 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001618 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001619 cinfo->intr_enabled = 1;
1620 }
1621 }
1622#endif /* CONFIG_CYZ_INTR */
1623 /* Make sure this Z port really exists in hardware */
1624 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1625 return -ENODEV;
1626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001628 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001630 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001631 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001632 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001635 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001636 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637#endif
Alan Cox77451e52008-07-16 21:57:02 +01001638 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001640 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001641 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Jiri Slaby02f11752006-12-08 02:39:28 -08001644 /*
1645 * If the port is the middle of closing, bail out now
1646 */
Alan Cox77451e52008-07-16 21:57:02 +01001647 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1648 wait_event_interruptible(info->port.close_wait,
1649 !(info->port.flags & ASYNC_CLOSING));
1650 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Jiri Slaby02f11752006-12-08 02:39:28 -08001653 /*
1654 * Start up serial port
1655 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001656 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001657 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001658 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Jiri Slabyf0737572009-09-19 13:13:12 -07001660 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001661 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001663 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1664 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001666 return retval;
1667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Jiri Slaby02f11752006-12-08 02:39:28 -08001669 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001670 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001673 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001675 return 0;
1676} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678/*
1679 * cy_wait_until_sent() --- wait until the transmitter is empty
1680 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001681static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
Jiri Slaby875b2062007-05-08 00:36:49 -07001683 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001684 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001685 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001686 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001687 unsigned long orig_jiffies;
1688 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Jiri Slaby02f11752006-12-08 02:39:28 -08001690 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1691 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Jiri Slaby02f11752006-12-08 02:39:28 -08001693 if (info->xmit_fifo_size == 0)
1694 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Jiri Slaby02f11752006-12-08 02:39:28 -08001696 orig_jiffies = jiffies;
Alan Cox978e5952008-04-30 00:53:59 -07001697 lock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08001698 /*
1699 * Set the check interval to be 1/5 of the estimated time to
1700 * send a single character, and make it at least 1. The check
1701 * interval should also be less than the timeout.
1702 *
1703 * Note: we have to use pretty tight timings here to satisfy
1704 * the NIST-PCTS.
1705 */
1706 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1707 char_time = char_time / 5;
1708 if (char_time <= 0)
1709 char_time = 1;
1710 if (timeout < 0)
1711 timeout = 0;
1712 if (timeout)
1713 char_time = min(char_time, timeout);
1714 /*
1715 * If the transmitter hasn't cleared in twice the approximate
1716 * amount of time to send the entire FIFO, it probably won't
1717 * ever clear. This assumes the UART isn't doing flow
1718 * control, which is currently the case. Hence, if it ever
1719 * takes longer than info->timeout, this is probably due to a
1720 * UART bug of some kind. So, we clamp the timeout parameter at
1721 * 2*info->timeout.
1722 */
1723 if (!timeout || timeout > 2 * info->timeout)
1724 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001726 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1727 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001729 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001730 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01001731 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001732 chip = channel >> 2;
1733 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001734 index = card->bus_index;
1735 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001736 while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001738 printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001740 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1741 break;
1742 if (timeout && time_after(jiffies, orig_jiffies +
1743 timeout))
1744 break;
1745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001747 /* Run one more char cycle */
1748 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Alan Cox978e5952008-04-30 00:53:59 -07001749 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001751 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752#endif
1753}
1754
Alan Cox978e5952008-04-30 00:53:59 -07001755static void cy_flush_buffer(struct tty_struct *tty)
1756{
1757 struct cyclades_port *info = tty->driver_data;
1758 struct cyclades_card *card;
1759 int channel, retval;
1760 unsigned long flags;
1761
1762#ifdef CY_DEBUG_IO
1763 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1764#endif
1765
1766 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1767 return;
1768
1769 card = info->card;
1770 channel = info->line - card->first_line;
1771
1772 spin_lock_irqsave(&card->card_lock, flags);
1773 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1774 spin_unlock_irqrestore(&card->card_lock, flags);
1775
Jiri Slaby2693f482009-06-11 12:31:06 +01001776 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001777 buffers as well */
1778 spin_lock_irqsave(&card->card_lock, flags);
1779 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1780 if (retval != 0) {
1781 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1782 "was %x\n", info->line, retval);
1783 }
1784 spin_unlock_irqrestore(&card->card_lock, flags);
1785 }
1786 tty_wakeup(tty);
1787} /* cy_flush_buffer */
1788
1789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790/*
1791 * This routine is called when a particular tty device is closed.
1792 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001793static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001795 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001796 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001797 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Alan Cox15ed6cc2008-04-30 00:53:55 -07001799 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001800 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001802 card = info->card;
1803
Jiri Slaby23342262009-09-19 13:13:13 -07001804 if (!tty_port_close_start(&info->port, tty, filp))
Jiri Slaby02f11752006-12-08 02:39:28 -08001805 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001806
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001807 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001808
Jiri Slaby2693f482009-06-11 12:31:06 +01001809 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001810 int channel = info->line - card->first_line;
1811 int index = card->bus_index;
1812 void __iomem *base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 (cy_chip_offset[channel >> 2] << index);
1814 /* Stop accepting input */
1815 channel &= 0x03;
1816 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1817 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001818 readb(base_addr + (CySRER << index)) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001819 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001820 /* Waiting for on-board buffers to be empty before
1821 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001822 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001823 cy_wait_until_sent(tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001824 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001825 }
1826 } else {
1827#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001828 /* Waiting for on-board buffers to be empty before closing
1829 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001830 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001831 int channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001832 int retval;
1833
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001834 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001835 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001836 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001837 printk(KERN_DEBUG "cyc:cy_close retval on "
1838 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001839 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001840 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001841 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001842 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001843 }
1844#endif
1845 }
1846
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001847 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001848 cy_shutdown(info, tty);
Alan Cox978e5952008-04-30 00:53:59 -07001849 cy_flush_buffer(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001850
Jiri Slabyd13549f2009-09-19 13:13:12 -07001851 tty_port_tty_set(&info->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Jiri Slaby23342262009-09-19 13:13:13 -07001853 tty_port_close_end(&info->port, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001854} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
1856/* This routine gets called when tty_write has put something into
1857 * the write_queue. The characters may come from user space or
1858 * kernel space.
1859 *
1860 * This routine will return the number of characters actually
1861 * accepted for writing.
1862 *
1863 * If the port is not already transmitting stuff, start it off by
1864 * enabling interrupts. The interrupt service routine will then
1865 * ensure that the characters are sent.
1866 * If the port is already active, there is no need to kick it.
1867 *
1868 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001869static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001871 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001872 unsigned long flags;
1873 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001876 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877#endif
1878
Alan Cox15ed6cc2008-04-30 00:53:55 -07001879 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001880 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Alan Cox77451e52008-07-16 21:57:02 +01001882 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001883 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001885 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001886 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001887 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1888 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Jiri Slaby02f11752006-12-08 02:39:28 -08001890 if (c <= 0)
1891 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
Alan Cox77451e52008-07-16 21:57:02 +01001893 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001894 info->xmit_head = (info->xmit_head + c) &
1895 (SERIAL_XMIT_SIZE - 1);
1896 info->xmit_cnt += c;
1897 buf += c;
1898 count -= c;
1899 ret += c;
1900 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001901 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
Jiri Slaby02f11752006-12-08 02:39:28 -08001903 info->idle_stats.xmit_bytes += ret;
1904 info->idle_stats.xmit_idle = jiffies;
1905
Alan Cox15ed6cc2008-04-30 00:53:55 -07001906 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001908
Jiri Slaby02f11752006-12-08 02:39:28 -08001909 return ret;
1910} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912/*
1913 * This routine is called by the kernel to write a single
1914 * character to the tty device. If the kernel uses this routine,
1915 * it must call the flush_chars() routine (if defined) when it is
1916 * done stuffing characters into the driver. If there is no room
1917 * in the queue, the character is ignored.
1918 */
Alan Cox76b25a52008-04-30 00:54:03 -07001919static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001921 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001922 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001925 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926#endif
1927
Jiri Slaby02f11752006-12-08 02:39:28 -08001928 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001929 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
Alan Cox77451e52008-07-16 21:57:02 +01001931 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001932 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001934 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001935 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001936 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001937 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
Alan Cox77451e52008-07-16 21:57:02 +01001940 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001941 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1942 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 info->idle_stats.xmit_bytes++;
1944 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001945 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001946 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001947} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949/*
1950 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001951 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001953static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001955 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001956
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001958 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959#endif
1960
Jiri Slaby02f11752006-12-08 02:39:28 -08001961 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1962 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
Jiri Slaby02f11752006-12-08 02:39:28 -08001964 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001965 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001966 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Jiri Slaby02f11752006-12-08 02:39:28 -08001968 start_xmit(info);
1969} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971/*
1972 * This routine returns the numbers of characters the tty driver
1973 * will accept for queuing to be written. This number is subject
1974 * to change as output buffers get emptied, or if the output flow
1975 * control is activated.
1976 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001977static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001979 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001980 int ret;
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001983 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984#endif
1985
Jiri Slaby02f11752006-12-08 02:39:28 -08001986 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1987 return 0;
1988 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1989 if (ret < 0)
1990 ret = 0;
1991 return ret;
1992} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Jiri Slaby02f11752006-12-08 02:39:28 -08001994static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001996 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
Jiri Slaby02f11752006-12-08 02:39:28 -08001998 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1999 return 0;
2000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002002 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002003#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002005 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2006 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002008 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002010 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002011 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002012 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07002013 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Alan Cox978e5952008-04-30 00:53:59 -07002015 lock_kernel();
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002016 tx_get = readl(&buf_ctrl->tx_get);
2017 tx_put = readl(&buf_ctrl->tx_put);
2018 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08002019 if (tx_put >= tx_get)
2020 char_count = tx_put - tx_get;
2021 else
2022 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002024 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2025 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026#endif
Alan Cox978e5952008-04-30 00:53:59 -07002027 unlock_kernel();
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002028 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08002029 }
2030#endif /* Z_EXT_CHARS_IN_BUFFER */
2031} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033/*
2034 * ------------------------------------------------------------
2035 * cy_ioctl() and friends
2036 * ------------------------------------------------------------
2037 */
2038
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002039static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
Jiri Slaby02f11752006-12-08 02:39:28 -08002041 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002042 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08002043 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Jiri Slaby02f11752006-12-08 02:39:28 -08002045 if (baud == 0) {
2046 info->tbpr = info->tco = info->rbpr = info->rco = 0;
2047 return;
2048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Jiri Slaby02f11752006-12-08 02:39:28 -08002050 /* determine which prescaler to use */
2051 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
2052 if (cy_clock / co_val / baud > 63)
2053 break;
2054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
Jiri Slaby02f11752006-12-08 02:39:28 -08002056 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
2057 if (bpr > 255)
2058 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
Jiri Slaby02f11752006-12-08 02:39:28 -08002060 info->tbpr = info->rbpr = bpr;
2061 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062}
2063
2064/*
2065 * This routine finds or computes the various line characteristics.
2066 * It used to be called config_setup
2067 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002068static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069{
Jiri Slaby875b2062007-05-08 00:36:49 -07002070 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002071 unsigned long flags;
2072 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002073 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002074 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002075 int baud, baud_rate = 0;
2076 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Jiri Slabyd13549f2009-09-19 13:13:12 -07002078 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002079 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002080
2081 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002082 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002083
Jiri Slabyd13549f2009-09-19 13:13:12 -07002084 cflag = tty->termios->c_cflag;
2085 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Jiri Slaby02f11752006-12-08 02:39:28 -08002087 /*
2088 * Set up the tty->alt_speed kludge
2089 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002090 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2091 tty->alt_speed = 57600;
2092 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2093 tty->alt_speed = 115200;
2094 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2095 tty->alt_speed = 230400;
2096 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2097 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
Jiri Slaby02f11752006-12-08 02:39:28 -08002099 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002100 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002101
Jiri Slaby2693f482009-06-11 12:31:06 +01002102 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002103
Jiri Slaby875b2062007-05-08 00:36:49 -07002104 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002105
2106 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002107 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002108 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002109 ASYNC_SPD_CUST) {
2110 if (info->custom_divisor)
2111 baud_rate = info->baud / info->custom_divisor;
2112 else
2113 baud_rate = info->baud;
2114 } else if (baud > CD1400_MAX_SPEED) {
2115 baud = CD1400_MAX_SPEED;
2116 }
2117 /* find the baud index */
2118 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002119 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002120 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002121 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002122 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002123 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002124
Alan Cox77451e52008-07-16 21:57:02 +01002125 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002126 ASYNC_SPD_CUST) {
2127 cyy_baud_calc(info, baud_rate);
2128 } else {
2129 if (info->chip_rev >= CD1400_REV_J) {
2130 /* It is a CD1400 rev. J or later */
2131 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2132 info->tco = baud_co_60[i]; /* Tx CO */
2133 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2134 info->rco = baud_co_60[i]; /* Rx CO */
2135 } else {
2136 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2137 info->tco = baud_co_25[i]; /* Tx CO */
2138 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2139 info->rco = baud_co_25[i]; /* Rx CO */
2140 }
2141 }
2142 if (baud_table[i] == 134) {
2143 /* get it right for 134.5 baud */
2144 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2145 2;
Alan Cox77451e52008-07-16 21:57:02 +01002146 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002147 ASYNC_SPD_CUST) {
2148 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2149 baud_rate) + 2;
2150 } else if (baud_table[i]) {
2151 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2152 baud_table[i]) + 2;
2153 /* this needs to be propagated into the card info */
2154 } else {
2155 info->timeout = 0;
2156 }
2157 /* By tradition (is it a standard?) a baud rate of zero
2158 implies the line should be/has been closed. A bit
2159 later in this routine such a test is performed. */
2160
2161 /* byte size and parity */
2162 info->cor5 = 0;
2163 info->cor4 = 0;
2164 /* receive threshold */
2165 info->cor3 = (info->default_threshold ?
2166 info->default_threshold : baud_cor3[i]);
2167 info->cor2 = CyETC;
2168 switch (cflag & CSIZE) {
2169 case CS5:
2170 info->cor1 = Cy_5_BITS;
2171 break;
2172 case CS6:
2173 info->cor1 = Cy_6_BITS;
2174 break;
2175 case CS7:
2176 info->cor1 = Cy_7_BITS;
2177 break;
2178 case CS8:
2179 info->cor1 = Cy_8_BITS;
2180 break;
2181 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002182 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002183 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002184
Jiri Slaby02f11752006-12-08 02:39:28 -08002185 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002186 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002187 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002188 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002189 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002190 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002191 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002192
2193 /* CTS flow control flag */
2194 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002195 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002196 info->cor2 |= CyCtsAE;
2197 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002198 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002199 info->cor2 &= ~CyCtsAE;
2200 }
2201 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002202 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002203 else
Alan Cox77451e52008-07-16 21:57:02 +01002204 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206 /***********************************************
2207 The hardware option, CyRtsAO, presents RTS when
2208 the chip has characters to send. Since most modems
2209 use RTS as reverse (inbound) flow control, this
2210 option is not used. If inbound flow control is
2211 necessary, DTR can be programmed to provide the
2212 appropriate signals for use with a non-standard
2213 cable. Contact Marcio Saito for details.
2214 ***********************************************/
2215
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 chip = channel >> 2;
2217 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002218 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002220 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002221 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Jiri Slaby02f11752006-12-08 02:39:28 -08002223 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Jiri Slaby02f11752006-12-08 02:39:28 -08002225 cy_writeb(base_addr + (CyTCOR << index), info->tco);
2226 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
2227 cy_writeb(base_addr + (CyRCOR << index), info->rco);
2228 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Jiri Slaby02f11752006-12-08 02:39:28 -08002230 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Jiri Slabyd13549f2009-09-19 13:13:12 -07002232 cy_writeb(base_addr + (CySCHR1 << index), START_CHAR(tty));
2233 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(tty));
Jiri Slaby02f11752006-12-08 02:39:28 -08002234 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
2235 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
2236 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2237 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
2238 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Jiri Slaby02f11752006-12-08 02:39:28 -08002240 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2241 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Alan Cox15ed6cc2008-04-30 00:53:55 -07002243 /* !!! Is this needed? */
2244 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08002245 cy_writeb(base_addr + (CyRTPR << index),
2246 (info->default_timeout ? info->default_timeout : 0x02));
2247 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
Jiri Slabyd13549f2009-09-19 13:13:12 -07002249 if (C_CLOCAL(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002250 /* without modem intr */
2251 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002252 readb(base_addr + (CySRER << index)) | CyMdmCh);
Jiri Slaby02f11752006-12-08 02:39:28 -08002253 /* act on 1->0 modem transitions */
2254 if ((cflag & CRTSCTS) && info->rflow) {
2255 cy_writeb(base_addr + (CyMCOR1 << index),
2256 (CyCTS | rflow_thr[i]));
2257 } else {
2258 cy_writeb(base_addr + (CyMCOR1 << index),
2259 CyCTS);
2260 }
2261 /* act on 0->1 modem transitions */
2262 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002264 /* without modem intr */
2265 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002266 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002267 (CySRER << index)) | CyMdmCh);
2268 /* act on 1->0 modem transitions */
2269 if ((cflag & CRTSCTS) && info->rflow) {
2270 cy_writeb(base_addr + (CyMCOR1 << index),
2271 (CyDSR | CyCTS | CyRI | CyDCD |
2272 rflow_thr[i]));
2273 } else {
2274 cy_writeb(base_addr + (CyMCOR1 << index),
2275 CyDSR | CyCTS | CyRI | CyDCD);
2276 }
2277 /* act on 0->1 modem transitions */
2278 cy_writeb(base_addr + (CyMCOR2 << index),
2279 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002281
Jiri Slaby4d768202009-09-19 13:13:15 -07002282 if (i == 0) /* baud rate is zero, turn off line */
2283 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2284 else
2285 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Jiri Slabyd13549f2009-09-19 13:13:12 -07002287 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002288 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002291 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002292 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002293 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
Jiri Slaby2693f482009-06-11 12:31:06 +01002295 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002296 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
Jiri Slaby02f11752006-12-08 02:39:28 -08002298 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002299 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002300 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002301 ASYNC_SPD_CUST) {
2302 if (info->custom_divisor)
2303 baud_rate = info->baud / info->custom_divisor;
2304 else
2305 baud_rate = info->baud;
2306 } else if (baud > CYZ_MAX_SPEED) {
2307 baud = CYZ_MAX_SPEED;
2308 }
2309 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Jiri Slaby02f11752006-12-08 02:39:28 -08002311 if (baud == 134) {
2312 /* get it right for 134.5 baud */
2313 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2314 2;
Alan Cox77451e52008-07-16 21:57:02 +01002315 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002316 ASYNC_SPD_CUST) {
2317 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2318 baud_rate) + 2;
2319 } else if (baud) {
2320 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2321 baud) + 2;
2322 /* this needs to be propagated into the card info */
2323 } else {
2324 info->timeout = 0;
2325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
Jiri Slaby02f11752006-12-08 02:39:28 -08002327 /* byte size and parity */
2328 switch (cflag & CSIZE) {
2329 case CS5:
2330 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2331 break;
2332 case CS6:
2333 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2334 break;
2335 case CS7:
2336 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2337 break;
2338 case CS8:
2339 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2340 break;
2341 }
2342 if (cflag & CSTOPB) {
2343 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002344 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002345 } else {
2346 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002347 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002348 }
2349 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002350 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002351 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002352 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002353 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002354 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002355 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Jiri Slaby02f11752006-12-08 02:39:28 -08002357 /* CTS flow control flag */
2358 if (cflag & CRTSCTS) {
2359 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002360 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002361 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002362 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2363 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002364 }
2365 /* As the HW flow control is done in firmware, the driver
2366 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002367 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002368
2369 /* XON/XOFF/XANY flow control flags */
2370 sw_flow = 0;
2371 if (iflag & IXON) {
2372 sw_flow |= C_FL_OXX;
2373 if (iflag & IXANY)
2374 sw_flow |= C_FL_OIXANY;
2375 }
2376 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2377
Jiri Slaby875b2062007-05-08 00:36:49 -07002378 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002379 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002380 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2381 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002382 }
2383
2384 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002385 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002386 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002387 else
Alan Cox77451e52008-07-16 21:57:02 +01002388 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002389
2390 if (baud == 0) { /* baud rate is zero, turn off line */
2391 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002392 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002394 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002396 } else {
2397 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002398 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002400 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
Alan Cox15ed6cc2008-04-30 00:53:55 -07002404 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002405 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002406 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2407 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
Jiri Slabyd13549f2009-09-19 13:13:12 -07002410 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002412} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
Jiri Slaby6c281812009-09-19 13:13:15 -07002414static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002415 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416{
Jiri Slaby875b2062007-05-08 00:36:49 -07002417 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002418 struct serial_struct tmp = {
2419 .type = info->type,
2420 .line = info->line,
2421 .port = (info->card - cy_card) * 0x100 + info->line -
2422 cinfo->first_line,
2423 .irq = cinfo->irq,
2424 .flags = info->port.flags,
2425 .close_delay = info->port.close_delay,
2426 .closing_wait = info->port.closing_wait,
2427 .baud_base = info->baud,
2428 .custom_divisor = info->custom_divisor,
2429 .hub6 = 0, /*!!! */
2430 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002431 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002432}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002435cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002436 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437{
Jiri Slaby02f11752006-12-08 02:39:28 -08002438 struct serial_struct new_serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Jiri Slaby02f11752006-12-08 02:39:28 -08002440 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2441 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
Jiri Slaby02f11752006-12-08 02:39:28 -08002443 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002444 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002445 new_serial.baud_base != info->baud ||
2446 (new_serial.flags & ASYNC_FLAGS &
2447 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002448 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Jiri Slaby02f11752006-12-08 02:39:28 -08002449 return -EPERM;
Alan Cox77451e52008-07-16 21:57:02 +01002450 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002451 (new_serial.flags & ASYNC_USR_MASK);
2452 info->baud = new_serial.baud_base;
2453 info->custom_divisor = new_serial.custom_divisor;
2454 goto check_and_exit;
2455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Jiri Slaby02f11752006-12-08 02:39:28 -08002457 /*
2458 * OK, past this point, all the error checking has been done.
2459 * At this point, we start making changes.....
2460 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Jiri Slaby02f11752006-12-08 02:39:28 -08002462 info->baud = new_serial.baud_base;
2463 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002464 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002465 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002466 info->port.close_delay = new_serial.close_delay * HZ / 100;
2467 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
2469check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002470 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002471 cy_set_line_char(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002472 return 0;
2473 } else {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002474 return cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002475 }
2476} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
2478/*
2479 * get_lsr_info - get line status register info
2480 *
2481 * Purpose: Let user call ioctl() to get info when the UART physically
2482 * is emptied. On bus types like RS485, the transmitter must
2483 * release the bus after transmitting. This must be done when
2484 * the transmit shift register is empty, not be done when the
2485 * transmit holding register is empty. This functionality
2486 * allows an RS485 driver to be written in user space.
2487 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002488static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489{
Jiri Slaby875b2062007-05-08 00:36:49 -07002490 struct cyclades_card *card;
2491 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002492 unsigned char status;
2493 unsigned int result;
2494 unsigned long flags;
2495 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
Jiri Slaby02f11752006-12-08 02:39:28 -08002497 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002498 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002499 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002500 chip = channel >> 2;
2501 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002502 index = card->bus_index;
2503 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002505 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002506 status = readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002507 (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002508 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002509 result = (status ? 0 : TIOCSER_TEMT);
2510 } else {
2511 /* Not supported yet */
2512 return -EINVAL;
2513 }
2514 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515}
2516
Jiri Slaby02f11752006-12-08 02:39:28 -08002517static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002519 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002520 struct cyclades_card *card;
2521 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002522 void __iomem *base_addr;
2523 unsigned long flags;
2524 unsigned char status;
2525 unsigned long lstatus;
2526 unsigned int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002528 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002529 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
Alan Cox7b130c02008-04-30 00:53:16 -07002531 lock_kernel();
2532
Jiri Slaby02f11752006-12-08 02:39:28 -08002533 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002534 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002535 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002536 chip = channel >> 2;
2537 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002538 index = card->bus_index;
2539 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002541 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002542 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002543 status = readb(base_addr + (CyMSVR1 << index));
2544 status |= readb(base_addr + (CyMSVR2 << index));
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002545 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
Jiri Slaby02f11752006-12-08 02:39:28 -08002547 if (info->rtsdtr_inv) {
2548 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2549 ((status & CyDTR) ? TIOCM_RTS : 0);
2550 } else {
2551 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2552 ((status & CyDTR) ? TIOCM_DTR : 0);
2553 }
2554 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2555 ((status & CyRI) ? TIOCM_RNG : 0) |
2556 ((status & CyDSR) ? TIOCM_DSR : 0) |
2557 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002559 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002560 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby02f11752006-12-08 02:39:28 -08002561 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2562 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2563 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2564 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2565 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2566 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
2567 } else {
2568 result = 0;
Alan Cox7b130c02008-04-30 00:53:16 -07002569 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002570 return -ENODEV;
2571 }
2572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 }
Alan Cox7b130c02008-04-30 00:53:16 -07002574 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002575 return result;
2576} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
2578static int
2579cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08002580 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002582 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002583 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002584 unsigned long flags;
Jiri Slaby4d768202009-09-19 13:13:15 -07002585 int channel, retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002587 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002588 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
Jiri Slaby02f11752006-12-08 02:39:28 -08002590 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002591 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002592 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002593 spin_lock_irqsave(&card->card_lock, flags);
2594 cyy_change_rts_dtr(info, set, clear);
2595 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002596 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002597 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002598 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002599
2600 if (set & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002601 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002602 cy_writel(&ch_ctrl->rs_control,
2603 readl(&ch_ctrl->rs_control) | C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002604 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002605 }
2606 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002607 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002608 cy_writel(&ch_ctrl->rs_control,
2609 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002610 ~C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002611 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002612 }
2613 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002614 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002615 cy_writel(&ch_ctrl->rs_control,
2616 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002617#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002618 printk(KERN_DEBUG "cyc:set_modem_info raising "
2619 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002620#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002621 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002622 }
2623 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002624 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002625 cy_writel(&ch_ctrl->rs_control,
2626 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002627 ~C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002628#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002629 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2630 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002631#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002632 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002633 }
2634 } else {
2635 return -ENODEV;
2636 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002637 spin_lock_irqsave(&card->card_lock, flags);
2638 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002639 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002640 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2641 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002642 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002643 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002645 return 0;
2646} /* cy_tiocmset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
2648/*
2649 * cy_break() --- routine which turns the break handling on or off
2650 */
Alan Cox9e989662008-07-22 11:18:03 +01002651static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002653 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002654 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002655 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002656 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Jiri Slaby02f11752006-12-08 02:39:28 -08002658 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002659 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002661 card = info->card;
2662
2663 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002664 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002665 /* Let the transmit ISR take care of this (since it
2666 requires stuffing characters into the output stream).
2667 */
2668 if (break_state == -1) {
2669 if (!info->breakon) {
2670 info->breakon = 1;
2671 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002672 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002673 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002674 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002675 }
2676 }
2677 } else {
2678 if (!info->breakoff) {
2679 info->breakoff = 1;
2680 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002681 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002682 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002683 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002684 }
2685 }
2686 }
2687 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002688 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002689 retval = cyz_issue_cmd(card,
2690 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002691 C_CM_SET_BREAK, 0L);
2692 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002693 printk(KERN_ERR "cyc:cy_break (set) retval on "
2694 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002695 }
2696 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002697 retval = cyz_issue_cmd(card,
2698 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002699 C_CM_CLR_BREAK, 0L);
2700 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002701 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2702 "on ttyC%d was %x\n", info->line,
2703 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002704 }
2705 }
2706 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002707 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002708 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002709} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
Jiri Slaby02f11752006-12-08 02:39:28 -08002711static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712{
Jiri Slaby875b2062007-05-08 00:36:49 -07002713 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002714 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002715 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002716 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
Jiri Slaby02f11752006-12-08 02:39:28 -08002718 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002719 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002720 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002721 chip = channel >> 2;
2722 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002723 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002724 base_addr =
Jiri Slaby875b2062007-05-08 00:36:49 -07002725 card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
Jiri Slaby02f11752006-12-08 02:39:28 -08002727 info->cor3 &= ~CyREC_FIFO;
2728 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002730 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002731 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2732 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002733 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002736} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
Alan Cox15ed6cc2008-04-30 00:53:55 -07002738static int get_threshold(struct cyclades_port *info,
2739 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740{
Jiri Slaby875b2062007-05-08 00:36:49 -07002741 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002742 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002743 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002744 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Jiri Slaby02f11752006-12-08 02:39:28 -08002746 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002747 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002748 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002749 chip = channel >> 2;
2750 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002751 index = card->bus_index;
2752 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002753
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002754 tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002755 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002756 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002757 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002758} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Jiri Slaby02f11752006-12-08 02:39:28 -08002760static int set_timeout(struct cyclades_port *info, unsigned long value)
2761{
Jiri Slaby875b2062007-05-08 00:36:49 -07002762 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002763 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002764 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002765 unsigned long flags;
2766
2767 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002768 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002769 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002770 chip = channel >> 2;
2771 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002772 index = card->bus_index;
2773 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002774
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002775 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002776 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002777 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002778 }
2779 return 0;
2780} /* set_timeout */
2781
Alan Cox15ed6cc2008-04-30 00:53:55 -07002782static int get_timeout(struct cyclades_port *info,
2783 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002784{
Jiri Slaby875b2062007-05-08 00:36:49 -07002785 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002786 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002787 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002788 unsigned long tmp;
2789
2790 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002791 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002792 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002793 chip = channel >> 2;
2794 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002795 index = card->bus_index;
2796 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002797
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002798 tmp = readb(base_addr + (CyRTPR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08002799 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002800 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002801 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002802} /* get_timeout */
2803
Jiri Slaby6c281812009-09-19 13:13:15 -07002804static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2805 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002806{
Jiri Slaby6c281812009-09-19 13:13:15 -07002807 struct cyclades_icount cnow;
2808 unsigned long flags;
2809 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002810
Jiri Slaby6c281812009-09-19 13:13:15 -07002811 spin_lock_irqsave(&info->card->card_lock, flags);
2812 cnow = info->icount; /* atomic copy */
2813 spin_unlock_irqrestore(&info->card->card_lock, flags);
2814
2815 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2816 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2817 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2818 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2819
2820 *cprev = cnow;
2821
2822 return ret;
2823}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
2825/*
2826 * This routine allows the tty driver to implement device-
2827 * specific ioctl's. If the ioctl number passed in cmd is
2828 * not recognized by the driver, it should return ENOIOCTLCMD.
2829 */
2830static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002831cy_ioctl(struct tty_struct *tty, struct file *file,
2832 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002834 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002835 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002836 int ret_val = 0;
2837 unsigned long flags;
2838 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
Jiri Slaby02f11752006-12-08 02:39:28 -08002840 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2841 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
2843#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002844 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2845 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846#endif
Alan Cox7b130c02008-04-30 00:53:16 -07002847 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
Jiri Slaby02f11752006-12-08 02:39:28 -08002849 switch (cmd) {
2850 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002851 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2852 ret_val = -EFAULT;
2853 break;
2854 }
2855 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002857 case CYGETTHRESH:
2858 ret_val = get_threshold(info, argp);
2859 break;
2860 case CYSETTHRESH:
2861 ret_val = set_threshold(info, arg);
2862 break;
2863 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002864 ret_val = put_user(info->default_threshold,
2865 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002866 break;
2867 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002868 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002869 break;
2870 case CYGETTIMEOUT:
2871 ret_val = get_timeout(info, argp);
2872 break;
2873 case CYSETTIMEOUT:
2874 ret_val = set_timeout(info, arg);
2875 break;
2876 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002877 ret_val = put_user(info->default_timeout,
2878 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002879 break;
2880 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002881 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002882 break;
2883 case CYSETRFLOW:
2884 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002885 break;
2886 case CYGETRFLOW:
2887 ret_val = info->rflow;
2888 break;
2889 case CYSETRTSDTR_INV:
2890 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002891 break;
2892 case CYGETRTSDTR_INV:
2893 ret_val = info->rtsdtr_inv;
2894 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002896 ret_val = info->chip_rev;
2897 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898#ifndef CONFIG_CYZ_INTR
2899 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002900 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002901 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002903 ret_val = (cyz_polling_cycle * 1000) / HZ;
2904 break;
2905#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002907 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002908 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002910 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002911 break;
2912 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002913 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002914 break;
2915 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002916 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002917 break;
2918 case TIOCSERGETLSR: /* Get line status register */
2919 ret_val = get_lsr_info(info, argp);
2920 break;
2921 /*
2922 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2923 * - mask passed in arg for lines of interest
2924 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2925 * Caller should use TIOCGICOUNT to see which one it was
2926 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002928 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002929 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002930 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002931 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby6c281812009-09-19 13:13:15 -07002932 ret_val = wait_event_interruptible(info->delta_msr_wait,
2933 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002934 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002935
2936 /*
2937 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2938 * Return: write counters to the user passed counter struct
2939 * NB: both 1->0 and 0->1 transitions are counted except for
2940 * RI where only 0->1 is counted.
2941 */
Jiri Slaby6c281812009-09-19 13:13:15 -07002942 case TIOCGICOUNT: {
2943 struct serial_icounter_struct sic = { };
2944
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002945 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002946 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002947 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby6c281812009-09-19 13:13:15 -07002948
2949 sic.cts = cnow.cts;
2950 sic.dsr = cnow.dsr;
2951 sic.rng = cnow.rng;
2952 sic.dcd = cnow.dcd;
2953 sic.rx = cnow.rx;
2954 sic.tx = cnow.tx;
2955 sic.frame = cnow.frame;
2956 sic.overrun = cnow.overrun;
2957 sic.parity = cnow.parity;
2958 sic.brk = cnow.brk;
2959 sic.buf_overrun = cnow.buf_overrun;
2960
2961 if (copy_to_user(argp, &sic, sizeof(sic)))
2962 ret_val = -EFAULT;
Jiri Slaby02f11752006-12-08 02:39:28 -08002963 break;
Jiri Slaby6c281812009-09-19 13:13:15 -07002964 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002965 default:
2966 ret_val = -ENOIOCTLCMD;
2967 }
Alan Cox7b130c02008-04-30 00:53:16 -07002968 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969
2970#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002971 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002973 return ret_val;
2974} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
2976/*
2977 * This routine allows the tty driver to be notified when
2978 * device's termios settings have changed. Note that a
2979 * well-designed tty driver should be prepared to accept the case
2980 * where old == NULL, and try to do something rational.
2981 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002982static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002984 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
2986#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002987 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988#endif
2989
Jiri Slabyd13549f2009-09-19 13:13:12 -07002990 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991
Jiri Slaby02f11752006-12-08 02:39:28 -08002992 if ((old_termios->c_cflag & CRTSCTS) &&
2993 !(tty->termios->c_cflag & CRTSCTS)) {
2994 tty->hw_stopped = 0;
2995 cy_start(tty);
2996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002998 /*
2999 * No need to wake up processes in open wait, since they
3000 * sample the CLOCAL flag once, and don't recheck it.
3001 * XXX It's not clear whether the current behavior is correct
3002 * or not. Hence, this may change.....
3003 */
3004 if (!(old_termios->c_cflag & CLOCAL) &&
3005 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01003006 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003008} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
3010/* This function is used to send a high-priority XON/XOFF character to
3011 the device.
3012*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003013static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003015 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003016 struct cyclades_card *card;
3017 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Jiri Slaby02f11752006-12-08 02:39:28 -08003019 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 return;
3021
Jiri Slaby02f11752006-12-08 02:39:28 -08003022 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
3024 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08003025 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
3027 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003028 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Jiri Slaby2693f482009-06-11 12:31:06 +01003030 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003031 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003032 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003033 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003034 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 }
3036}
3037
3038/* This routine is called by the upper-layer tty layer to signal
3039 that incoming characters should be throttled because the input
3040 buffers are close to full.
3041 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003042static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003044 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003045 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003046 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047
3048#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003049 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050
Jiri Slaby21719192007-05-08 00:36:42 -07003051 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08003052 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053#endif
3054
Alan Cox15ed6cc2008-04-30 00:53:55 -07003055 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003056 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
Jiri Slaby02f11752006-12-08 02:39:28 -08003058 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
Jiri Slaby02f11752006-12-08 02:39:28 -08003060 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003061 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08003062 cy_send_xchar(tty, STOP_CHAR(tty));
3063 else
3064 info->throttle = 1;
3065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
Jiri Slaby02f11752006-12-08 02:39:28 -08003067 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003068 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003069 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003070 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003071 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003072 } else {
3073 info->throttle = 1;
3074 }
3075 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003076} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
3078/*
3079 * This routine notifies the tty driver that it should signal
3080 * that characters can now be sent to the tty without fear of
3081 * overrunning the input buffers of the line disciplines.
3082 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003083static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003085 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003086 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003087 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003090 char buf[64];
3091
Jiri Slaby21719192007-05-08 00:36:42 -07003092 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07003093 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094#endif
3095
Alan Cox15ed6cc2008-04-30 00:53:55 -07003096 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003097 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Jiri Slaby02f11752006-12-08 02:39:28 -08003099 if (I_IXOFF(tty)) {
3100 if (info->x_char)
3101 info->x_char = 0;
3102 else
3103 cy_send_xchar(tty, START_CHAR(tty));
3104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Jiri Slaby02f11752006-12-08 02:39:28 -08003106 if (tty->termios->c_cflag & CRTSCTS) {
3107 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01003108 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003109 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003110 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003111 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003112 } else {
3113 info->throttle = 0;
3114 }
3115 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003116} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
3118/* cy_start and cy_stop provide software output flow control as a
3119 function of XON/XOFF, software CTS, and other such stuff.
3120*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003121static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122{
Jiri Slaby02f11752006-12-08 02:39:28 -08003123 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003124 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003125 void __iomem *base_addr;
3126 int chip, channel, index;
3127 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
3129#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003130 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131#endif
3132
Jiri Slaby02f11752006-12-08 02:39:28 -08003133 if (serial_paranoia_check(info, tty->name, "cy_stop"))
3134 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
Jiri Slaby875b2062007-05-08 00:36:49 -07003136 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003137 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003138 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003139 index = cinfo->bus_index;
3140 chip = channel >> 2;
3141 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003142 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003144 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003145 cy_writeb(base_addr + (CyCAR << index),
3146 (u_char)(channel & 0x0003)); /* index channel */
3147 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003148 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003149 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003151} /* cy_stop */
3152
3153static void cy_start(struct tty_struct *tty)
3154{
3155 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003156 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003157 void __iomem *base_addr;
3158 int chip, channel, index;
3159 unsigned long flags;
3160
3161#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003162 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08003163#endif
3164
3165 if (serial_paranoia_check(info, tty->name, "cy_start"))
3166 return;
3167
Jiri Slaby875b2062007-05-08 00:36:49 -07003168 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003169 channel = info->line - cinfo->first_line;
3170 index = cinfo->bus_index;
Jiri Slaby2693f482009-06-11 12:31:06 +01003171 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003172 chip = channel >> 2;
3173 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003174 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003175
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003176 spin_lock_irqsave(&cinfo->card_lock, flags);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003177 cy_writeb(base_addr + (CyCAR << index),
3178 (u_char) (channel & 0x0003)); /* index channel */
Jiri Slaby02f11752006-12-08 02:39:28 -08003179 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003180 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003181 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003182 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003183} /* cy_start */
3184
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185/*
3186 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3187 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003188static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003190 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003191
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003193 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194#endif
3195
Jiri Slaby02f11752006-12-08 02:39:28 -08003196 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3197 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
Jiri Slaby02f11752006-12-08 02:39:28 -08003199 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003200 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003201 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003202} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
Jiri Slabyf0737572009-09-19 13:13:12 -07003204static int cyy_carrier_raised(struct tty_port *port)
3205{
3206 struct cyclades_port *info = container_of(port, struct cyclades_port,
3207 port);
3208 struct cyclades_card *cinfo = info->card;
3209 void __iomem *base = cinfo->base_addr;
3210 unsigned long flags;
3211 int channel = info->line - cinfo->first_line;
3212 int chip = channel >> 2, index = cinfo->bus_index;
3213 u32 cd;
3214
3215 channel &= 0x03;
3216 base += cy_chip_offset[chip] << index;
3217
3218 spin_lock_irqsave(&cinfo->card_lock, flags);
3219 cy_writeb(base + (CyCAR << index), (u8)channel);
3220 cd = readb(base + (CyMSVR1 << index)) & CyDCD;
3221 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3222
3223 return cd;
3224}
3225
3226static void cyy_dtr_rts(struct tty_port *port, int raise)
3227{
3228 struct cyclades_port *info = container_of(port, struct cyclades_port,
3229 port);
3230 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003231 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003232
3233 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003234 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3235 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003236 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3237}
3238
3239static int cyz_carrier_raised(struct tty_port *port)
3240{
3241 struct cyclades_port *info = container_of(port, struct cyclades_port,
3242 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003243
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003244 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003245}
3246
3247static void cyz_dtr_rts(struct tty_port *port, int raise)
3248{
3249 struct cyclades_port *info = container_of(port, struct cyclades_port,
3250 port);
3251 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003252 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003253 int ret, channel = info->line - cinfo->first_line;
3254 u32 rs;
3255
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003256 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003257 if (raise)
3258 rs |= C_RS_RTS | C_RS_DTR;
3259 else
3260 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003261 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003262 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3263 if (ret != 0)
3264 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3265 __func__, info->line, ret);
3266#ifdef CY_DEBUG_DTR
3267 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3268#endif
3269}
3270
3271static const struct tty_port_operations cyy_port_ops = {
3272 .carrier_raised = cyy_carrier_raised,
3273 .dtr_rts = cyy_dtr_rts,
3274};
3275
3276static const struct tty_port_operations cyz_port_ops = {
3277 .carrier_raised = cyz_carrier_raised,
3278 .dtr_rts = cyz_dtr_rts,
3279};
3280
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281/*
3282 * ---------------------------------------------------------------------
3283 * cy_init() and friends
3284 *
3285 * cy_init() is called at boot-time to initialize the serial driver.
3286 * ---------------------------------------------------------------------
3287 */
3288
Jiri Slabydd025c02007-05-08 00:37:02 -07003289static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003290{
3291 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003292 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003293
Jiri Slaby3046d502007-05-08 00:36:46 -07003294 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003295 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003296
Jiri Slaby963118e2009-06-11 12:34:27 +01003297 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3298 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003299 if (cinfo->ports == NULL) {
3300 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3301 return -ENOMEM;
3302 }
3303
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003304 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3305 channel++, port++) {
3306 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003307 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003308 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003309 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003310 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003311
Alan Cox44b7d1b2008-07-16 21:57:18 +01003312 info->port.closing_wait = CLOSING_WAIT_DELAY;
3313 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003314 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003315 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003316 init_waitqueue_head(&info->delta_msr_wait);
3317
Jiri Slaby2693f482009-06-11 12:31:06 +01003318 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003319 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3320 struct ZFW_CTRL *zfw_ctrl;
3321
Jiri Slabyf0737572009-09-19 13:13:12 -07003322 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003323 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003324
3325 zfw_ctrl = cinfo->base_addr +
3326 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3327 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3328 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3329
Jiri Slaby101b8152009-06-11 12:30:10 +01003330 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003331 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3332 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003333 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003334#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003335 setup_timer(&cyz_rx_full_timer[port],
3336 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003337#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003338 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003339 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003340 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003341
Jiri Slabyf0737572009-09-19 13:13:12 -07003342 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003343 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003344 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003345 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003346 info->cor2 = CyETC;
3347 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003348
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003349 chip_number = channel / CyPORTS_PER_CHIP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07003350 info->chip_rev = readb(cinfo->base_addr +
3351 (cy_chip_offset[chip_number] << index) +
3352 (CyGFRCR << index));
3353
3354 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003355 /* It is a CD1400 rev. J or later */
3356 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3357 info->tco = baud_co_60[13]; /* Tx CO */
3358 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3359 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003360 info->rtsdtr_inv = 1;
3361 } else {
3362 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3363 info->tco = baud_co_25[13]; /* Tx CO */
3364 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3365 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003366 info->rtsdtr_inv = 0;
3367 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003368 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3369 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003370 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003371
Jiri Slaby0809e262007-05-08 00:36:14 -07003372 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003373
3374#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003375 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003376 mod_timer(&cyz_timerlist, jiffies + 1);
3377#ifdef CY_PCI_DEBUG
3378 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3379#endif
3380 }
3381#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003382 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003383}
3384
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385/* initialize chips on Cyclom-Y card -- return number of valid
3386 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003387static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3388 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389{
Jiri Slaby02f11752006-12-08 02:39:28 -08003390 unsigned int chip_number;
3391 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
Jiri Slaby02f11752006-12-08 02:39:28 -08003393 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3394 /* Cy_HwReset is 0x1400 */
3395 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3396 /* Cy_ClrIntr is 0x1800 */
3397 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
Alan Cox15ed6cc2008-04-30 00:53:55 -07003399 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3400 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003401 base_addr =
3402 true_base_addr + (cy_chip_offset[chip_number] << index);
3403 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003404 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003405 /*************
3406 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3407 chip_number, (unsigned long)base_addr);
3408 *************/
3409 return chip_number;
3410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411
Jiri Slaby02f11752006-12-08 02:39:28 -08003412 cy_writeb(base_addr + (CyGFRCR << index), 0);
3413 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
Jiri Slaby02f11752006-12-08 02:39:28 -08003415 /* The Cyclom-16Y does not decode address bit 9 and therefore
3416 cannot distinguish between references to chip 0 and a non-
3417 existent chip 4. If the preceding clearing of the supposed
3418 chip 4 GFRCR register appears at chip 0, there is no chip 4
3419 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3420 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003421 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003422 (cy_chip_offset[0] << index) +
3423 (CyGFRCR << index)) == 0) {
3424 return chip_number;
3425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
Jiri Slaby02f11752006-12-08 02:39:28 -08003427 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3428 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003430 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003431 /*
3432 printk(" chip #%d at %#6lx is not responding ",
3433 chip_number, (unsigned long)base_addr);
3434 printk("(GFRCR stayed 0)\n",
3435 */
3436 return chip_number;
3437 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003438 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003439 0x40) {
3440 /*
3441 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3442 "%#2x)\n",
3443 chip_number, (unsigned long)base_addr,
3444 base_addr[CyGFRCR<<index]);
3445 */
3446 return chip_number;
3447 }
3448 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003449 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003450 /* It is a CD1400 rev. J or later */
3451 /* Impossible to reach 5ms with this chip.
3452 Changed to 2ms instead (f = 500 Hz). */
3453 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3454 } else {
3455 /* f = 200 Hz */
3456 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3457 }
3458
3459 /*
3460 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3461 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003462 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003463 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003465 return chip_number;
3466} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
3468/*
3469 * ---------------------------------------------------------------------
3470 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3471 * sets global variables and return the number of ISA boards found.
3472 * ---------------------------------------------------------------------
3473 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003474static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475{
3476#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003477 unsigned short cy_isa_irq, nboard;
3478 void __iomem *cy_isa_address;
3479 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08003481 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482#endif
3483
Jiri Slaby02f11752006-12-08 02:39:28 -08003484 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485
3486#ifdef MODULE
3487 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003488 for (i = 0; i < NR_CARDS; i++) {
3489 if (maddr[i] || i) {
3490 isparam = 1;
3491 cy_isa_addresses[i] = maddr[i];
3492 }
3493 if (!maddr[i])
3494 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 }
3496#endif
3497
Jiri Slaby02f11752006-12-08 02:39:28 -08003498 /* scan the address table probing for Cyclom-Y/ISA boards */
3499 for (i = 0; i < NR_ISA_ADDRS; i++) {
3500 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003501 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003502 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
Jiri Slaby02f11752006-12-08 02:39:28 -08003504 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003505 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003506 if (cy_isa_address == NULL) {
3507 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3508 "address\n");
3509 continue;
3510 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003511 cy_isa_nchan = CyPORTS_PER_CHIP *
3512 cyy_init_card(cy_isa_address, 0);
3513 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003514 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003515 continue;
3516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517#ifdef MODULE
3518 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003519 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 else
3521#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003522 /* find out the board's irq by probing */
3523 cy_isa_irq = detect_isa_irq(cy_isa_address);
3524 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003525 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3526 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003527 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003528 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003529 continue;
3530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
Jiri Slaby02f11752006-12-08 02:39:28 -08003532 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003533 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3534 "more channels are available. Change NR_PORTS "
3535 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003536 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003537 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003538 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003539 }
3540 /* fill the next cy_card structure available */
3541 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003542 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003543 break;
3544 }
3545 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003546 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3547 "more cards can be used. Change NR_CARDS in "
3548 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003549 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003550 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003551 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
Jiri Slaby02f11752006-12-08 02:39:28 -08003554 /* allocate IRQ */
3555 if (request_irq(cy_isa_irq, cyy_interrupt,
3556 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003557 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3558 "could not allocate IRQ#%d.\n",
3559 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003560 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003561 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
Jiri Slaby02f11752006-12-08 02:39:28 -08003564 /* set cy_card */
3565 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003566 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003567 cy_card[j].irq = (int)cy_isa_irq;
3568 cy_card[j].bus_index = 0;
3569 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003570 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3571 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003572 if (cy_init_card(&cy_card[j])) {
3573 cy_card[j].base_addr = NULL;
3574 free_irq(cy_isa_irq, &cy_card[j]);
3575 iounmap(cy_isa_address);
3576 continue;
3577 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003578 nboard++;
3579
Jiri Slaby21719192007-05-08 00:36:42 -07003580 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3581 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003582 j + 1, (unsigned long)cy_isa_address,
3583 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003584 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3585
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003586 for (j = cy_next_channel;
3587 j < cy_next_channel + cy_isa_nchan; j++)
3588 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003589 cy_next_channel += cy_isa_nchan;
3590 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003591 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003593 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003594#endif /* CONFIG_ISA */
3595} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
Jiri Slaby58936d82007-05-08 00:36:13 -07003597#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003598static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3599{
3600 unsigned int a;
3601
3602 for (a = 0; a < size && *str; a++, str++)
3603 if (*str & 0x80)
3604 return -EINVAL;
3605
3606 for (; a < size; a++, str++)
3607 if (*str)
3608 return -EINVAL;
3609
3610 return 0;
3611}
3612
David Woodhousef61e7612008-05-23 23:57:19 +01003613static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003614 unsigned int size)
3615{
3616 for (; size > 0; size--) {
3617 cy_writel(fpga, *data++);
3618 udelay(10);
3619 }
3620}
3621
3622static void __devinit plx_init(struct pci_dev *pdev, int irq,
3623 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624{
Jiri Slaby02f11752006-12-08 02:39:28 -08003625 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003626 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003627 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003628 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
Jiri Slaby02f11752006-12-08 02:39:28 -08003630 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003631 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003632 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003633 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3634
3635 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3636 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3637 * registers. This will remain here until we find a permanent fix.
3638 */
3639 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3640}
3641
3642static int __devinit __cyz_load_fw(const struct firmware *fw,
3643 const char *name, const u32 mailbox, void __iomem *base,
3644 void __iomem *fpga)
3645{
David Woodhousef61e7612008-05-23 23:57:19 +01003646 const void *ptr = fw->data;
3647 const struct zfile_header *h = ptr;
3648 const struct zfile_config *c, *cs;
3649 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003650 unsigned int a, tmp, len = fw->size;
3651#define BAD_FW KERN_ERR "Bad firmware: "
3652 if (len < sizeof(*h)) {
3653 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3654 return -EINVAL;
3655 }
3656
3657 cs = ptr + h->config_offset;
3658 bs = ptr + h->block_offset;
3659
3660 if ((void *)(cs + h->n_config) > ptr + len ||
3661 (void *)(bs + h->n_blocks) > ptr + len) {
3662 printk(BAD_FW "too short");
3663 return -EINVAL;
3664 }
3665
3666 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3667 cyc_isfwstr(h->date, sizeof(h->date))) {
3668 printk(BAD_FW "bad formatted header string\n");
3669 return -EINVAL;
3670 }
3671
3672 if (strncmp(name, h->name, sizeof(h->name))) {
3673 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3674 return -EINVAL;
3675 }
3676
3677 tmp = 0;
3678 for (c = cs; c < cs + h->n_config; c++) {
3679 for (a = 0; a < c->n_blocks; a++)
3680 if (c->block_list[a] > h->n_blocks) {
3681 printk(BAD_FW "bad block ref number in cfgs\n");
3682 return -EINVAL;
3683 }
3684 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3685 tmp++;
3686 }
3687 if (!tmp) {
3688 printk(BAD_FW "nothing appropriate\n");
3689 return -EINVAL;
3690 }
3691
3692 for (b = bs; b < bs + h->n_blocks; b++)
3693 if (b->file_offset + b->size > len) {
3694 printk(BAD_FW "bad block data offset\n");
3695 return -EINVAL;
3696 }
3697
3698 /* everything is OK, let's seek'n'load it */
3699 for (c = cs; c < cs + h->n_config; c++)
3700 if (c->mailbox == mailbox && c->function == 0)
3701 break;
3702
3703 for (a = 0; a < c->n_blocks; a++) {
3704 b = &bs[c->block_list[a]];
3705 if (b->type == ZBLOCK_FPGA) {
3706 if (fpga != NULL)
3707 cyz_fpga_copy(fpga, ptr + b->file_offset,
3708 b->size);
3709 } else {
3710 if (base != NULL)
3711 memcpy_toio(base + b->ram_offset,
3712 ptr + b->file_offset, b->size);
3713 }
3714 }
3715#undef BAD_FW
3716 return 0;
3717}
3718
3719static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3720 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3721{
3722 const struct firmware *fw;
3723 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3724 struct CUSTOM_REG __iomem *cust = base_addr;
3725 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003726 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003727 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003728 unsigned int i;
3729 int retval;
3730
3731 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3732 if (retval) {
3733 dev_err(&pdev->dev, "can't get firmware\n");
3734 goto err;
3735 }
3736
3737 /* Check whether the firmware is already loaded and running. If
3738 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003739 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003740 u32 cntval = readl(base_addr + 0x190);
3741
3742 udelay(100);
3743 if (cntval != readl(base_addr + 0x190)) {
3744 /* FW counter is working, FW is running */
3745 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3746 "Skipping board.\n");
3747 retval = 0;
3748 goto err_rel;
3749 }
3750 }
3751
3752 /* start boot */
3753 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3754 ~0x00030800UL);
3755
3756 mailbox = readl(&ctl_addr->mail_box_0);
3757
Jiri Slaby2693f482009-06-11 12:31:06 +01003758 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003759 /* stops CPU and set window to beginning of RAM */
3760 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3761 cy_writel(&cust->cpu_stop, 0);
3762 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3763 udelay(100);
3764 }
3765
3766 plx_init(pdev, irq, ctl_addr);
3767
3768 if (mailbox != 0) {
3769 /* load FPGA */
3770 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3771 base_addr);
3772 if (retval)
3773 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003774 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003775 dev_err(&pdev->dev, "fw upload successful, but fw is "
3776 "not loaded\n");
3777 goto err_rel;
3778 }
3779 }
3780
3781 /* stops CPU and set window to beginning of RAM */
3782 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3783 cy_writel(&cust->cpu_stop, 0);
3784 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3785 udelay(100);
3786
3787 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003788 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003789 cy_writeb(tmp, 255);
3790 if (mailbox != 0) {
3791 /* set window to last 512K of RAM */
3792 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003793 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003794 cy_writeb(tmp, 255);
3795 /* set window to beginning of RAM */
3796 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003797 }
3798
3799 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3800 release_firmware(fw);
3801 if (retval)
3802 goto err;
3803
3804 /* finish boot and start boards */
3805 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3806 cy_writel(&cust->cpu_start, 0);
3807 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3808 i = 0;
3809 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3810 msleep(100);
3811 if (status != ZFIRM_ID) {
3812 if (status == ZFIRM_HLT) {
3813 dev_err(&pdev->dev, "you need an external power supply "
3814 "for this number of ports. Firmware halted and "
3815 "board reset.\n");
3816 retval = -EIO;
3817 goto err;
3818 }
3819 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3820 "some more time\n", status);
3821 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3822 i++ < 200)
3823 msleep(100);
3824 if (status != ZFIRM_ID) {
3825 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3826 "Giving up. (fid->signature = 0x%x)\n",
3827 status);
3828 dev_info(&pdev->dev, "*** Warning ***: if you are "
3829 "upgrading the FW, please power cycle the "
3830 "system before loading the new FW to the "
3831 "Cyclades-Z.\n");
3832
Jiri Slaby2693f482009-06-11 12:31:06 +01003833 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003834 plx_init(pdev, irq, ctl_addr);
3835
3836 retval = -EIO;
3837 goto err;
3838 }
3839 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3840 i / 10);
3841 }
3842 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3843
3844 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3845 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3846 base_addr + readl(&fid->zfwctrl_addr));
3847
Jiri Slaby963118e2009-06-11 12:34:27 +01003848 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003849 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003850 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003851
Jiri Slaby963118e2009-06-11 12:34:27 +01003852 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003853 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3854 "check the connection between the Z host card and the "
3855 "serial expanders.\n");
3856
Jiri Slaby2693f482009-06-11 12:31:06 +01003857 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003858 plx_init(pdev, irq, ctl_addr);
3859
3860 dev_info(&pdev->dev, "Null number of ports detected. Board "
3861 "reset.\n");
3862 retval = 0;
3863 goto err;
3864 }
3865
3866 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3867 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3868
3869 /*
3870 Early firmware failed to start looking for commands.
3871 This enables firmware interrupts for those commands.
3872 */
3873 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3874 (1 << 17));
3875 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3876 0x00030800UL);
3877
Jiri Slaby963118e2009-06-11 12:34:27 +01003878 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003879err_rel:
3880 release_firmware(fw);
3881err:
3882 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883}
3884
Jiri Slaby58936d82007-05-08 00:36:13 -07003885static int __devinit cy_pci_probe(struct pci_dev *pdev,
3886 const struct pci_device_id *ent)
3887{
Jiri Slaby31375532007-05-08 00:37:04 -07003888 void __iomem *addr0 = NULL, *addr2 = NULL;
3889 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003890 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003891 unsigned int device_id, nchan = 0, card_no, i;
3892 unsigned char plx_ver;
3893 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003894
3895 retval = pci_enable_device(pdev);
3896 if (retval) {
3897 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003898 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003899 }
3900
3901 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003902 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003903 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3904
Jiri Slaby31375532007-05-08 00:37:04 -07003905#if defined(__alpha__)
3906 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3907 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3908 "addresses on Alpha systems.\n");
3909 retval = -EIO;
3910 goto err_dis;
3911 }
3912#endif
3913 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3914 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3915 "addresses\n");
3916 retval = -EIO;
3917 goto err_dis;
3918 }
3919
3920 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3921 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3922 "it...\n");
3923 pdev->resource[2].flags &= ~IORESOURCE_IO;
3924 }
3925
3926 retval = pci_request_regions(pdev, "cyclades");
3927 if (retval) {
3928 dev_err(&pdev->dev, "failed to reserve resources\n");
3929 goto err_dis;
3930 }
3931
3932 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003933 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3934 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003935 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003936
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003937 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3938 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003939 if (addr0 == NULL) {
3940 dev_err(&pdev->dev, "can't remap ctl region\n");
3941 goto err_reg;
3942 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003943 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3944 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003945 if (addr2 == NULL) {
3946 dev_err(&pdev->dev, "can't remap base region\n");
3947 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003948 }
3949
Jiri Slaby31375532007-05-08 00:37:04 -07003950 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3951 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003952 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3953 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003954 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003955 }
Jiri Slaby31375532007-05-08 00:37:04 -07003956 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3957 struct RUNTIME_9060 __iomem *ctl_addr;
3958
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003959 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3960 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003961 if (addr0 == NULL) {
3962 dev_err(&pdev->dev, "can't remap ctl region\n");
3963 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003964 }
3965
Jiri Slaby31375532007-05-08 00:37:04 -07003966 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003967 cy_writew(&ctl_addr->intr_ctrl_stat,
3968 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003969
Jiri Slaby054f5b02007-07-17 04:05:16 -07003970 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003971
Jiri Slaby101b8152009-06-11 12:30:10 +01003972 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003973
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003974 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3975 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003976 if (addr2 == NULL) {
3977 dev_err(&pdev->dev, "can't remap base region\n");
3978 goto err_unmap;
3979 }
3980
3981 if (mailbox == ZE_V1) {
3982 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003983 } else {
3984 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003985#ifdef CY_PCI_DEBUG
3986 if (mailbox == ZO_V1) {
3987 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3988 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3989 "id %lx, ver %lx\n", (ulong)(0xff &
3990 readl(&((struct CUSTOM_REG *)addr2)->
3991 fpga_id)), (ulong)(0xff &
3992 readl(&((struct CUSTOM_REG *)addr2)->
3993 fpga_version)));
3994 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3995 } else {
3996 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3997 "Cyclades-Z board. FPGA not loaded\n");
3998 }
3999#endif
4000 /* The following clears the firmware id word. This
4001 ensures that the driver will not attempt to talk to
4002 the board until it has been properly initialized.
4003 */
4004 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
4005 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07004006 }
Jiri Slabyace08c32009-06-11 12:20:38 +01004007
4008 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01004009 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01004010 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01004011 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07004012 }
4013
4014 if ((cy_next_channel + nchan) > NR_PORTS) {
4015 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4016 "channels are available. Change NR_PORTS in "
4017 "cyclades.c and recompile kernel.\n");
4018 goto err_unmap;
4019 }
4020 /* fill the next cy_card structure available */
4021 for (card_no = 0; card_no < NR_CARDS; card_no++) {
4022 if (cy_card[card_no].base_addr == NULL)
4023 break;
4024 }
4025 if (card_no == NR_CARDS) { /* no more cy_cards available */
4026 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4027 "more cards can be used. Change NR_CARDS in "
4028 "cyclades.c and recompile kernel.\n");
4029 goto err_unmap;
4030 }
4031
4032 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4033 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004034 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07004035 retval = request_irq(irq, cyy_interrupt,
4036 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07004037 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07004038 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004039 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004040 }
Jiri Slaby963118e2009-06-11 12:34:27 +01004041 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07004042 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004043 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
4044 struct ZFW_CTRL __iomem *zfw_ctrl;
4045
4046 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4047
Jiri Slaby101b8152009-06-11 12:30:10 +01004048 cy_card[card_no].hw_ver = mailbox;
4049 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004050 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07004051#ifdef CONFIG_CYZ_INTR
4052 /* allocate IRQ only if board has an IRQ */
4053 if (irq != 0 && irq != 255) {
4054 retval = request_irq(irq, cyz_interrupt,
4055 IRQF_SHARED, "Cyclades-Z",
4056 &cy_card[card_no]);
4057 if (retval) {
4058 dev_err(&pdev->dev, "could not allocate IRQ\n");
4059 goto err_unmap;
4060 }
4061 }
4062#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07004063 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004064
Jiri Slaby31375532007-05-08 00:37:04 -07004065 /* set cy_card */
4066 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01004067 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07004068 cy_card[card_no].irq = irq;
4069 cy_card[card_no].bus_index = 1;
4070 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01004071 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07004072 retval = cy_init_card(&cy_card[card_no]);
4073 if (retval)
4074 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07004075
Jiri Slaby31375532007-05-08 00:37:04 -07004076 pci_set_drvdata(pdev, &cy_card[card_no]);
4077
4078 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4079 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004080 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07004081 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07004082 switch (plx_ver) {
4083 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07004084 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07004085 break;
4086
4087 case PLX_9060:
4088 case PLX_9080:
4089 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004090 {
4091 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
4092 plx_init(pdev, irq, ctl_addr);
4093 cy_writew(&ctl_addr->intr_ctrl_stat,
4094 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07004095 break;
4096 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01004097 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004098 }
4099
Jiri Slaby31375532007-05-08 00:37:04 -07004100 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
4101 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
4102 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
4103 tty_register_device(cy_serial_driver, i, &pdev->dev);
4104 cy_next_channel += nchan;
4105
Jiri Slaby58936d82007-05-08 00:36:13 -07004106 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07004107err_null:
4108 cy_card[card_no].base_addr = NULL;
4109 free_irq(irq, &cy_card[card_no]);
4110err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004111 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004112 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004113 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07004114err_reg:
4115 pci_release_regions(pdev);
4116err_dis:
4117 pci_disable_device(pdev);
4118err:
4119 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07004120}
Jiri Slaby58936d82007-05-08 00:36:13 -07004121
Jiri Slaby6747cd92007-05-08 00:36:34 -07004122static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123{
Jiri Slaby38d09092007-05-08 00:36:10 -07004124 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07004125 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07004126
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004127 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01004128 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07004129 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01004130 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004131 else
4132#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004133 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004134#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01004135 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
4136 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
4137 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004138
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004139 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004140 if (cinfo->ctl_addr.p9050)
4141 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07004142 if (cinfo->irq
4143#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004144 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07004145#endif /* CONFIG_CYZ_INTR */
4146 )
4147 free_irq(cinfo->irq, cinfo);
4148 pci_release_regions(pdev);
4149
4150 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004151 for (i = cinfo->first_line; i < cinfo->first_line +
4152 cinfo->nports; i++)
4153 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07004154 cinfo->nports = 0;
4155 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07004156}
4157
Jiri Slaby6747cd92007-05-08 00:36:34 -07004158static struct pci_driver cy_pci_driver = {
4159 .name = "cyclades",
4160 .id_table = cy_pci_dev_id,
4161 .probe = cy_pci_probe,
4162 .remove = __devexit_p(cy_pci_remove)
4163};
4164#endif
4165
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004166static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167{
Jiri Slaby02f11752006-12-08 02:39:28 -08004168 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07004169 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08004170 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004172 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08004173 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
Jiri Slaby02f11752006-12-08 02:39:28 -08004175 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07004176 for (i = 0; i < NR_CARDS; i++)
4177 for (j = 0; j < cy_card[i].nports; j++) {
4178 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08004179
Jiri Slabyd13549f2009-09-19 13:13:12 -07004180 if (info->port.count) {
4181 /* XXX is the ldisc num worth this? */
4182 struct tty_struct *tty;
4183 struct tty_ldisc *ld;
4184 int num = 0;
4185 tty = tty_port_tty_get(&info->port);
4186 if (tty) {
4187 ld = tty_ldisc_ref(tty);
4188 if (ld) {
4189 num = ld->ops->num;
4190 tty_ldisc_deref(ld);
4191 }
4192 tty_kref_put(tty);
4193 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004194 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004195 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004196 (cur_jifs - info->idle_stats.in_use) /
4197 HZ, info->idle_stats.xmit_bytes,
4198 (cur_jifs - info->idle_stats.xmit_idle)/
4199 HZ, info->idle_stats.recv_bytes,
4200 (cur_jifs - info->idle_stats.recv_idle)/
4201 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004202 num);
4203 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004204 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004205 "%10lu %8lu %9lu %6ld\n",
4206 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004207 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004208 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209}
4210
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004211static int cyclades_proc_open(struct inode *inode, struct file *file)
4212{
4213 return single_open(file, cyclades_proc_show, NULL);
4214}
4215
4216static const struct file_operations cyclades_proc_fops = {
4217 .owner = THIS_MODULE,
4218 .open = cyclades_proc_open,
4219 .read = seq_read,
4220 .llseek = seq_lseek,
4221 .release = single_release,
4222};
4223
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224/* The serial driver boot-time initialization code!
4225 Hardware I/O ports are mapped to character special devices on a
4226 first found, first allocated manner. That is, this code searches
4227 for Cyclom cards in the system. As each is found, it is probed
4228 to discover how many chips (and thus how many ports) are present.
4229 These ports are mapped to the tty ports 32 and upward in monotonic
4230 fashion. If an 8-port card is replaced with a 16-port card, the
4231 port mapping on a following card will shift.
4232
4233 This approach is different from what is used in the other serial
4234 device driver because the Cyclom is more properly a multiplexer,
4235 not just an aggregation of serial ports on one card.
4236
4237 If there are more cards with more ports than have been
4238 statically allocated above, a warning is printed and the
4239 extra ports are ignored.
4240 */
4241
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004242static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004243 .open = cy_open,
4244 .close = cy_close,
4245 .write = cy_write,
4246 .put_char = cy_put_char,
4247 .flush_chars = cy_flush_chars,
4248 .write_room = cy_write_room,
4249 .chars_in_buffer = cy_chars_in_buffer,
4250 .flush_buffer = cy_flush_buffer,
4251 .ioctl = cy_ioctl,
4252 .throttle = cy_throttle,
4253 .unthrottle = cy_unthrottle,
4254 .set_termios = cy_set_termios,
4255 .stop = cy_stop,
4256 .start = cy_start,
4257 .hangup = cy_hangup,
4258 .break_ctl = cy_break,
4259 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004260 .tiocmget = cy_tiocmget,
4261 .tiocmset = cy_tiocmset,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004262 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263};
4264
Jiri Slaby02f11752006-12-08 02:39:28 -08004265static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
Jiri Slabydd025c02007-05-08 00:37:02 -07004267 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004268 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Jiri Slaby02f11752006-12-08 02:39:28 -08004270 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4271 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004272 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004273
4274 printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
4275 __DATE__, __TIME__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Jiri Slaby02f11752006-12-08 02:39:28 -08004277 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
Jiri Slaby02f11752006-12-08 02:39:28 -08004279 cy_serial_driver->owner = THIS_MODULE;
4280 cy_serial_driver->driver_name = "cyclades";
4281 cy_serial_driver->name = "ttyC";
4282 cy_serial_driver->major = CYCLADES_MAJOR;
4283 cy_serial_driver->minor_start = 0;
4284 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4285 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4286 cy_serial_driver->init_termios = tty_std_termios;
4287 cy_serial_driver->init_termios.c_cflag =
4288 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004289 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004290 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004292 retval = tty_register_driver(cy_serial_driver);
4293 if (retval) {
4294 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4295 goto err_frtty;
4296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297
Jiri Slaby02f11752006-12-08 02:39:28 -08004298 /* the code below is responsible to find the boards. Each different
4299 type of board has its own detection routine. If a board is found,
4300 the next cy_card structure available is set by the detection
4301 routine. These functions are responsible for checking the
4302 availability of cy_card and cy_port data structures and updating
4303 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
Jiri Slaby02f11752006-12-08 02:39:28 -08004305 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004306 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
Jiri Slaby6747cd92007-05-08 00:36:34 -07004308#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004309 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004310 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004311 if (retval && !nboards) {
4312 tty_unregister_driver(cy_serial_driver);
4313 goto err_frtty;
4314 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004315#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004316
4317 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004318err_frtty:
4319 put_tty_driver(cy_serial_driver);
4320err:
4321 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004322} /* cy_init */
4323
4324static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325{
Jiri Slabydd025c02007-05-08 00:37:02 -07004326 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004327 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328
4329#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004330 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331#endif /* CONFIG_CYZ_INTR */
4332
Alan Cox15ed6cc2008-04-30 00:53:55 -07004333 e1 = tty_unregister_driver(cy_serial_driver);
4334 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004335 printk(KERN_ERR "failed to unregister Cyclades serial "
4336 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337
Jiri Slaby6747cd92007-05-08 00:36:34 -07004338#ifdef CONFIG_PCI
4339 pci_unregister_driver(&cy_pci_driver);
4340#endif
4341
Jiri Slaby02f11752006-12-08 02:39:28 -08004342 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004343 card = &cy_card[i];
4344 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004345 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004346 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4347 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004348 if (card->ctl_addr.p9050)
4349 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004350 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004352 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004354 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004355 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004356 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004357 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004358 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004359 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004360 }
4361 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004362
4363 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364} /* cy_cleanup_module */
4365
4366module_init(cy_init);
4367module_exit(cy_cleanup_module);
4368
4369MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004370MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad72009-04-06 17:33:04 +01004371MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);