blob: ed66c3ab230d72a8b7c146ac7298e45220742a8f [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 Remnant9f56fad2009-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;
Jiri Slaby0d348722009-09-19 13:13:16 -0700834 u32 rts, dtr, msvrr, msvrd;
Jiri Slaby4d768202009-09-19 13:13:15 -0700835
836 channel = info->line - card->first_line;
837 chip = channel >> 2;
838 channel &= 0x03;
839 index = card->bus_index;
840 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
841
Jiri Slaby0d348722009-09-19 13:13:16 -0700842 if (info->rtsdtr_inv) {
843 msvrr = CyMSVR2;
844 msvrd = CyMSVR1;
845 rts = CyDTR;
846 dtr = CyRTS;
847 } else {
848 msvrr = CyMSVR1;
849 msvrd = CyMSVR2;
850 rts = CyRTS;
851 dtr = CyDTR;
852 }
Jiri Slaby4d768202009-09-19 13:13:15 -0700853 if (set & TIOCM_RTS) {
Jiri Slaby0d348722009-09-19 13:13:16 -0700854 cy_writeb(base_addr + (CyCAR << index), (u8)channel);
855 cy_writeb(base_addr + (msvrr << index), rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700856 }
857 if (clear & TIOCM_RTS) {
Jiri Slaby0d348722009-09-19 13:13:16 -0700858 cy_writeb(base_addr + (CyCAR << index), (u8)channel);
859 cy_writeb(base_addr + (msvrr << index), ~rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700860 }
861 if (set & TIOCM_DTR) {
Jiri Slaby0d348722009-09-19 13:13:16 -0700862 cy_writeb(base_addr + (CyCAR << index), (u8)channel);
863 cy_writeb(base_addr + (msvrd << index), dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700864#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) {
Jiri Slaby0d348722009-09-19 13:13:16 -0700872 cy_writeb(base_addr + (CyCAR << index), (u8)channel);
873 cy_writeb(base_addr + (msvrd << index), ~dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700874#ifdef CY_DEBUG_DTR
875 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
876 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
877 readb(base_addr + (CyMSVR1 << index)),
878 readb(base_addr + (CyMSVR2 << index)));
879#endif
880 }
881}
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883/***********************************************************/
884/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700885/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886/***********************************************************/
887
888static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800889cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700890 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700892 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800893 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Jiri Slaby97e87f82009-06-11 12:29:27 +0100895 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800896 if (loc_doorbell) {
897 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700898 *channel = readl(&board_ctrl->fwcmd_channel);
899 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100900 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800901 return 1;
902 }
903 return 0;
904} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800907cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700908 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700910 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700911 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700912 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Jiri Slaby2693f482009-06-11 12:31:06 +0100914 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800915 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700916
Jiri Slaby02f11752006-12-08 02:39:28 -0800917 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100918 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700919 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700920 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700921 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800922 udelay(50L);
923 }
924 cy_writel(&board_ctrl->hcmd_channel, channel);
925 cy_writel(&board_ctrl->hcmd_param, param);
926 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800928 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800929} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700931static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700933 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700934 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700935 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800936 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700938 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800940 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700942 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700944 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
945 rx_put = readl(&buf_ctrl->rx_put);
946 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
947 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800948 if (rx_put >= rx_get)
949 char_count = rx_put - rx_get;
950 else
951 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Jiri Slaby02f11752006-12-08 02:39:28 -0800953 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800955 info->mon.int_count++;
956 info->mon.char_count += char_count;
957 if (char_count > info->mon.char_max)
958 info->mon.char_max = char_count;
959 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700961 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800962 /* flush received characters */
963 new_rx_get = (new_rx_get + char_count) &
964 (rx_bufsize - 1);
965 info->rflush_count++;
966 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800968 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
969 for performance, but because of buffer boundaries, there
970 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700971 while (1) {
972 len = tty_prepare_flip_string(tty, &buf,
973 char_count);
974 if (!len)
975 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700977 len = min_t(unsigned int, min(len, char_count),
978 rx_bufsize - new_rx_get);
979
980 memcpy_fromio(buf, cinfo->base_addr +
981 rx_bufaddr + new_rx_get, len);
982
983 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800984 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700985 char_count -= len;
986 info->icount.rx += len;
987 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800990 len = tty_buffer_request_room(tty, char_count);
991 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700992 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800993 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700994 new_rx_get = (new_rx_get + 1) &
995 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800996 tty_insert_flip_char(tty, data, TTY_NORMAL);
997 info->idle_stats.recv_bytes++;
998 info->icount.rx++;
999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000#endif
1001#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001002 /* Recalculate the number of chars in the RX buffer and issue
1003 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001004 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001005 if (rx_put >= rx_get)
1006 char_count = rx_put - rx_get;
1007 else
1008 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001009 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -07001010 !timer_pending(&cyz_rx_full_timer[
1011 info->line]))
1012 mod_timer(&cyz_rx_full_timer[info->line],
1013 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001015 info->idle_stats.recv_idle = jiffies;
1016 tty_schedule_flip(tty);
1017 }
1018 /* Update rx_get */
1019 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021}
1022
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001023static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001025 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001026 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001027 u8 data;
1028 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001030 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001032 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Jiri Slaby02f11752006-12-08 02:39:28 -08001034 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1035 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001037 tx_get = readl(&buf_ctrl->tx_get);
1038 tx_put = readl(&buf_ctrl->tx_put);
1039 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1040 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001041 if (tx_put >= tx_get)
1042 char_count = tx_get - tx_put - 1 + tx_bufsize;
1043 else
1044 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Jiri Slaby02f11752006-12-08 02:39:28 -08001046 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Jiri Slabyf7429032007-05-08 00:36:59 -07001048 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001049 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001050
1051 if (info->x_char) { /* send special char */
1052 data = info->x_char;
1053
1054 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1055 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1056 info->x_char = 0;
1057 char_count--;
1058 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001059 }
1060#ifdef BLOCKMOVE
1061 while (0 < (small_count = min_t(unsigned int,
1062 tx_bufsize - tx_put, min_t(unsigned int,
1063 (SERIAL_XMIT_SIZE - info->xmit_tail),
1064 min_t(unsigned int, info->xmit_cnt,
1065 char_count))))) {
1066
1067 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1068 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001069 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001070 small_count);
1071
1072 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1073 char_count -= small_count;
1074 info->icount.tx += small_count;
1075 info->xmit_cnt -= small_count;
1076 info->xmit_tail = (info->xmit_tail + small_count) &
1077 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001078 }
1079#else
1080 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001081 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001082 info->xmit_cnt--;
1083 info->xmit_tail = (info->xmit_tail + 1) &
1084 (SERIAL_XMIT_SIZE - 1);
1085
1086 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1087 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1088 char_count--;
1089 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001092 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001093ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001094 /* Update tx_put */
1095 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097}
1098
Jiri Slaby02f11752006-12-08 02:39:28 -08001099static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001101 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001102 struct tty_struct *tty;
1103 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001104 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001105 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001106 int special_count;
1107 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001109 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Jiri Slaby02f11752006-12-08 02:39:28 -08001111 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1112 special_count = 0;
1113 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001114 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001115 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001116 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001117 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001118
Jiri Slaby02f11752006-12-08 02:39:28 -08001119 switch (cmd) {
1120 case C_CM_PR_ERROR:
1121 tty_insert_flip_char(tty, 0, TTY_PARITY);
1122 info->icount.rx++;
1123 special_count++;
1124 break;
1125 case C_CM_FR_ERROR:
1126 tty_insert_flip_char(tty, 0, TTY_FRAME);
1127 info->icount.rx++;
1128 special_count++;
1129 break;
1130 case C_CM_RXBRK:
1131 tty_insert_flip_char(tty, 0, TTY_BREAK);
1132 info->icount.rx++;
1133 special_count++;
1134 break;
1135 case C_CM_MDCD:
1136 info->icount.dcd++;
1137 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001138 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001139 u32 dcd = fw_ver > 241 ? param :
1140 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001141 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001142 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001143 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001144 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001145 }
1146 break;
1147 case C_CM_MCTS:
1148 info->icount.cts++;
1149 delta_count++;
1150 break;
1151 case C_CM_MRI:
1152 info->icount.rng++;
1153 delta_count++;
1154 break;
1155 case C_CM_MDSR:
1156 info->icount.dsr++;
1157 delta_count++;
1158 break;
1159#ifdef Z_WAKE
1160 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001161 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001162 break;
1163#endif
1164#ifdef CONFIG_CYZ_INTR
1165 case C_CM_RXHIWM:
1166 case C_CM_RXNNDT:
1167 case C_CM_INTBACK2:
1168 /* Reception Interrupt */
1169#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001170 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1171 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001172#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001173 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001174 break;
1175 case C_CM_TXBEMPTY:
1176 case C_CM_TXLOWWM:
1177 case C_CM_INTBACK:
1178 /* Transmission Interrupt */
1179#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001180 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1181 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001182#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001183 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001184 break;
1185#endif /* CONFIG_CYZ_INTR */
1186 case C_CM_FATAL:
1187 /* should do something with this !!! */
1188 break;
1189 default:
1190 break;
1191 }
1192 if (delta_count)
Jiri Slabyebafeef2007-10-18 03:06:20 -07001193 wake_up_interruptible(&info->delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001194 if (special_count)
1195 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001196 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001197 }
1198}
1199
1200#ifdef CONFIG_CYZ_INTR
1201static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1202{
Jiri Slabyf7429032007-05-08 00:36:59 -07001203 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001204
Jiri Slaby2693f482009-06-11 12:31:06 +01001205 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001206#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001207 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1208 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001209#endif
1210 return IRQ_NONE;
1211 }
1212
1213 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 cyz_handle_cmd(cinfo);
1215
Jiri Slaby02f11752006-12-08 02:39:28 -08001216 return IRQ_HANDLED;
1217} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Jiri Slaby02f11752006-12-08 02:39:28 -08001219static void cyz_rx_restart(unsigned long arg)
1220{
1221 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001222 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001223 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001224 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001225 unsigned long flags;
1226
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001227 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001228 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001229 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001230 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001231 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001233 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001234}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Jiri Slaby02f11752006-12-08 02:39:28 -08001236#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Jiri Slaby02f11752006-12-08 02:39:28 -08001238static void cyz_poll(unsigned long arg)
1239{
1240 struct cyclades_card *cinfo;
1241 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001242 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001243 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001244
Jiri Slaby02f11752006-12-08 02:39:28 -08001245 for (card = 0; card < NR_CARDS; card++) {
1246 cinfo = &cy_card[card];
1247
Jiri Slaby2693f482009-06-11 12:31:06 +01001248 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001249 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001250 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001251 continue;
1252
Jiri Slaby02f11752006-12-08 02:39:28 -08001253 /* Skip first polling cycle to avoid racing conditions with the FW */
1254 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001255 cinfo->intr_enabled = 1;
1256 continue;
1257 }
1258
1259 cyz_handle_cmd(cinfo);
1260
1261 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001262 struct tty_struct *tty;
1263
Jiri Slabydd025c02007-05-08 00:37:02 -07001264 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001265 tty = tty_port_tty_get(&info->port);
1266 /* OK to pass NULL to the handle functions below.
1267 They need to drop the data in that case. */
1268
Jiri Slaby02f11752006-12-08 02:39:28 -08001269 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001270 cyz_handle_rx(info, tty);
1271 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001272 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001273 }
1274 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001275 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001276 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001277 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001278} /* cyz_poll */
1279
1280#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
1282/********** End of block of Cyclades-Z specific code *********/
1283/***********************************************************/
1284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285/* This is called whenever a port becomes active;
1286 interrupts are enabled and DTR & RTS are turned on.
1287 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001288static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
Jiri Slaby875b2062007-05-08 00:36:49 -07001290 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001291 unsigned long flags;
1292 int retval = 0;
1293 void __iomem *base_addr;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001294 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001295 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Jiri Slaby02f11752006-12-08 02:39:28 -08001297 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001298 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Jiri Slaby02f11752006-12-08 02:39:28 -08001300 page = get_zeroed_page(GFP_KERNEL);
1301 if (!page)
1302 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001304 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001306 if (info->port.flags & ASYNC_INITIALIZED)
Jiri Slaby02f11752006-12-08 02:39:28 -08001307 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001308
1309 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001310 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001311 goto errout;
1312 }
1313
Alan Cox77451e52008-07-16 21:57:02 +01001314 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001315 free_page(page);
1316 else
Alan Cox77451e52008-07-16 21:57:02 +01001317 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001319 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Jiri Slabyd13549f2009-09-19 13:13:12 -07001321 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Jiri Slaby2693f482009-06-11 12:31:06 +01001323 if (!cy_is_Z(card)) {
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001324 int chip = channel >> 2;
1325 int index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001326 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001327 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001330 printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
1331 "base_addr %p\n",
1332 card, chip, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001333#endif
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001334 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001335
1336 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1337
1338 cy_writeb(base_addr + (CyRTPR << index),
1339 (info->default_timeout ? info->default_timeout : 0x02));
1340 /* 10ms rx timeout */
1341
1342 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
1343 index);
1344
Jiri Slaby4d768202009-09-19 13:13:15 -07001345 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Jiri Slaby02f11752006-12-08 02:39:28 -08001347 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001348 readb(base_addr + (CySRER << index)) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001349 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001350 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001351
Jiri Slaby2693f482009-06-11 12:31:06 +01001352 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001353 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001354
Jiri Slaby02f11752006-12-08 02:39:28 -08001355#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001356 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001357 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001358#endif
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001359 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001360
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001361 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362#ifdef Z_WAKE
1363#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001364 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001365 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1366 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001368 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001369 C_IN_IOCTLW | C_IN_MDCD);
1370#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371#else
1372#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001373 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001374 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1375 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001377 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001378#endif /* CONFIG_CYZ_INTR */
1379#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Jiri Slaby875b2062007-05-08 00:36:49 -07001381 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001382 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001383 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1384 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Jiri Slaby02f11752006-12-08 02:39:28 -08001387 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001388 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001389 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001390 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1391 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Jiri Slaby02f11752006-12-08 02:39:28 -08001394 /* set timeout !!! */
1395 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001396 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Jiri Slaby02f11752006-12-08 02:39:28 -08001398 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001401 info->port.flags |= ASYNC_INITIALIZED;
1402
1403 clear_bit(TTY_IO_ERROR, &tty->flags);
1404 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1405 info->breakon = info->breakoff = 0;
1406 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1407 info->idle_stats.in_use =
1408 info->idle_stats.recv_idle =
1409 info->idle_stats.xmit_idle = jiffies;
1410
1411 spin_unlock_irqrestore(&card->card_lock, flags);
1412
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001414 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415#endif
1416 return 0;
1417
1418errout:
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001419 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001420 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001422} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Jiri Slaby02f11752006-12-08 02:39:28 -08001424static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425{
Jiri Slaby875b2062007-05-08 00:36:49 -07001426 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001427 unsigned long flags;
1428 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001429 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Jiri Slaby02f11752006-12-08 02:39:28 -08001431 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001432 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001433 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001434 chip = channel >> 2;
1435 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001436 index = card->bus_index;
1437 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001439 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001440 cy_writeb(base_addr + (CyCAR << index), channel);
1441 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001442 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001443 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001444 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001446 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001448 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001449 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001450 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001451 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1452 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001453 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001454 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001455#else /* CONFIG_CYZ_INTR */
1456 /* Don't have to do anything at this time */
1457#endif /* CONFIG_CYZ_INTR */
1458 }
1459} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
1461/*
1462 * This routine shuts down a serial port; interrupts are disabled,
1463 * and DTR is dropped if the hangup on close termio flag is on.
1464 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001465static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466{
Jiri Slaby875b2062007-05-08 00:36:49 -07001467 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001468 unsigned long flags;
1469 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001470 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Alan Cox77451e52008-07-16 21:57:02 +01001472 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001473 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Jiri Slaby02f11752006-12-08 02:39:28 -08001475 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001476 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001477 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001478 chip = channel >> 2;
1479 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001480 index = card->bus_index;
1481 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
1483#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001484 printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
1485 "channel %d, base_addr %p\n",
1486 card, chip, channel, base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001489 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001490
1491 /* Clear delta_msr_wait queue to avoid mem leaks. */
1492 wake_up_interruptible(&info->delta_msr_wait);
1493
Alan Cox77451e52008-07-16 21:57:02 +01001494 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001495 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001496 temp = info->port.xmit_buf;
1497 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001498 free_page((unsigned long)temp);
1499 }
Jiri Slaby4d768202009-09-19 13:13:15 -07001500 if (tty->termios->c_cflag & HUPCL)
1501 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1502
Jiri Slaby02f11752006-12-08 02:39:28 -08001503 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
1504 /* it may be appropriate to clear _XMIT at
1505 some later date (after testing)!!! */
1506
Jiri Slabyd13549f2009-09-19 13:13:12 -07001507 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001508 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001509 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001510 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001511#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001512 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001513 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001514#endif
1515
Jiri Slaby2693f482009-06-11 12:31:06 +01001516 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001517 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001518
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001519 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001520
Alan Cox77451e52008-07-16 21:57:02 +01001521 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001522 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001523 temp = info->port.xmit_buf;
1524 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001525 free_page((unsigned long)temp);
1526 }
1527
Jiri Slaby4d768202009-09-19 13:13:15 -07001528 if (tty->termios->c_cflag & HUPCL)
1529 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001530
Jiri Slabyd13549f2009-09-19 13:13:12 -07001531 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001532 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001533
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001534 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001535 }
1536
1537#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001538 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001539#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001540} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
1542/*
1543 * ------------------------------------------------------------
1544 * cy_open() and friends
1545 * ------------------------------------------------------------
1546 */
1547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548/*
1549 * This routine is called whenever a serial port is opened. It
1550 * performs the serial-specific initialization for the tty structure.
1551 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001552static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553{
Jiri Slaby02f11752006-12-08 02:39:28 -08001554 struct cyclades_port *info;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001555 unsigned int i, line;
1556 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
Jiri Slaby02f11752006-12-08 02:39:28 -08001558 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001559 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001561
Jiri Slabydd025c02007-05-08 00:37:02 -07001562 for (i = 0; i < NR_CARDS; i++)
1563 if (line < cy_card[i].first_line + cy_card[i].nports &&
1564 line >= cy_card[i].first_line)
1565 break;
1566 if (i >= NR_CARDS)
1567 return -ENODEV;
1568 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001569 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001570 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001571
1572 /* If the card's firmware hasn't been loaded,
1573 treat it as absent from the system. This
1574 will make the user pay attention.
1575 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001576 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001577 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001578 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1579
Jiri Slaby2693f482009-06-11 12:31:06 +01001580 if (!cyz_is_loaded(cinfo)) {
1581 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001582 readl(&firm_id->signature) ==
1583 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001584 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1585 "need an external power supply for "
1586 "this number of ports.\nFirmware "
1587 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001588 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001589 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1590 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001591 }
1592 return -ENODEV;
1593 }
1594#ifdef CONFIG_CYZ_INTR
1595 else {
1596 /* In case this Z board is operating in interrupt mode, its
1597 interrupts should be enabled as soon as the first open
1598 happens to one of its ports. */
1599 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001600 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001601
Jiri Slaby02f11752006-12-08 02:39:28 -08001602 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001603 intr = readw(&cinfo->ctl_addr.p9060->
1604 intr_ctrl_stat) | 0x0900;
1605 cy_writew(&cinfo->ctl_addr.p9060->
1606 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001607 /* Enable interrupts on the FW */
1608 retval = cyz_issue_cmd(cinfo, 0,
1609 C_CM_IRQ_ENBL, 0L);
1610 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001611 printk(KERN_ERR "cyc:IRQ enable retval "
1612 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001613 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001614 cinfo->intr_enabled = 1;
1615 }
1616 }
1617#endif /* CONFIG_CYZ_INTR */
1618 /* Make sure this Z port really exists in hardware */
1619 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1620 return -ENODEV;
1621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001623 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001625 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001626 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001627 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001628
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001630 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001631 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632#endif
Alan Cox77451e52008-07-16 21:57:02 +01001633 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001635 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001636 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
Jiri Slaby02f11752006-12-08 02:39:28 -08001639 /*
1640 * If the port is the middle of closing, bail out now
1641 */
Alan Cox77451e52008-07-16 21:57:02 +01001642 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1643 wait_event_interruptible(info->port.close_wait,
1644 !(info->port.flags & ASYNC_CLOSING));
1645 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Jiri Slaby02f11752006-12-08 02:39:28 -08001648 /*
1649 * Start up serial port
1650 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001651 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001652 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001653 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
Jiri Slabyf0737572009-09-19 13:13:12 -07001655 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001656 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001658 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1659 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001661 return retval;
1662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Jiri Slaby02f11752006-12-08 02:39:28 -08001664 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001665 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001668 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001670 return 0;
1671} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673/*
1674 * cy_wait_until_sent() --- wait until the transmitter is empty
1675 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001676static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677{
Jiri Slaby875b2062007-05-08 00:36:49 -07001678 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001679 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001680 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001681 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001682 unsigned long orig_jiffies;
1683 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Jiri Slaby02f11752006-12-08 02:39:28 -08001685 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1686 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Jiri Slaby02f11752006-12-08 02:39:28 -08001688 if (info->xmit_fifo_size == 0)
1689 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Jiri Slaby02f11752006-12-08 02:39:28 -08001691 orig_jiffies = jiffies;
Alan Cox978e5952008-04-30 00:53:59 -07001692 lock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08001693 /*
1694 * Set the check interval to be 1/5 of the estimated time to
1695 * send a single character, and make it at least 1. The check
1696 * interval should also be less than the timeout.
1697 *
1698 * Note: we have to use pretty tight timings here to satisfy
1699 * the NIST-PCTS.
1700 */
1701 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1702 char_time = char_time / 5;
1703 if (char_time <= 0)
1704 char_time = 1;
1705 if (timeout < 0)
1706 timeout = 0;
1707 if (timeout)
1708 char_time = min(char_time, timeout);
1709 /*
1710 * If the transmitter hasn't cleared in twice the approximate
1711 * amount of time to send the entire FIFO, it probably won't
1712 * ever clear. This assumes the UART isn't doing flow
1713 * control, which is currently the case. Hence, if it ever
1714 * takes longer than info->timeout, this is probably due to a
1715 * UART bug of some kind. So, we clamp the timeout parameter at
1716 * 2*info->timeout.
1717 */
1718 if (!timeout || timeout > 2 * info->timeout)
1719 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001721 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1722 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001724 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001725 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01001726 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001727 chip = channel >> 2;
1728 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001729 index = card->bus_index;
1730 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001731 while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001733 printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001735 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1736 break;
1737 if (timeout && time_after(jiffies, orig_jiffies +
1738 timeout))
1739 break;
1740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001742 /* Run one more char cycle */
1743 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Alan Cox978e5952008-04-30 00:53:59 -07001744 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001746 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747#endif
1748}
1749
Alan Cox978e5952008-04-30 00:53:59 -07001750static void cy_flush_buffer(struct tty_struct *tty)
1751{
1752 struct cyclades_port *info = tty->driver_data;
1753 struct cyclades_card *card;
1754 int channel, retval;
1755 unsigned long flags;
1756
1757#ifdef CY_DEBUG_IO
1758 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1759#endif
1760
1761 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1762 return;
1763
1764 card = info->card;
1765 channel = info->line - card->first_line;
1766
1767 spin_lock_irqsave(&card->card_lock, flags);
1768 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1769 spin_unlock_irqrestore(&card->card_lock, flags);
1770
Jiri Slaby2693f482009-06-11 12:31:06 +01001771 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001772 buffers as well */
1773 spin_lock_irqsave(&card->card_lock, flags);
1774 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1775 if (retval != 0) {
1776 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1777 "was %x\n", info->line, retval);
1778 }
1779 spin_unlock_irqrestore(&card->card_lock, flags);
1780 }
1781 tty_wakeup(tty);
1782} /* cy_flush_buffer */
1783
1784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785/*
1786 * This routine is called when a particular tty device is closed.
1787 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001788static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001790 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001791 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001792 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Alan Cox15ed6cc2008-04-30 00:53:55 -07001794 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001795 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001797 card = info->card;
1798
Jiri Slaby23342262009-09-19 13:13:13 -07001799 if (!tty_port_close_start(&info->port, tty, filp))
Jiri Slaby02f11752006-12-08 02:39:28 -08001800 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001801
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001802 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001803
Jiri Slaby2693f482009-06-11 12:31:06 +01001804 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001805 int channel = info->line - card->first_line;
1806 int index = card->bus_index;
1807 void __iomem *base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001808 (cy_chip_offset[channel >> 2] << index);
1809 /* Stop accepting input */
1810 channel &= 0x03;
1811 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1812 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001813 readb(base_addr + (CySRER << index)) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001814 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001815 /* Waiting for on-board buffers to be empty before
1816 closing the port */
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001817 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001818 cy_wait_until_sent(tty, info->timeout);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001819 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001820 }
1821 } else {
1822#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001823 /* Waiting for on-board buffers to be empty before closing
1824 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001825 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001826 int channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001827 int retval;
1828
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001829 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001830 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001831 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001832 printk(KERN_DEBUG "cyc:cy_close retval on "
1833 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001834 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001835 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001836 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001837 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001838 }
1839#endif
1840 }
1841
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001842 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001843 cy_shutdown(info, tty);
Alan Cox978e5952008-04-30 00:53:59 -07001844 cy_flush_buffer(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001845
Jiri Slabyd13549f2009-09-19 13:13:12 -07001846 tty_port_tty_set(&info->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
Jiri Slaby23342262009-09-19 13:13:13 -07001848 tty_port_close_end(&info->port, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001849} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851/* This routine gets called when tty_write has put something into
1852 * the write_queue. The characters may come from user space or
1853 * kernel space.
1854 *
1855 * This routine will return the number of characters actually
1856 * accepted for writing.
1857 *
1858 * If the port is not already transmitting stuff, start it off by
1859 * enabling interrupts. The interrupt service routine will then
1860 * ensure that the characters are sent.
1861 * If the port is already active, there is no need to kick it.
1862 *
1863 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001864static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001866 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001867 unsigned long flags;
1868 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001871 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872#endif
1873
Alan Cox15ed6cc2008-04-30 00:53:55 -07001874 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
Alan Cox77451e52008-07-16 21:57:02 +01001877 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001878 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001880 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001881 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001882 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1883 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Jiri Slaby02f11752006-12-08 02:39:28 -08001885 if (c <= 0)
1886 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
Alan Cox77451e52008-07-16 21:57:02 +01001888 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001889 info->xmit_head = (info->xmit_head + c) &
1890 (SERIAL_XMIT_SIZE - 1);
1891 info->xmit_cnt += c;
1892 buf += c;
1893 count -= c;
1894 ret += c;
1895 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001896 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Jiri Slaby02f11752006-12-08 02:39:28 -08001898 info->idle_stats.xmit_bytes += ret;
1899 info->idle_stats.xmit_idle = jiffies;
1900
Alan Cox15ed6cc2008-04-30 00:53:55 -07001901 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001902 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001903
Jiri Slaby02f11752006-12-08 02:39:28 -08001904 return ret;
1905} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907/*
1908 * This routine is called by the kernel to write a single
1909 * character to the tty device. If the kernel uses this routine,
1910 * it must call the flush_chars() routine (if defined) when it is
1911 * done stuffing characters into the driver. If there is no room
1912 * in the queue, the character is ignored.
1913 */
Alan Cox76b25a52008-04-30 00:54:03 -07001914static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001916 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001917 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001920 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921#endif
1922
Jiri Slaby02f11752006-12-08 02:39:28 -08001923 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001924 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
Alan Cox77451e52008-07-16 21:57:02 +01001926 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001927 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001929 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001930 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001931 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001932 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Alan Cox77451e52008-07-16 21:57:02 +01001935 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001936 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1937 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 info->idle_stats.xmit_bytes++;
1939 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001940 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001941 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001942} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
1944/*
1945 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001946 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001948static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001950 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001953 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954#endif
1955
Jiri Slaby02f11752006-12-08 02:39:28 -08001956 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1957 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Jiri Slaby02f11752006-12-08 02:39:28 -08001959 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001960 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001961 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
Jiri Slaby02f11752006-12-08 02:39:28 -08001963 start_xmit(info);
1964} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
1966/*
1967 * This routine returns the numbers of characters the tty driver
1968 * will accept for queuing to be written. This number is subject
1969 * to change as output buffers get emptied, or if the output flow
1970 * control is activated.
1971 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001972static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001974 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001975 int ret;
1976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001978 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979#endif
1980
Jiri Slaby02f11752006-12-08 02:39:28 -08001981 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1982 return 0;
1983 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1984 if (ret < 0)
1985 ret = 0;
1986 return ret;
1987} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Jiri Slaby02f11752006-12-08 02:39:28 -08001989static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001991 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
Jiri Slaby02f11752006-12-08 02:39:28 -08001993 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1994 return 0;
1995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001997 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001998#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002000 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2001 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002003 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002005 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002006 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002007 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07002008 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009
Alan Cox978e5952008-04-30 00:53:59 -07002010 lock_kernel();
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002011 tx_get = readl(&buf_ctrl->tx_get);
2012 tx_put = readl(&buf_ctrl->tx_put);
2013 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08002014 if (tx_put >= tx_get)
2015 char_count = tx_put - tx_get;
2016 else
2017 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002019 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2020 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021#endif
Alan Cox978e5952008-04-30 00:53:59 -07002022 unlock_kernel();
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002023 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08002024 }
2025#endif /* Z_EXT_CHARS_IN_BUFFER */
2026} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028/*
2029 * ------------------------------------------------------------
2030 * cy_ioctl() and friends
2031 * ------------------------------------------------------------
2032 */
2033
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002034static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035{
Jiri Slaby02f11752006-12-08 02:39:28 -08002036 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002037 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08002038 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
Jiri Slaby02f11752006-12-08 02:39:28 -08002040 if (baud == 0) {
2041 info->tbpr = info->tco = info->rbpr = info->rco = 0;
2042 return;
2043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Jiri Slaby02f11752006-12-08 02:39:28 -08002045 /* determine which prescaler to use */
2046 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
2047 if (cy_clock / co_val / baud > 63)
2048 break;
2049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
Jiri Slaby02f11752006-12-08 02:39:28 -08002051 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
2052 if (bpr > 255)
2053 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054
Jiri Slaby02f11752006-12-08 02:39:28 -08002055 info->tbpr = info->rbpr = bpr;
2056 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057}
2058
2059/*
2060 * This routine finds or computes the various line characteristics.
2061 * It used to be called config_setup
2062 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002063static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
Jiri Slaby875b2062007-05-08 00:36:49 -07002065 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002066 unsigned long flags;
2067 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002068 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002069 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002070 int baud, baud_rate = 0;
2071 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Jiri Slabyd13549f2009-09-19 13:13:12 -07002073 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002074 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002075
2076 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002077 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002078
Jiri Slabyd13549f2009-09-19 13:13:12 -07002079 cflag = tty->termios->c_cflag;
2080 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Jiri Slaby02f11752006-12-08 02:39:28 -08002082 /*
2083 * Set up the tty->alt_speed kludge
2084 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002085 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2086 tty->alt_speed = 57600;
2087 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2088 tty->alt_speed = 115200;
2089 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2090 tty->alt_speed = 230400;
2091 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2092 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Jiri Slaby02f11752006-12-08 02:39:28 -08002094 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002095 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002096
Jiri Slaby2693f482009-06-11 12:31:06 +01002097 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002098
Jiri Slaby875b2062007-05-08 00:36:49 -07002099 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002100
2101 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002102 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002103 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002104 ASYNC_SPD_CUST) {
2105 if (info->custom_divisor)
2106 baud_rate = info->baud / info->custom_divisor;
2107 else
2108 baud_rate = info->baud;
2109 } else if (baud > CD1400_MAX_SPEED) {
2110 baud = CD1400_MAX_SPEED;
2111 }
2112 /* find the baud index */
2113 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002114 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002115 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002116 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002117 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002118 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002119
Alan Cox77451e52008-07-16 21:57:02 +01002120 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002121 ASYNC_SPD_CUST) {
2122 cyy_baud_calc(info, baud_rate);
2123 } else {
2124 if (info->chip_rev >= CD1400_REV_J) {
2125 /* It is a CD1400 rev. J or later */
2126 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2127 info->tco = baud_co_60[i]; /* Tx CO */
2128 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2129 info->rco = baud_co_60[i]; /* Rx CO */
2130 } else {
2131 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2132 info->tco = baud_co_25[i]; /* Tx CO */
2133 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2134 info->rco = baud_co_25[i]; /* Rx CO */
2135 }
2136 }
2137 if (baud_table[i] == 134) {
2138 /* get it right for 134.5 baud */
2139 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2140 2;
Alan Cox77451e52008-07-16 21:57:02 +01002141 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002142 ASYNC_SPD_CUST) {
2143 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2144 baud_rate) + 2;
2145 } else if (baud_table[i]) {
2146 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2147 baud_table[i]) + 2;
2148 /* this needs to be propagated into the card info */
2149 } else {
2150 info->timeout = 0;
2151 }
2152 /* By tradition (is it a standard?) a baud rate of zero
2153 implies the line should be/has been closed. A bit
2154 later in this routine such a test is performed. */
2155
2156 /* byte size and parity */
2157 info->cor5 = 0;
2158 info->cor4 = 0;
2159 /* receive threshold */
2160 info->cor3 = (info->default_threshold ?
2161 info->default_threshold : baud_cor3[i]);
2162 info->cor2 = CyETC;
2163 switch (cflag & CSIZE) {
2164 case CS5:
2165 info->cor1 = Cy_5_BITS;
2166 break;
2167 case CS6:
2168 info->cor1 = Cy_6_BITS;
2169 break;
2170 case CS7:
2171 info->cor1 = Cy_7_BITS;
2172 break;
2173 case CS8:
2174 info->cor1 = Cy_8_BITS;
2175 break;
2176 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002177 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002178 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002179
Jiri Slaby02f11752006-12-08 02:39:28 -08002180 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002181 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002182 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002183 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002184 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002185 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002186 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002187
2188 /* CTS flow control flag */
2189 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002190 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002191 info->cor2 |= CyCtsAE;
2192 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002193 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002194 info->cor2 &= ~CyCtsAE;
2195 }
2196 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002197 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002198 else
Alan Cox77451e52008-07-16 21:57:02 +01002199 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
2201 /***********************************************
2202 The hardware option, CyRtsAO, presents RTS when
2203 the chip has characters to send. Since most modems
2204 use RTS as reverse (inbound) flow control, this
2205 option is not used. If inbound flow control is
2206 necessary, DTR can be programmed to provide the
2207 appropriate signals for use with a non-standard
2208 cable. Contact Marcio Saito for details.
2209 ***********************************************/
2210
Jiri Slaby02f11752006-12-08 02:39:28 -08002211 chip = channel >> 2;
2212 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002213 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002215 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Jiri Slaby02f11752006-12-08 02:39:28 -08002218 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Jiri Slaby02f11752006-12-08 02:39:28 -08002220 cy_writeb(base_addr + (CyTCOR << index), info->tco);
2221 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
2222 cy_writeb(base_addr + (CyRCOR << index), info->rco);
2223 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Jiri Slaby02f11752006-12-08 02:39:28 -08002225 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
Jiri Slabyd13549f2009-09-19 13:13:12 -07002227 cy_writeb(base_addr + (CySCHR1 << index), START_CHAR(tty));
2228 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(tty));
Jiri Slaby02f11752006-12-08 02:39:28 -08002229 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
2230 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
2231 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2232 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
2233 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Jiri Slaby02f11752006-12-08 02:39:28 -08002235 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2236 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Alan Cox15ed6cc2008-04-30 00:53:55 -07002238 /* !!! Is this needed? */
2239 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08002240 cy_writeb(base_addr + (CyRTPR << index),
2241 (info->default_timeout ? info->default_timeout : 0x02));
2242 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
Jiri Slabyd13549f2009-09-19 13:13:12 -07002244 if (C_CLOCAL(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002245 /* without modem intr */
2246 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002247 readb(base_addr + (CySRER << index)) | CyMdmCh);
Jiri Slaby02f11752006-12-08 02:39:28 -08002248 /* act on 1->0 modem transitions */
2249 if ((cflag & CRTSCTS) && info->rflow) {
2250 cy_writeb(base_addr + (CyMCOR1 << index),
2251 (CyCTS | rflow_thr[i]));
2252 } else {
2253 cy_writeb(base_addr + (CyMCOR1 << index),
2254 CyCTS);
2255 }
2256 /* act on 0->1 modem transitions */
2257 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002259 /* without modem intr */
2260 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002261 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002262 (CySRER << index)) | CyMdmCh);
2263 /* act on 1->0 modem transitions */
2264 if ((cflag & CRTSCTS) && info->rflow) {
2265 cy_writeb(base_addr + (CyMCOR1 << index),
2266 (CyDSR | CyCTS | CyRI | CyDCD |
2267 rflow_thr[i]));
2268 } else {
2269 cy_writeb(base_addr + (CyMCOR1 << index),
2270 CyDSR | CyCTS | CyRI | CyDCD);
2271 }
2272 /* act on 0->1 modem transitions */
2273 cy_writeb(base_addr + (CyMCOR2 << index),
2274 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002276
Jiri Slaby4d768202009-09-19 13:13:15 -07002277 if (i == 0) /* baud rate is zero, turn off line */
2278 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2279 else
2280 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
Jiri Slabyd13549f2009-09-19 13:13:12 -07002282 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002283 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002286 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002287 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002288 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
Jiri Slaby2693f482009-06-11 12:31:06 +01002290 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002291 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Jiri Slaby02f11752006-12-08 02:39:28 -08002293 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002294 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002295 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002296 ASYNC_SPD_CUST) {
2297 if (info->custom_divisor)
2298 baud_rate = info->baud / info->custom_divisor;
2299 else
2300 baud_rate = info->baud;
2301 } else if (baud > CYZ_MAX_SPEED) {
2302 baud = CYZ_MAX_SPEED;
2303 }
2304 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
Jiri Slaby02f11752006-12-08 02:39:28 -08002306 if (baud == 134) {
2307 /* get it right for 134.5 baud */
2308 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2309 2;
Alan Cox77451e52008-07-16 21:57:02 +01002310 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002311 ASYNC_SPD_CUST) {
2312 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2313 baud_rate) + 2;
2314 } else if (baud) {
2315 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2316 baud) + 2;
2317 /* this needs to be propagated into the card info */
2318 } else {
2319 info->timeout = 0;
2320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Jiri Slaby02f11752006-12-08 02:39:28 -08002322 /* byte size and parity */
2323 switch (cflag & CSIZE) {
2324 case CS5:
2325 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2326 break;
2327 case CS6:
2328 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2329 break;
2330 case CS7:
2331 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2332 break;
2333 case CS8:
2334 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2335 break;
2336 }
2337 if (cflag & CSTOPB) {
2338 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002339 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002340 } else {
2341 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002342 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002343 }
2344 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002345 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002346 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002347 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002348 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002349 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002350 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Jiri Slaby02f11752006-12-08 02:39:28 -08002352 /* CTS flow control flag */
2353 if (cflag & CRTSCTS) {
2354 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002355 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002356 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002357 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2358 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002359 }
2360 /* As the HW flow control is done in firmware, the driver
2361 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002362 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002363
2364 /* XON/XOFF/XANY flow control flags */
2365 sw_flow = 0;
2366 if (iflag & IXON) {
2367 sw_flow |= C_FL_OXX;
2368 if (iflag & IXANY)
2369 sw_flow |= C_FL_OIXANY;
2370 }
2371 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2372
Jiri Slaby875b2062007-05-08 00:36:49 -07002373 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002374 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002375 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2376 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002377 }
2378
2379 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002380 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002381 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002382 else
Alan Cox77451e52008-07-16 21:57:02 +01002383 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002384
2385 if (baud == 0) { /* baud rate is zero, turn off line */
2386 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002387 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002389 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002391 } else {
2392 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002393 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002395 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
Alan Cox15ed6cc2008-04-30 00:53:55 -07002399 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002400 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002401 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2402 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Jiri Slabyd13549f2009-09-19 13:13:12 -07002405 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002407} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
Jiri Slaby6c281812009-09-19 13:13:15 -07002409static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002410 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411{
Jiri Slaby875b2062007-05-08 00:36:49 -07002412 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002413 struct serial_struct tmp = {
2414 .type = info->type,
2415 .line = info->line,
2416 .port = (info->card - cy_card) * 0x100 + info->line -
2417 cinfo->first_line,
2418 .irq = cinfo->irq,
2419 .flags = info->port.flags,
2420 .close_delay = info->port.close_delay,
2421 .closing_wait = info->port.closing_wait,
2422 .baud_base = info->baud,
2423 .custom_divisor = info->custom_divisor,
2424 .hub6 = 0, /*!!! */
2425 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002426 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002427}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
2429static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002430cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002431 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432{
Jiri Slaby02f11752006-12-08 02:39:28 -08002433 struct serial_struct new_serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Jiri Slaby02f11752006-12-08 02:39:28 -08002435 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2436 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Jiri Slaby02f11752006-12-08 02:39:28 -08002438 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002439 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002440 new_serial.baud_base != info->baud ||
2441 (new_serial.flags & ASYNC_FLAGS &
2442 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002443 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Jiri Slaby02f11752006-12-08 02:39:28 -08002444 return -EPERM;
Alan Cox77451e52008-07-16 21:57:02 +01002445 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002446 (new_serial.flags & ASYNC_USR_MASK);
2447 info->baud = new_serial.baud_base;
2448 info->custom_divisor = new_serial.custom_divisor;
2449 goto check_and_exit;
2450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
Jiri Slaby02f11752006-12-08 02:39:28 -08002452 /*
2453 * OK, past this point, all the error checking has been done.
2454 * At this point, we start making changes.....
2455 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Jiri Slaby02f11752006-12-08 02:39:28 -08002457 info->baud = new_serial.baud_base;
2458 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002459 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002460 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002461 info->port.close_delay = new_serial.close_delay * HZ / 100;
2462 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002465 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002466 cy_set_line_char(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002467 return 0;
2468 } else {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002469 return cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002470 }
2471} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473/*
2474 * get_lsr_info - get line status register info
2475 *
2476 * Purpose: Let user call ioctl() to get info when the UART physically
2477 * is emptied. On bus types like RS485, the transmitter must
2478 * release the bus after transmitting. This must be done when
2479 * the transmit shift register is empty, not be done when the
2480 * transmit holding register is empty. This functionality
2481 * allows an RS485 driver to be written in user space.
2482 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002483static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484{
Jiri Slaby875b2062007-05-08 00:36:49 -07002485 struct cyclades_card *card;
2486 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002487 unsigned char status;
2488 unsigned int result;
2489 unsigned long flags;
2490 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
Jiri Slaby02f11752006-12-08 02:39:28 -08002492 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002493 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002494 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002495 chip = channel >> 2;
2496 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002497 index = card->bus_index;
2498 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002500 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002501 status = readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002502 (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002503 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002504 result = (status ? 0 : TIOCSER_TEMT);
2505 } else {
2506 /* Not supported yet */
2507 return -EINVAL;
2508 }
2509 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510}
2511
Jiri Slaby02f11752006-12-08 02:39:28 -08002512static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002514 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002515 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002516 void __iomem *base_addr;
Jiri Slaby0d348722009-09-19 13:13:16 -07002517 int result, channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002519 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002520 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Jiri Slaby02f11752006-12-08 02:39:28 -08002522 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002523 channel = info->line - card->first_line;
Jiri Slaby0d348722009-09-19 13:13:16 -07002524
2525 lock_kernel();
Jiri Slaby2693f482009-06-11 12:31:06 +01002526 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002527 unsigned long flags;
2528 unsigned char status;
2529 int chip = channel >> 2;
2530 int index = card->bus_index;
2531
Jiri Slaby02f11752006-12-08 02:39:28 -08002532 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002533 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002535 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002536 cy_writeb(base_addr + (CyCAR << index), (u8)channel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002537 status = readb(base_addr + (CyMSVR1 << index));
2538 status |= readb(base_addr + (CyMSVR2 << index));
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002539 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Jiri Slaby02f11752006-12-08 02:39:28 -08002541 if (info->rtsdtr_inv) {
2542 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2543 ((status & CyDTR) ? TIOCM_RTS : 0);
2544 } else {
2545 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2546 ((status & CyDTR) ? TIOCM_DTR : 0);
2547 }
2548 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2549 ((status & CyRI) ? TIOCM_RNG : 0) |
2550 ((status & CyDSR) ? TIOCM_DSR : 0) |
2551 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002553 u32 lstatus;
2554
2555 if (!cyz_is_loaded(card)) {
2556 result = -ENODEV;
2557 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002558 }
2559
Jiri Slaby0d348722009-09-19 13:13:16 -07002560 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2561 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002568end:
Alan Cox7b130c02008-04-30 00:53:16 -07002569 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002570 return result;
2571} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
2573static int
2574cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08002575 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002577 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002578 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002579 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002581 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002582 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
Jiri Slaby02f11752006-12-08 02:39:28 -08002584 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002585 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002586 spin_lock_irqsave(&card->card_lock, flags);
2587 cyy_change_rts_dtr(info, set, clear);
2588 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002589 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002590 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2591 int retval, channel = info->line - card->first_line;
2592 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002593
Jiri Slaby0d348722009-09-19 13:13:16 -07002594 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002595 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002596
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002597 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002598 rs = readl(&ch_ctrl->rs_control);
2599 if (set & TIOCM_RTS)
2600 rs |= C_RS_RTS;
2601 if (clear & TIOCM_RTS)
2602 rs &= ~C_RS_RTS;
2603 if (set & TIOCM_DTR) {
2604 rs |= C_RS_DTR;
2605#ifdef CY_DEBUG_DTR
2606 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2607#endif
2608 }
2609 if (clear & TIOCM_DTR) {
2610 rs &= ~C_RS_DTR;
2611#ifdef CY_DEBUG_DTR
2612 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2613 "Z DTR\n");
2614#endif
2615 }
2616 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002617 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002618 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002619 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002620 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2621 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002624 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002625}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
2627/*
2628 * cy_break() --- routine which turns the break handling on or off
2629 */
Alan Cox9e989662008-07-22 11:18:03 +01002630static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002632 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002633 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002634 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002635 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
Jiri Slaby02f11752006-12-08 02:39:28 -08002637 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002638 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002640 card = info->card;
2641
2642 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002643 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002644 /* Let the transmit ISR take care of this (since it
2645 requires stuffing characters into the output stream).
2646 */
2647 if (break_state == -1) {
2648 if (!info->breakon) {
2649 info->breakon = 1;
2650 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002651 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002652 start_xmit(info);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002653 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002654 }
2655 }
2656 } else {
2657 if (!info->breakoff) {
2658 info->breakoff = 1;
2659 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002660 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002661 start_xmit(info);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002662 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002663 }
2664 }
2665 }
2666 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002667 if (break_state == -1) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002668 retval = cyz_issue_cmd(card,
2669 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002670 C_CM_SET_BREAK, 0L);
2671 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002672 printk(KERN_ERR "cyc:cy_break (set) retval on "
2673 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002674 }
2675 } else {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002676 retval = cyz_issue_cmd(card,
2677 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002678 C_CM_CLR_BREAK, 0L);
2679 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002680 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2681 "on ttyC%d was %x\n", info->line,
2682 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002683 }
2684 }
2685 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002686 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002687 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002688} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Jiri Slaby02f11752006-12-08 02:39:28 -08002690static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691{
Jiri Slaby875b2062007-05-08 00:36:49 -07002692 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002693 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002694 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002695 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Jiri Slaby02f11752006-12-08 02:39:28 -08002697 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002698 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002699 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002700 chip = channel >> 2;
2701 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002702 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002703 base_addr =
Jiri Slaby875b2062007-05-08 00:36:49 -07002704 card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Jiri Slaby02f11752006-12-08 02:39:28 -08002706 info->cor3 &= ~CyREC_FIFO;
2707 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002709 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002710 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2711 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002712 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002715} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Alan Cox15ed6cc2008-04-30 00:53:55 -07002717static int get_threshold(struct cyclades_port *info,
2718 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719{
Jiri Slaby875b2062007-05-08 00:36:49 -07002720 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002721 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002722 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002723 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
Jiri Slaby02f11752006-12-08 02:39:28 -08002725 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002726 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002727 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002728 chip = channel >> 2;
2729 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002730 index = card->bus_index;
2731 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002732
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002733 tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002735 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002736 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002737} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
Jiri Slaby02f11752006-12-08 02:39:28 -08002739static int set_timeout(struct cyclades_port *info, unsigned long value)
2740{
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 flags;
2745
2746 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 Slaby9fa1b3b2007-05-08 00:36:57 -07002754 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002755 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002756 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002757 }
2758 return 0;
2759} /* set_timeout */
2760
Alan Cox15ed6cc2008-04-30 00:53:55 -07002761static int get_timeout(struct cyclades_port *info,
2762 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002763{
Jiri Slaby875b2062007-05-08 00:36:49 -07002764 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002765 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002766 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002767 unsigned long tmp;
2768
2769 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002770 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002771 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002772 chip = channel >> 2;
2773 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002774 index = card->bus_index;
2775 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002776
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002777 tmp = readb(base_addr + (CyRTPR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08002778 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002779 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002780 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002781} /* get_timeout */
2782
Jiri Slaby6c281812009-09-19 13:13:15 -07002783static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2784 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002785{
Jiri Slaby6c281812009-09-19 13:13:15 -07002786 struct cyclades_icount cnow;
2787 unsigned long flags;
2788 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002789
Jiri Slaby6c281812009-09-19 13:13:15 -07002790 spin_lock_irqsave(&info->card->card_lock, flags);
2791 cnow = info->icount; /* atomic copy */
2792 spin_unlock_irqrestore(&info->card->card_lock, flags);
2793
2794 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2795 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2796 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2797 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2798
2799 *cprev = cnow;
2800
2801 return ret;
2802}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
2804/*
2805 * This routine allows the tty driver to implement device-
2806 * specific ioctl's. If the ioctl number passed in cmd is
2807 * not recognized by the driver, it should return ENOIOCTLCMD.
2808 */
2809static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002810cy_ioctl(struct tty_struct *tty, struct file *file,
2811 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002813 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002814 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002815 int ret_val = 0;
2816 unsigned long flags;
2817 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
Jiri Slaby02f11752006-12-08 02:39:28 -08002819 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2820 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
2822#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002823 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2824 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825#endif
Alan Cox7b130c02008-04-30 00:53:16 -07002826 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827
Jiri Slaby02f11752006-12-08 02:39:28 -08002828 switch (cmd) {
2829 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002830 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2831 ret_val = -EFAULT;
2832 break;
2833 }
2834 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002836 case CYGETTHRESH:
2837 ret_val = get_threshold(info, argp);
2838 break;
2839 case CYSETTHRESH:
2840 ret_val = set_threshold(info, arg);
2841 break;
2842 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002843 ret_val = put_user(info->default_threshold,
2844 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002845 break;
2846 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002847 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002848 break;
2849 case CYGETTIMEOUT:
2850 ret_val = get_timeout(info, argp);
2851 break;
2852 case CYSETTIMEOUT:
2853 ret_val = set_timeout(info, arg);
2854 break;
2855 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002856 ret_val = put_user(info->default_timeout,
2857 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002858 break;
2859 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002860 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002861 break;
2862 case CYSETRFLOW:
2863 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002864 break;
2865 case CYGETRFLOW:
2866 ret_val = info->rflow;
2867 break;
2868 case CYSETRTSDTR_INV:
2869 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002870 break;
2871 case CYGETRTSDTR_INV:
2872 ret_val = info->rtsdtr_inv;
2873 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002875 ret_val = info->chip_rev;
2876 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877#ifndef CONFIG_CYZ_INTR
2878 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002879 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002880 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002882 ret_val = (cyz_polling_cycle * 1000) / HZ;
2883 break;
2884#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002886 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002887 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002889 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002890 break;
2891 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002892 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002893 break;
2894 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002895 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002896 break;
2897 case TIOCSERGETLSR: /* Get line status register */
2898 ret_val = get_lsr_info(info, argp);
2899 break;
2900 /*
2901 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2902 * - mask passed in arg for lines of interest
2903 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2904 * Caller should use TIOCGICOUNT to see which one it was
2905 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 case TIOCMIWAIT:
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002907 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002908 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002909 cnow = info->icount;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002910 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby6c281812009-09-19 13:13:15 -07002911 ret_val = wait_event_interruptible(info->delta_msr_wait,
2912 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002913 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002914
2915 /*
2916 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2917 * Return: write counters to the user passed counter struct
2918 * NB: both 1->0 and 0->1 transitions are counted except for
2919 * RI where only 0->1 is counted.
2920 */
Jiri Slaby6c281812009-09-19 13:13:15 -07002921 case TIOCGICOUNT: {
2922 struct serial_icounter_struct sic = { };
2923
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002924 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002925 cnow = info->icount;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002926 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby6c281812009-09-19 13:13:15 -07002927
2928 sic.cts = cnow.cts;
2929 sic.dsr = cnow.dsr;
2930 sic.rng = cnow.rng;
2931 sic.dcd = cnow.dcd;
2932 sic.rx = cnow.rx;
2933 sic.tx = cnow.tx;
2934 sic.frame = cnow.frame;
2935 sic.overrun = cnow.overrun;
2936 sic.parity = cnow.parity;
2937 sic.brk = cnow.brk;
2938 sic.buf_overrun = cnow.buf_overrun;
2939
2940 if (copy_to_user(argp, &sic, sizeof(sic)))
2941 ret_val = -EFAULT;
Jiri Slaby02f11752006-12-08 02:39:28 -08002942 break;
Jiri Slaby6c281812009-09-19 13:13:15 -07002943 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002944 default:
2945 ret_val = -ENOIOCTLCMD;
2946 }
Alan Cox7b130c02008-04-30 00:53:16 -07002947 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
2949#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002950 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002952 return ret_val;
2953} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954
2955/*
2956 * This routine allows the tty driver to be notified when
2957 * device's termios settings have changed. Note that a
2958 * well-designed tty driver should be prepared to accept the case
2959 * where old == NULL, and try to do something rational.
2960 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002961static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002963 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
2965#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002966 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967#endif
2968
Jiri Slabyd13549f2009-09-19 13:13:12 -07002969 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
Jiri Slaby02f11752006-12-08 02:39:28 -08002971 if ((old_termios->c_cflag & CRTSCTS) &&
2972 !(tty->termios->c_cflag & CRTSCTS)) {
2973 tty->hw_stopped = 0;
2974 cy_start(tty);
2975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002977 /*
2978 * No need to wake up processes in open wait, since they
2979 * sample the CLOCAL flag once, and don't recheck it.
2980 * XXX It's not clear whether the current behavior is correct
2981 * or not. Hence, this may change.....
2982 */
2983 if (!(old_termios->c_cflag & CLOCAL) &&
2984 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01002985 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002987} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988
2989/* This function is used to send a high-priority XON/XOFF character to
2990 the device.
2991*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002992static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002994 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002995 struct cyclades_card *card;
2996 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
Jiri Slaby02f11752006-12-08 02:39:28 -08002998 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 return;
3000
Jiri Slaby02f11752006-12-08 02:39:28 -08003001 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
3003 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08003004 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
3006 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003007 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
Jiri Slaby2693f482009-06-11 12:31:06 +01003009 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003010 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003011 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003012 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003013 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 }
3015}
3016
3017/* This routine is called by the upper-layer tty layer to signal
3018 that incoming characters should be throttled because the input
3019 buffers are close to full.
3020 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003021static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003023 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003024 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003025 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
3027#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003028 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Jiri Slaby21719192007-05-08 00:36:42 -07003030 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08003031 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032#endif
3033
Alan Cox15ed6cc2008-04-30 00:53:55 -07003034 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003035 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Jiri Slaby02f11752006-12-08 02:39:28 -08003037 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
Jiri Slaby02f11752006-12-08 02:39:28 -08003039 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003040 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08003041 cy_send_xchar(tty, STOP_CHAR(tty));
3042 else
3043 info->throttle = 1;
3044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
Jiri Slaby02f11752006-12-08 02:39:28 -08003046 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003047 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003048 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003049 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003050 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003051 } else {
3052 info->throttle = 1;
3053 }
3054 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003055} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
3057/*
3058 * This routine notifies the tty driver that it should signal
3059 * that characters can now be sent to the tty without fear of
3060 * overrunning the input buffers of the line disciplines.
3061 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003062static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003064 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003065 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003066 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
3068#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003069 char buf[64];
3070
Jiri Slaby21719192007-05-08 00:36:42 -07003071 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07003072 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073#endif
3074
Alan Cox15ed6cc2008-04-30 00:53:55 -07003075 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003076 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Jiri Slaby02f11752006-12-08 02:39:28 -08003078 if (I_IXOFF(tty)) {
3079 if (info->x_char)
3080 info->x_char = 0;
3081 else
3082 cy_send_xchar(tty, START_CHAR(tty));
3083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084
Jiri Slaby02f11752006-12-08 02:39:28 -08003085 if (tty->termios->c_cflag & CRTSCTS) {
3086 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01003087 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003088 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003089 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003090 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003091 } else {
3092 info->throttle = 0;
3093 }
3094 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003095} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
3097/* cy_start and cy_stop provide software output flow control as a
3098 function of XON/XOFF, software CTS, and other such stuff.
3099*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003100static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101{
Jiri Slaby02f11752006-12-08 02:39:28 -08003102 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003103 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003104 void __iomem *base_addr;
3105 int chip, channel, index;
3106 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003109 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110#endif
3111
Jiri Slaby02f11752006-12-08 02:39:28 -08003112 if (serial_paranoia_check(info, tty->name, "cy_stop"))
3113 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
Jiri Slaby875b2062007-05-08 00:36:49 -07003115 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003116 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003117 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003118 index = cinfo->bus_index;
3119 chip = channel >> 2;
3120 channel &= 0x03;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003121 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003123 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003124 cy_writeb(base_addr + (CyCAR << index),
3125 (u_char)(channel & 0x0003)); /* index channel */
3126 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003127 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003128 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003130} /* cy_stop */
3131
3132static void cy_start(struct tty_struct *tty)
3133{
3134 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003135 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003136 void __iomem *base_addr;
3137 int chip, channel, index;
3138 unsigned long flags;
3139
3140#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003141 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08003142#endif
3143
3144 if (serial_paranoia_check(info, tty->name, "cy_start"))
3145 return;
3146
Jiri Slaby875b2062007-05-08 00:36:49 -07003147 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003148 channel = info->line - cinfo->first_line;
3149 index = cinfo->bus_index;
Jiri Slaby2693f482009-06-11 12:31:06 +01003150 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003151 chip = channel >> 2;
3152 channel &= 0x03;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003153 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003154
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003155 spin_lock_irqsave(&cinfo->card_lock, flags);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003156 cy_writeb(base_addr + (CyCAR << index),
3157 (u_char) (channel & 0x0003)); /* index channel */
Jiri Slaby02f11752006-12-08 02:39:28 -08003158 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003159 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003160 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003161 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003162} /* cy_start */
3163
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164/*
3165 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3166 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003167static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003169 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003170
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003172 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173#endif
3174
Jiri Slaby02f11752006-12-08 02:39:28 -08003175 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3176 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Jiri Slaby02f11752006-12-08 02:39:28 -08003178 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003179 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003180 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003181} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Jiri Slabyf0737572009-09-19 13:13:12 -07003183static int cyy_carrier_raised(struct tty_port *port)
3184{
3185 struct cyclades_port *info = container_of(port, struct cyclades_port,
3186 port);
3187 struct cyclades_card *cinfo = info->card;
3188 void __iomem *base = cinfo->base_addr;
3189 unsigned long flags;
3190 int channel = info->line - cinfo->first_line;
3191 int chip = channel >> 2, index = cinfo->bus_index;
3192 u32 cd;
3193
3194 channel &= 0x03;
3195 base += cy_chip_offset[chip] << index;
3196
3197 spin_lock_irqsave(&cinfo->card_lock, flags);
3198 cy_writeb(base + (CyCAR << index), (u8)channel);
3199 cd = readb(base + (CyMSVR1 << index)) & CyDCD;
3200 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3201
3202 return cd;
3203}
3204
3205static void cyy_dtr_rts(struct tty_port *port, int raise)
3206{
3207 struct cyclades_port *info = container_of(port, struct cyclades_port,
3208 port);
3209 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003210 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003211
3212 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003213 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3214 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003215 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3216}
3217
3218static int cyz_carrier_raised(struct tty_port *port)
3219{
3220 struct cyclades_port *info = container_of(port, struct cyclades_port,
3221 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003222
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003223 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003224}
3225
3226static void cyz_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 Slabyf0eefdc2009-09-19 13:13:13 -07003231 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003232 int ret, channel = info->line - cinfo->first_line;
3233 u32 rs;
3234
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003235 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003236 if (raise)
3237 rs |= C_RS_RTS | C_RS_DTR;
3238 else
3239 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003240 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003241 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3242 if (ret != 0)
3243 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3244 __func__, info->line, ret);
3245#ifdef CY_DEBUG_DTR
3246 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3247#endif
3248}
3249
3250static const struct tty_port_operations cyy_port_ops = {
3251 .carrier_raised = cyy_carrier_raised,
3252 .dtr_rts = cyy_dtr_rts,
3253};
3254
3255static const struct tty_port_operations cyz_port_ops = {
3256 .carrier_raised = cyz_carrier_raised,
3257 .dtr_rts = cyz_dtr_rts,
3258};
3259
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260/*
3261 * ---------------------------------------------------------------------
3262 * cy_init() and friends
3263 *
3264 * cy_init() is called at boot-time to initialize the serial driver.
3265 * ---------------------------------------------------------------------
3266 */
3267
Jiri Slabydd025c02007-05-08 00:37:02 -07003268static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003269{
3270 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003271 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003272
Jiri Slaby3046d502007-05-08 00:36:46 -07003273 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003274 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003275
Jiri Slaby963118e2009-06-11 12:34:27 +01003276 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3277 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003278 if (cinfo->ports == NULL) {
3279 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3280 return -ENOMEM;
3281 }
3282
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003283 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3284 channel++, port++) {
3285 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003286 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003287 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003288 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003289 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003290
Alan Cox44b7d1b2008-07-16 21:57:18 +01003291 info->port.closing_wait = CLOSING_WAIT_DELAY;
3292 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003293 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003294 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003295 init_waitqueue_head(&info->delta_msr_wait);
3296
Jiri Slaby2693f482009-06-11 12:31:06 +01003297 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003298 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3299 struct ZFW_CTRL *zfw_ctrl;
3300
Jiri Slabyf0737572009-09-19 13:13:12 -07003301 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003302 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003303
3304 zfw_ctrl = cinfo->base_addr +
3305 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3306 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3307 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3308
Jiri Slaby101b8152009-06-11 12:30:10 +01003309 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003310 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3311 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003312 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003313#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003314 setup_timer(&cyz_rx_full_timer[port],
3315 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003316#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003317 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003318 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003319 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003320
Jiri Slabyf0737572009-09-19 13:13:12 -07003321 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003322 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003323 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003324 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003325 info->cor2 = CyETC;
3326 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003327
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003328 chip_number = channel / CyPORTS_PER_CHIP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07003329 info->chip_rev = readb(cinfo->base_addr +
3330 (cy_chip_offset[chip_number] << index) +
3331 (CyGFRCR << index));
3332
3333 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003334 /* It is a CD1400 rev. J or later */
3335 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3336 info->tco = baud_co_60[13]; /* Tx CO */
3337 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3338 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003339 info->rtsdtr_inv = 1;
3340 } else {
3341 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3342 info->tco = baud_co_25[13]; /* Tx CO */
3343 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3344 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003345 info->rtsdtr_inv = 0;
3346 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003347 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3348 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003349 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003350
Jiri Slaby0809e262007-05-08 00:36:14 -07003351 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003352
3353#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003354 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003355 mod_timer(&cyz_timerlist, jiffies + 1);
3356#ifdef CY_PCI_DEBUG
3357 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3358#endif
3359 }
3360#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003361 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003362}
3363
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364/* initialize chips on Cyclom-Y card -- return number of valid
3365 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003366static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3367 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368{
Jiri Slaby02f11752006-12-08 02:39:28 -08003369 unsigned int chip_number;
3370 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
Jiri Slaby02f11752006-12-08 02:39:28 -08003372 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3373 /* Cy_HwReset is 0x1400 */
3374 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3375 /* Cy_ClrIntr is 0x1800 */
3376 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
Alan Cox15ed6cc2008-04-30 00:53:55 -07003378 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3379 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003380 base_addr =
3381 true_base_addr + (cy_chip_offset[chip_number] << index);
3382 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003383 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003384 /*************
3385 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3386 chip_number, (unsigned long)base_addr);
3387 *************/
3388 return chip_number;
3389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390
Jiri Slaby02f11752006-12-08 02:39:28 -08003391 cy_writeb(base_addr + (CyGFRCR << index), 0);
3392 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
Jiri Slaby02f11752006-12-08 02:39:28 -08003394 /* The Cyclom-16Y does not decode address bit 9 and therefore
3395 cannot distinguish between references to chip 0 and a non-
3396 existent chip 4. If the preceding clearing of the supposed
3397 chip 4 GFRCR register appears at chip 0, there is no chip 4
3398 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3399 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003400 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003401 (cy_chip_offset[0] << index) +
3402 (CyGFRCR << index)) == 0) {
3403 return chip_number;
3404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405
Jiri Slaby02f11752006-12-08 02:39:28 -08003406 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3407 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003409 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003410 /*
3411 printk(" chip #%d at %#6lx is not responding ",
3412 chip_number, (unsigned long)base_addr);
3413 printk("(GFRCR stayed 0)\n",
3414 */
3415 return chip_number;
3416 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003417 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003418 0x40) {
3419 /*
3420 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3421 "%#2x)\n",
3422 chip_number, (unsigned long)base_addr,
3423 base_addr[CyGFRCR<<index]);
3424 */
3425 return chip_number;
3426 }
3427 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003428 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003429 /* It is a CD1400 rev. J or later */
3430 /* Impossible to reach 5ms with this chip.
3431 Changed to 2ms instead (f = 500 Hz). */
3432 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3433 } else {
3434 /* f = 200 Hz */
3435 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3436 }
3437
3438 /*
3439 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3440 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003441 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003442 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003444 return chip_number;
3445} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
3447/*
3448 * ---------------------------------------------------------------------
3449 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3450 * sets global variables and return the number of ISA boards found.
3451 * ---------------------------------------------------------------------
3452 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003453static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454{
3455#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003456 unsigned short cy_isa_irq, nboard;
3457 void __iomem *cy_isa_address;
3458 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08003460 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461#endif
3462
Jiri Slaby02f11752006-12-08 02:39:28 -08003463 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
3465#ifdef MODULE
3466 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003467 for (i = 0; i < NR_CARDS; i++) {
3468 if (maddr[i] || i) {
3469 isparam = 1;
3470 cy_isa_addresses[i] = maddr[i];
3471 }
3472 if (!maddr[i])
3473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 }
3475#endif
3476
Jiri Slaby02f11752006-12-08 02:39:28 -08003477 /* scan the address table probing for Cyclom-Y/ISA boards */
3478 for (i = 0; i < NR_ISA_ADDRS; i++) {
3479 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003480 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003481 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482
Jiri Slaby02f11752006-12-08 02:39:28 -08003483 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003484 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003485 if (cy_isa_address == NULL) {
3486 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3487 "address\n");
3488 continue;
3489 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003490 cy_isa_nchan = CyPORTS_PER_CHIP *
3491 cyy_init_card(cy_isa_address, 0);
3492 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003493 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003494 continue;
3495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496#ifdef MODULE
3497 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003498 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 else
3500#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003501 /* find out the board's irq by probing */
3502 cy_isa_irq = detect_isa_irq(cy_isa_address);
3503 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003504 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3505 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003506 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003507 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003508 continue;
3509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510
Jiri Slaby02f11752006-12-08 02:39:28 -08003511 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003512 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3513 "more channels are available. Change NR_PORTS "
3514 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003515 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003516 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003517 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003518 }
3519 /* fill the next cy_card structure available */
3520 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003521 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003522 break;
3523 }
3524 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003525 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3526 "more cards can be used. Change NR_CARDS in "
3527 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003528 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003529 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003530 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
Jiri Slaby02f11752006-12-08 02:39:28 -08003533 /* allocate IRQ */
3534 if (request_irq(cy_isa_irq, cyy_interrupt,
3535 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003536 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3537 "could not allocate IRQ#%d.\n",
3538 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003539 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003540 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
Jiri Slaby02f11752006-12-08 02:39:28 -08003543 /* set cy_card */
3544 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003545 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003546 cy_card[j].irq = (int)cy_isa_irq;
3547 cy_card[j].bus_index = 0;
3548 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003549 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3550 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003551 if (cy_init_card(&cy_card[j])) {
3552 cy_card[j].base_addr = NULL;
3553 free_irq(cy_isa_irq, &cy_card[j]);
3554 iounmap(cy_isa_address);
3555 continue;
3556 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003557 nboard++;
3558
Jiri Slaby21719192007-05-08 00:36:42 -07003559 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3560 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003561 j + 1, (unsigned long)cy_isa_address,
3562 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003563 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3564
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003565 for (j = cy_next_channel;
3566 j < cy_next_channel + cy_isa_nchan; j++)
3567 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003568 cy_next_channel += cy_isa_nchan;
3569 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003570 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003572 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003573#endif /* CONFIG_ISA */
3574} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
Jiri Slaby58936d82007-05-08 00:36:13 -07003576#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003577static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3578{
3579 unsigned int a;
3580
3581 for (a = 0; a < size && *str; a++, str++)
3582 if (*str & 0x80)
3583 return -EINVAL;
3584
3585 for (; a < size; a++, str++)
3586 if (*str)
3587 return -EINVAL;
3588
3589 return 0;
3590}
3591
David Woodhousef61e7612008-05-23 23:57:19 +01003592static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003593 unsigned int size)
3594{
3595 for (; size > 0; size--) {
3596 cy_writel(fpga, *data++);
3597 udelay(10);
3598 }
3599}
3600
3601static void __devinit plx_init(struct pci_dev *pdev, int irq,
3602 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603{
Jiri Slaby02f11752006-12-08 02:39:28 -08003604 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003605 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003606 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003607 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Jiri Slaby02f11752006-12-08 02:39:28 -08003609 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003610 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003611 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003612 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3613
3614 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3615 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3616 * registers. This will remain here until we find a permanent fix.
3617 */
3618 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3619}
3620
3621static int __devinit __cyz_load_fw(const struct firmware *fw,
3622 const char *name, const u32 mailbox, void __iomem *base,
3623 void __iomem *fpga)
3624{
David Woodhousef61e7612008-05-23 23:57:19 +01003625 const void *ptr = fw->data;
3626 const struct zfile_header *h = ptr;
3627 const struct zfile_config *c, *cs;
3628 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003629 unsigned int a, tmp, len = fw->size;
3630#define BAD_FW KERN_ERR "Bad firmware: "
3631 if (len < sizeof(*h)) {
3632 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3633 return -EINVAL;
3634 }
3635
3636 cs = ptr + h->config_offset;
3637 bs = ptr + h->block_offset;
3638
3639 if ((void *)(cs + h->n_config) > ptr + len ||
3640 (void *)(bs + h->n_blocks) > ptr + len) {
3641 printk(BAD_FW "too short");
3642 return -EINVAL;
3643 }
3644
3645 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3646 cyc_isfwstr(h->date, sizeof(h->date))) {
3647 printk(BAD_FW "bad formatted header string\n");
3648 return -EINVAL;
3649 }
3650
3651 if (strncmp(name, h->name, sizeof(h->name))) {
3652 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3653 return -EINVAL;
3654 }
3655
3656 tmp = 0;
3657 for (c = cs; c < cs + h->n_config; c++) {
3658 for (a = 0; a < c->n_blocks; a++)
3659 if (c->block_list[a] > h->n_blocks) {
3660 printk(BAD_FW "bad block ref number in cfgs\n");
3661 return -EINVAL;
3662 }
3663 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3664 tmp++;
3665 }
3666 if (!tmp) {
3667 printk(BAD_FW "nothing appropriate\n");
3668 return -EINVAL;
3669 }
3670
3671 for (b = bs; b < bs + h->n_blocks; b++)
3672 if (b->file_offset + b->size > len) {
3673 printk(BAD_FW "bad block data offset\n");
3674 return -EINVAL;
3675 }
3676
3677 /* everything is OK, let's seek'n'load it */
3678 for (c = cs; c < cs + h->n_config; c++)
3679 if (c->mailbox == mailbox && c->function == 0)
3680 break;
3681
3682 for (a = 0; a < c->n_blocks; a++) {
3683 b = &bs[c->block_list[a]];
3684 if (b->type == ZBLOCK_FPGA) {
3685 if (fpga != NULL)
3686 cyz_fpga_copy(fpga, ptr + b->file_offset,
3687 b->size);
3688 } else {
3689 if (base != NULL)
3690 memcpy_toio(base + b->ram_offset,
3691 ptr + b->file_offset, b->size);
3692 }
3693 }
3694#undef BAD_FW
3695 return 0;
3696}
3697
3698static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3699 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3700{
3701 const struct firmware *fw;
3702 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3703 struct CUSTOM_REG __iomem *cust = base_addr;
3704 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003705 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003706 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003707 unsigned int i;
3708 int retval;
3709
3710 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3711 if (retval) {
3712 dev_err(&pdev->dev, "can't get firmware\n");
3713 goto err;
3714 }
3715
3716 /* Check whether the firmware is already loaded and running. If
3717 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003718 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003719 u32 cntval = readl(base_addr + 0x190);
3720
3721 udelay(100);
3722 if (cntval != readl(base_addr + 0x190)) {
3723 /* FW counter is working, FW is running */
3724 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3725 "Skipping board.\n");
3726 retval = 0;
3727 goto err_rel;
3728 }
3729 }
3730
3731 /* start boot */
3732 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3733 ~0x00030800UL);
3734
3735 mailbox = readl(&ctl_addr->mail_box_0);
3736
Jiri Slaby2693f482009-06-11 12:31:06 +01003737 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003738 /* stops CPU and set window to beginning of RAM */
3739 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3740 cy_writel(&cust->cpu_stop, 0);
3741 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3742 udelay(100);
3743 }
3744
3745 plx_init(pdev, irq, ctl_addr);
3746
3747 if (mailbox != 0) {
3748 /* load FPGA */
3749 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3750 base_addr);
3751 if (retval)
3752 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003753 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003754 dev_err(&pdev->dev, "fw upload successful, but fw is "
3755 "not loaded\n");
3756 goto err_rel;
3757 }
3758 }
3759
3760 /* stops CPU and set window to beginning of RAM */
3761 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3762 cy_writel(&cust->cpu_stop, 0);
3763 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3764 udelay(100);
3765
3766 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003767 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003768 cy_writeb(tmp, 255);
3769 if (mailbox != 0) {
3770 /* set window to last 512K of RAM */
3771 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003772 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003773 cy_writeb(tmp, 255);
3774 /* set window to beginning of RAM */
3775 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003776 }
3777
3778 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3779 release_firmware(fw);
3780 if (retval)
3781 goto err;
3782
3783 /* finish boot and start boards */
3784 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3785 cy_writel(&cust->cpu_start, 0);
3786 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3787 i = 0;
3788 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3789 msleep(100);
3790 if (status != ZFIRM_ID) {
3791 if (status == ZFIRM_HLT) {
3792 dev_err(&pdev->dev, "you need an external power supply "
3793 "for this number of ports. Firmware halted and "
3794 "board reset.\n");
3795 retval = -EIO;
3796 goto err;
3797 }
3798 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3799 "some more time\n", status);
3800 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3801 i++ < 200)
3802 msleep(100);
3803 if (status != ZFIRM_ID) {
3804 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3805 "Giving up. (fid->signature = 0x%x)\n",
3806 status);
3807 dev_info(&pdev->dev, "*** Warning ***: if you are "
3808 "upgrading the FW, please power cycle the "
3809 "system before loading the new FW to the "
3810 "Cyclades-Z.\n");
3811
Jiri Slaby2693f482009-06-11 12:31:06 +01003812 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003813 plx_init(pdev, irq, ctl_addr);
3814
3815 retval = -EIO;
3816 goto err;
3817 }
3818 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3819 i / 10);
3820 }
3821 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3822
3823 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3824 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3825 base_addr + readl(&fid->zfwctrl_addr));
3826
Jiri Slaby963118e2009-06-11 12:34:27 +01003827 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003828 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003829 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003830
Jiri Slaby963118e2009-06-11 12:34:27 +01003831 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003832 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3833 "check the connection between the Z host card and the "
3834 "serial expanders.\n");
3835
Jiri Slaby2693f482009-06-11 12:31:06 +01003836 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003837 plx_init(pdev, irq, ctl_addr);
3838
3839 dev_info(&pdev->dev, "Null number of ports detected. Board "
3840 "reset.\n");
3841 retval = 0;
3842 goto err;
3843 }
3844
3845 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3846 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3847
3848 /*
3849 Early firmware failed to start looking for commands.
3850 This enables firmware interrupts for those commands.
3851 */
3852 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3853 (1 << 17));
3854 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3855 0x00030800UL);
3856
Jiri Slaby963118e2009-06-11 12:34:27 +01003857 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003858err_rel:
3859 release_firmware(fw);
3860err:
3861 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862}
3863
Jiri Slaby58936d82007-05-08 00:36:13 -07003864static int __devinit cy_pci_probe(struct pci_dev *pdev,
3865 const struct pci_device_id *ent)
3866{
Jiri Slaby31375532007-05-08 00:37:04 -07003867 void __iomem *addr0 = NULL, *addr2 = NULL;
3868 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003869 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003870 unsigned int device_id, nchan = 0, card_no, i;
3871 unsigned char plx_ver;
3872 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003873
3874 retval = pci_enable_device(pdev);
3875 if (retval) {
3876 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003877 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003878 }
3879
3880 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003881 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003882 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3883
Jiri Slaby31375532007-05-08 00:37:04 -07003884#if defined(__alpha__)
3885 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3886 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3887 "addresses on Alpha systems.\n");
3888 retval = -EIO;
3889 goto err_dis;
3890 }
3891#endif
3892 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3893 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3894 "addresses\n");
3895 retval = -EIO;
3896 goto err_dis;
3897 }
3898
3899 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3900 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3901 "it...\n");
3902 pdev->resource[2].flags &= ~IORESOURCE_IO;
3903 }
3904
3905 retval = pci_request_regions(pdev, "cyclades");
3906 if (retval) {
3907 dev_err(&pdev->dev, "failed to reserve resources\n");
3908 goto err_dis;
3909 }
3910
3911 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003912 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3913 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003914 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003915
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003916 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3917 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003918 if (addr0 == NULL) {
3919 dev_err(&pdev->dev, "can't remap ctl region\n");
3920 goto err_reg;
3921 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003922 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3923 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003924 if (addr2 == NULL) {
3925 dev_err(&pdev->dev, "can't remap base region\n");
3926 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003927 }
3928
Jiri Slaby31375532007-05-08 00:37:04 -07003929 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3930 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003931 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3932 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003933 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003934 }
Jiri Slaby31375532007-05-08 00:37:04 -07003935 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3936 struct RUNTIME_9060 __iomem *ctl_addr;
3937
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003938 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3939 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003940 if (addr0 == NULL) {
3941 dev_err(&pdev->dev, "can't remap ctl region\n");
3942 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003943 }
3944
Jiri Slaby31375532007-05-08 00:37:04 -07003945 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003946 cy_writew(&ctl_addr->intr_ctrl_stat,
3947 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003948
Jiri Slaby054f5b02007-07-17 04:05:16 -07003949 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003950
Jiri Slaby101b8152009-06-11 12:30:10 +01003951 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003952
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003953 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3954 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003955 if (addr2 == NULL) {
3956 dev_err(&pdev->dev, "can't remap base region\n");
3957 goto err_unmap;
3958 }
3959
3960 if (mailbox == ZE_V1) {
3961 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003962 } else {
3963 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003964#ifdef CY_PCI_DEBUG
3965 if (mailbox == ZO_V1) {
3966 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3967 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3968 "id %lx, ver %lx\n", (ulong)(0xff &
3969 readl(&((struct CUSTOM_REG *)addr2)->
3970 fpga_id)), (ulong)(0xff &
3971 readl(&((struct CUSTOM_REG *)addr2)->
3972 fpga_version)));
3973 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3974 } else {
3975 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3976 "Cyclades-Z board. FPGA not loaded\n");
3977 }
3978#endif
3979 /* The following clears the firmware id word. This
3980 ensures that the driver will not attempt to talk to
3981 the board until it has been properly initialized.
3982 */
3983 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3984 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003985 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003986
3987 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003988 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003989 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003990 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003991 }
3992
3993 if ((cy_next_channel + nchan) > NR_PORTS) {
3994 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3995 "channels are available. Change NR_PORTS in "
3996 "cyclades.c and recompile kernel.\n");
3997 goto err_unmap;
3998 }
3999 /* fill the next cy_card structure available */
4000 for (card_no = 0; card_no < NR_CARDS; card_no++) {
4001 if (cy_card[card_no].base_addr == NULL)
4002 break;
4003 }
4004 if (card_no == NR_CARDS) { /* no more cy_cards available */
4005 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4006 "more cards can be used. Change NR_CARDS in "
4007 "cyclades.c and recompile kernel.\n");
4008 goto err_unmap;
4009 }
4010
4011 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4012 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004013 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07004014 retval = request_irq(irq, cyy_interrupt,
4015 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07004016 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07004017 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004018 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004019 }
Jiri Slaby963118e2009-06-11 12:34:27 +01004020 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07004021 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004022 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
4023 struct ZFW_CTRL __iomem *zfw_ctrl;
4024
4025 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4026
Jiri Slaby101b8152009-06-11 12:30:10 +01004027 cy_card[card_no].hw_ver = mailbox;
4028 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004029 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07004030#ifdef CONFIG_CYZ_INTR
4031 /* allocate IRQ only if board has an IRQ */
4032 if (irq != 0 && irq != 255) {
4033 retval = request_irq(irq, cyz_interrupt,
4034 IRQF_SHARED, "Cyclades-Z",
4035 &cy_card[card_no]);
4036 if (retval) {
4037 dev_err(&pdev->dev, "could not allocate IRQ\n");
4038 goto err_unmap;
4039 }
4040 }
4041#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07004042 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004043
Jiri Slaby31375532007-05-08 00:37:04 -07004044 /* set cy_card */
4045 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01004046 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07004047 cy_card[card_no].irq = irq;
4048 cy_card[card_no].bus_index = 1;
4049 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01004050 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07004051 retval = cy_init_card(&cy_card[card_no]);
4052 if (retval)
4053 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07004054
Jiri Slaby31375532007-05-08 00:37:04 -07004055 pci_set_drvdata(pdev, &cy_card[card_no]);
4056
4057 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4058 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004059 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07004060 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07004061 switch (plx_ver) {
4062 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07004063 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07004064 break;
4065
4066 case PLX_9060:
4067 case PLX_9080:
4068 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004069 {
4070 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
4071 plx_init(pdev, irq, ctl_addr);
4072 cy_writew(&ctl_addr->intr_ctrl_stat,
4073 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07004074 break;
4075 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01004076 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004077 }
4078
Jiri Slaby31375532007-05-08 00:37:04 -07004079 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
4080 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
4081 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
4082 tty_register_device(cy_serial_driver, i, &pdev->dev);
4083 cy_next_channel += nchan;
4084
Jiri Slaby58936d82007-05-08 00:36:13 -07004085 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07004086err_null:
4087 cy_card[card_no].base_addr = NULL;
4088 free_irq(irq, &cy_card[card_no]);
4089err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004090 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004091 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004092 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07004093err_reg:
4094 pci_release_regions(pdev);
4095err_dis:
4096 pci_disable_device(pdev);
4097err:
4098 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07004099}
Jiri Slaby58936d82007-05-08 00:36:13 -07004100
Jiri Slaby6747cd92007-05-08 00:36:34 -07004101static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102{
Jiri Slaby38d09092007-05-08 00:36:10 -07004103 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07004104 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07004105
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004106 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01004107 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07004108 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01004109 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004110 else
4111#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004112 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004113#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01004114 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
4115 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
4116 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004117
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004118 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004119 if (cinfo->ctl_addr.p9050)
4120 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07004121 if (cinfo->irq
4122#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004123 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07004124#endif /* CONFIG_CYZ_INTR */
4125 )
4126 free_irq(cinfo->irq, cinfo);
4127 pci_release_regions(pdev);
4128
4129 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004130 for (i = cinfo->first_line; i < cinfo->first_line +
4131 cinfo->nports; i++)
4132 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07004133 cinfo->nports = 0;
4134 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07004135}
4136
Jiri Slaby6747cd92007-05-08 00:36:34 -07004137static struct pci_driver cy_pci_driver = {
4138 .name = "cyclades",
4139 .id_table = cy_pci_dev_id,
4140 .probe = cy_pci_probe,
4141 .remove = __devexit_p(cy_pci_remove)
4142};
4143#endif
4144
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004145static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146{
Jiri Slaby02f11752006-12-08 02:39:28 -08004147 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07004148 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08004149 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004151 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08004152 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
Jiri Slaby02f11752006-12-08 02:39:28 -08004154 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07004155 for (i = 0; i < NR_CARDS; i++)
4156 for (j = 0; j < cy_card[i].nports; j++) {
4157 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08004158
Jiri Slabyd13549f2009-09-19 13:13:12 -07004159 if (info->port.count) {
4160 /* XXX is the ldisc num worth this? */
4161 struct tty_struct *tty;
4162 struct tty_ldisc *ld;
4163 int num = 0;
4164 tty = tty_port_tty_get(&info->port);
4165 if (tty) {
4166 ld = tty_ldisc_ref(tty);
4167 if (ld) {
4168 num = ld->ops->num;
4169 tty_ldisc_deref(ld);
4170 }
4171 tty_kref_put(tty);
4172 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004173 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004174 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004175 (cur_jifs - info->idle_stats.in_use) /
4176 HZ, info->idle_stats.xmit_bytes,
4177 (cur_jifs - info->idle_stats.xmit_idle)/
4178 HZ, info->idle_stats.recv_bytes,
4179 (cur_jifs - info->idle_stats.recv_idle)/
4180 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004181 num);
4182 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004183 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004184 "%10lu %8lu %9lu %6ld\n",
4185 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004186 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004187 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188}
4189
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004190static int cyclades_proc_open(struct inode *inode, struct file *file)
4191{
4192 return single_open(file, cyclades_proc_show, NULL);
4193}
4194
4195static const struct file_operations cyclades_proc_fops = {
4196 .owner = THIS_MODULE,
4197 .open = cyclades_proc_open,
4198 .read = seq_read,
4199 .llseek = seq_lseek,
4200 .release = single_release,
4201};
4202
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203/* The serial driver boot-time initialization code!
4204 Hardware I/O ports are mapped to character special devices on a
4205 first found, first allocated manner. That is, this code searches
4206 for Cyclom cards in the system. As each is found, it is probed
4207 to discover how many chips (and thus how many ports) are present.
4208 These ports are mapped to the tty ports 32 and upward in monotonic
4209 fashion. If an 8-port card is replaced with a 16-port card, the
4210 port mapping on a following card will shift.
4211
4212 This approach is different from what is used in the other serial
4213 device driver because the Cyclom is more properly a multiplexer,
4214 not just an aggregation of serial ports on one card.
4215
4216 If there are more cards with more ports than have been
4217 statically allocated above, a warning is printed and the
4218 extra ports are ignored.
4219 */
4220
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004221static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004222 .open = cy_open,
4223 .close = cy_close,
4224 .write = cy_write,
4225 .put_char = cy_put_char,
4226 .flush_chars = cy_flush_chars,
4227 .write_room = cy_write_room,
4228 .chars_in_buffer = cy_chars_in_buffer,
4229 .flush_buffer = cy_flush_buffer,
4230 .ioctl = cy_ioctl,
4231 .throttle = cy_throttle,
4232 .unthrottle = cy_unthrottle,
4233 .set_termios = cy_set_termios,
4234 .stop = cy_stop,
4235 .start = cy_start,
4236 .hangup = cy_hangup,
4237 .break_ctl = cy_break,
4238 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004239 .tiocmget = cy_tiocmget,
4240 .tiocmset = cy_tiocmset,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004241 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242};
4243
Jiri Slaby02f11752006-12-08 02:39:28 -08004244static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245{
Jiri Slabydd025c02007-05-08 00:37:02 -07004246 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004247 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
Jiri Slaby02f11752006-12-08 02:39:28 -08004249 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4250 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004251 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004252
4253 printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
4254 __DATE__, __TIME__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255
Jiri Slaby02f11752006-12-08 02:39:28 -08004256 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257
Jiri Slaby02f11752006-12-08 02:39:28 -08004258 cy_serial_driver->owner = THIS_MODULE;
4259 cy_serial_driver->driver_name = "cyclades";
4260 cy_serial_driver->name = "ttyC";
4261 cy_serial_driver->major = CYCLADES_MAJOR;
4262 cy_serial_driver->minor_start = 0;
4263 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4264 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4265 cy_serial_driver->init_termios = tty_std_termios;
4266 cy_serial_driver->init_termios.c_cflag =
4267 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004268 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004269 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004271 retval = tty_register_driver(cy_serial_driver);
4272 if (retval) {
4273 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4274 goto err_frtty;
4275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Jiri Slaby02f11752006-12-08 02:39:28 -08004277 /* the code below is responsible to find the boards. Each different
4278 type of board has its own detection routine. If a board is found,
4279 the next cy_card structure available is set by the detection
4280 routine. These functions are responsible for checking the
4281 availability of cy_card and cy_port data structures and updating
4282 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Jiri Slaby02f11752006-12-08 02:39:28 -08004284 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004285 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286
Jiri Slaby6747cd92007-05-08 00:36:34 -07004287#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004288 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004289 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004290 if (retval && !nboards) {
4291 tty_unregister_driver(cy_serial_driver);
4292 goto err_frtty;
4293 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004294#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004295
4296 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004297err_frtty:
4298 put_tty_driver(cy_serial_driver);
4299err:
4300 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004301} /* cy_init */
4302
4303static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304{
Jiri Slabydd025c02007-05-08 00:37:02 -07004305 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004306 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
4308#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004309 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310#endif /* CONFIG_CYZ_INTR */
4311
Alan Cox15ed6cc2008-04-30 00:53:55 -07004312 e1 = tty_unregister_driver(cy_serial_driver);
4313 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004314 printk(KERN_ERR "failed to unregister Cyclades serial "
4315 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
Jiri Slaby6747cd92007-05-08 00:36:34 -07004317#ifdef CONFIG_PCI
4318 pci_unregister_driver(&cy_pci_driver);
4319#endif
4320
Jiri Slaby02f11752006-12-08 02:39:28 -08004321 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004322 card = &cy_card[i];
4323 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004324 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004325 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4326 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004327 if (card->ctl_addr.p9050)
4328 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004329 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004331 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004333 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004334 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004335 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004336 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004337 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004338 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004339 }
4340 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004341
4342 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343} /* cy_cleanup_module */
4344
4345module_init(cy_init);
4346module_exit(cy_cleanup_module);
4347
4348MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004349MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad2009-04-06 17:33:04 +01004350MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);