blob: 3884ea439935991c70d63bac7b30c2c9318036f1 [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 ... */
392 udelay(5000L);
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 ... */
405 udelay(5000L);
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
828/***********************************************************/
829/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700830/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831/***********************************************************/
832
833static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800834cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700835 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700837 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800838 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Jiri Slaby97e87f82009-06-11 12:29:27 +0100840 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800841 if (loc_doorbell) {
842 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700843 *channel = readl(&board_ctrl->fwcmd_channel);
844 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100845 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800846 return 1;
847 }
848 return 0;
849} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800852cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700853 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700855 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700856 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700857 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Jiri Slaby2693f482009-06-11 12:31:06 +0100859 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800860 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700861
Jiri Slaby02f11752006-12-08 02:39:28 -0800862 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100863 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700864 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700865 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700866 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800867 udelay(50L);
868 }
869 cy_writel(&board_ctrl->hcmd_channel, channel);
870 cy_writel(&board_ctrl->hcmd_param, param);
871 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800873 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800874} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700876static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700878 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700879 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700880 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800881 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700883 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800885 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700887 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700889 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
890 rx_put = readl(&buf_ctrl->rx_put);
891 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
892 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800893 if (rx_put >= rx_get)
894 char_count = rx_put - rx_get;
895 else
896 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
Jiri Slaby02f11752006-12-08 02:39:28 -0800898 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800900 info->mon.int_count++;
901 info->mon.char_count += char_count;
902 if (char_count > info->mon.char_max)
903 info->mon.char_max = char_count;
904 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700906 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800907 /* flush received characters */
908 new_rx_get = (new_rx_get + char_count) &
909 (rx_bufsize - 1);
910 info->rflush_count++;
911 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800913 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
914 for performance, but because of buffer boundaries, there
915 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700916 while (1) {
917 len = tty_prepare_flip_string(tty, &buf,
918 char_count);
919 if (!len)
920 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700922 len = min_t(unsigned int, min(len, char_count),
923 rx_bufsize - new_rx_get);
924
925 memcpy_fromio(buf, cinfo->base_addr +
926 rx_bufaddr + new_rx_get, len);
927
928 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800929 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700930 char_count -= len;
931 info->icount.rx += len;
932 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800935 len = tty_buffer_request_room(tty, char_count);
936 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700937 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800938 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700939 new_rx_get = (new_rx_get + 1) &
940 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800941 tty_insert_flip_char(tty, data, TTY_NORMAL);
942 info->idle_stats.recv_bytes++;
943 info->icount.rx++;
944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945#endif
946#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -0800947 /* Recalculate the number of chars in the RX buffer and issue
948 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700949 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -0800950 if (rx_put >= rx_get)
951 char_count = rx_put - rx_get;
952 else
953 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700954 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -0700955 !timer_pending(&cyz_rx_full_timer[
956 info->line]))
957 mod_timer(&cyz_rx_full_timer[info->line],
958 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800960 info->idle_stats.recv_idle = jiffies;
961 tty_schedule_flip(tty);
962 }
963 /* Update rx_get */
964 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700968static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700970 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700971 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700972 u8 data;
973 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800975 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700977 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Jiri Slaby02f11752006-12-08 02:39:28 -0800979 if (info->xmit_cnt <= 0) /* Nothing to transmit */
980 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700982 tx_get = readl(&buf_ctrl->tx_get);
983 tx_put = readl(&buf_ctrl->tx_put);
984 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
985 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800986 if (tx_put >= tx_get)
987 char_count = tx_get - tx_put - 1 + tx_bufsize;
988 else
989 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Jiri Slaby02f11752006-12-08 02:39:28 -0800991 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Jiri Slabyf7429032007-05-08 00:36:59 -0700993 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -0800994 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -0800995
996 if (info->x_char) { /* send special char */
997 data = info->x_char;
998
999 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1000 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1001 info->x_char = 0;
1002 char_count--;
1003 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001004 }
1005#ifdef BLOCKMOVE
1006 while (0 < (small_count = min_t(unsigned int,
1007 tx_bufsize - tx_put, min_t(unsigned int,
1008 (SERIAL_XMIT_SIZE - info->xmit_tail),
1009 min_t(unsigned int, info->xmit_cnt,
1010 char_count))))) {
1011
1012 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1013 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001014 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001015 small_count);
1016
1017 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1018 char_count -= small_count;
1019 info->icount.tx += small_count;
1020 info->xmit_cnt -= small_count;
1021 info->xmit_tail = (info->xmit_tail + small_count) &
1022 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001023 }
1024#else
1025 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001026 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001027 info->xmit_cnt--;
1028 info->xmit_tail = (info->xmit_tail + 1) &
1029 (SERIAL_XMIT_SIZE - 1);
1030
1031 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1032 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1033 char_count--;
1034 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001037 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001038ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001039 /* Update tx_put */
1040 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042}
1043
Jiri Slaby02f11752006-12-08 02:39:28 -08001044static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001046 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001047 struct tty_struct *tty;
1048 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001049 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001050 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001051 int special_count;
1052 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001054 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Jiri Slaby02f11752006-12-08 02:39:28 -08001056 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1057 special_count = 0;
1058 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001059 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001060 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001061 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001062 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001063
Jiri Slaby02f11752006-12-08 02:39:28 -08001064 switch (cmd) {
1065 case C_CM_PR_ERROR:
1066 tty_insert_flip_char(tty, 0, TTY_PARITY);
1067 info->icount.rx++;
1068 special_count++;
1069 break;
1070 case C_CM_FR_ERROR:
1071 tty_insert_flip_char(tty, 0, TTY_FRAME);
1072 info->icount.rx++;
1073 special_count++;
1074 break;
1075 case C_CM_RXBRK:
1076 tty_insert_flip_char(tty, 0, TTY_BREAK);
1077 info->icount.rx++;
1078 special_count++;
1079 break;
1080 case C_CM_MDCD:
1081 info->icount.dcd++;
1082 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001083 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001084 u32 dcd = fw_ver > 241 ? param :
1085 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001086 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001087 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001088 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001089 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001090 }
1091 break;
1092 case C_CM_MCTS:
1093 info->icount.cts++;
1094 delta_count++;
1095 break;
1096 case C_CM_MRI:
1097 info->icount.rng++;
1098 delta_count++;
1099 break;
1100 case C_CM_MDSR:
1101 info->icount.dsr++;
1102 delta_count++;
1103 break;
1104#ifdef Z_WAKE
1105 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001106 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001107 break;
1108#endif
1109#ifdef CONFIG_CYZ_INTR
1110 case C_CM_RXHIWM:
1111 case C_CM_RXNNDT:
1112 case C_CM_INTBACK2:
1113 /* Reception Interrupt */
1114#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001115 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1116 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001117#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001118 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001119 break;
1120 case C_CM_TXBEMPTY:
1121 case C_CM_TXLOWWM:
1122 case C_CM_INTBACK:
1123 /* Transmission Interrupt */
1124#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001125 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1126 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001127#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001128 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001129 break;
1130#endif /* CONFIG_CYZ_INTR */
1131 case C_CM_FATAL:
1132 /* should do something with this !!! */
1133 break;
1134 default:
1135 break;
1136 }
1137 if (delta_count)
Jiri Slabyebafeef2007-10-18 03:06:20 -07001138 wake_up_interruptible(&info->delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001139 if (special_count)
1140 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001141 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001142 }
1143}
1144
1145#ifdef CONFIG_CYZ_INTR
1146static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1147{
Jiri Slabyf7429032007-05-08 00:36:59 -07001148 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001149
Jiri Slaby2693f482009-06-11 12:31:06 +01001150 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001151#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001152 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1153 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001154#endif
1155 return IRQ_NONE;
1156 }
1157
1158 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 cyz_handle_cmd(cinfo);
1160
Jiri Slaby02f11752006-12-08 02:39:28 -08001161 return IRQ_HANDLED;
1162} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Jiri Slaby02f11752006-12-08 02:39:28 -08001164static void cyz_rx_restart(unsigned long arg)
1165{
1166 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001167 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001168 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001169 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001170 unsigned long flags;
1171
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001172 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001173 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001174 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001175 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001176 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001178 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001179}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
Jiri Slaby02f11752006-12-08 02:39:28 -08001181#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
Jiri Slaby02f11752006-12-08 02:39:28 -08001183static void cyz_poll(unsigned long arg)
1184{
1185 struct cyclades_card *cinfo;
1186 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001187 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001188 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001189
Jiri Slaby02f11752006-12-08 02:39:28 -08001190 for (card = 0; card < NR_CARDS; card++) {
1191 cinfo = &cy_card[card];
1192
Jiri Slaby2693f482009-06-11 12:31:06 +01001193 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001194 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001195 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001196 continue;
1197
Jiri Slaby02f11752006-12-08 02:39:28 -08001198 /* Skip first polling cycle to avoid racing conditions with the FW */
1199 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001200 cinfo->intr_enabled = 1;
1201 continue;
1202 }
1203
1204 cyz_handle_cmd(cinfo);
1205
1206 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001207 struct tty_struct *tty;
1208
Jiri Slabydd025c02007-05-08 00:37:02 -07001209 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001210 tty = tty_port_tty_get(&info->port);
1211 /* OK to pass NULL to the handle functions below.
1212 They need to drop the data in that case. */
1213
Jiri Slaby02f11752006-12-08 02:39:28 -08001214 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001215 cyz_handle_rx(info, tty);
1216 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001217 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001218 }
1219 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001220 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001221 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001222 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001223} /* cyz_poll */
1224
1225#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227/********** End of block of Cyclades-Z specific code *********/
1228/***********************************************************/
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230/* This is called whenever a port becomes active;
1231 interrupts are enabled and DTR & RTS are turned on.
1232 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001233static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234{
Jiri Slaby875b2062007-05-08 00:36:49 -07001235 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001236 unsigned long flags;
1237 int retval = 0;
1238 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001239 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001240 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Jiri Slaby02f11752006-12-08 02:39:28 -08001242 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001243 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Jiri Slaby02f11752006-12-08 02:39:28 -08001245 page = get_zeroed_page(GFP_KERNEL);
1246 if (!page)
1247 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001249 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Alan Cox77451e52008-07-16 21:57:02 +01001251 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001252 free_page(page);
1253 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001255
1256 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001257 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001258 free_page(page);
1259 goto errout;
1260 }
1261
Alan Cox77451e52008-07-16 21:57:02 +01001262 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001263 free_page(page);
1264 else
Alan Cox77451e52008-07-16 21:57:02 +01001265 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001267 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
Jiri Slabyd13549f2009-09-19 13:13:12 -07001269 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Jiri Slaby2693f482009-06-11 12:31:06 +01001271 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001272 chip = channel >> 2;
1273 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001274 index = card->bus_index;
1275 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001278 printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
1279 "base_addr %p\n",
1280 card, chip, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001281#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001282 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001283
1284 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1285
1286 cy_writeb(base_addr + (CyRTPR << index),
1287 (info->default_timeout ? info->default_timeout : 0x02));
1288 /* 10ms rx timeout */
1289
1290 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
1291 index);
1292
1293 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1294 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
1295 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
1296
1297#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07001298 printk(KERN_DEBUG "cyc:startup raising DTR\n");
1299 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001300 readb(base_addr + (CyMSVR1 << index)),
1301 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302#endif
1303
Jiri Slaby02f11752006-12-08 02:39:28 -08001304 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001305 readb(base_addr + (CySRER << index)) | CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001306 info->port.flags |= ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Jiri Slabyd13549f2009-09-19 13:13:12 -07001308 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001309 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1310 info->breakon = info->breakoff = 0;
1311 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1312 info->idle_stats.in_use =
1313 info->idle_stats.recv_idle =
1314 info->idle_stats.xmit_idle = jiffies;
1315
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001316 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001317
1318 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001319 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001320
Jiri Slaby2693f482009-06-11 12:31:06 +01001321 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001322 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001323
Jiri Slaby02f11752006-12-08 02:39:28 -08001324#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001325 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001326 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001327#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001328 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001329
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001330 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331#ifdef Z_WAKE
1332#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001333 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001334 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1335 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001337 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001338 C_IN_IOCTLW | C_IN_MDCD);
1339#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340#else
1341#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001342 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001343 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1344 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001346 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001347#endif /* CONFIG_CYZ_INTR */
1348#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Jiri Slaby875b2062007-05-08 00:36:49 -07001350 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001351 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001352 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1353 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Jiri Slaby02f11752006-12-08 02:39:28 -08001356 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001357 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001358 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001359 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1360 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
Jiri Slaby02f11752006-12-08 02:39:28 -08001363 /* set timeout !!! */
1364 /* set RTS and DTR !!! */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001365 cy_writel(&ch_ctrl->rs_control, readl(&ch_ctrl->rs_control) |
1366 C_RS_RTS | C_RS_DTR);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001367 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001368 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001369 printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
1370 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07001373 printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374#endif
1375
Jiri Slaby02f11752006-12-08 02:39:28 -08001376 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Alan Cox77451e52008-07-16 21:57:02 +01001378 info->port.flags |= ASYNC_INITIALIZED;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001379 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001380 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1381 info->breakon = info->breakoff = 0;
1382 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1383 info->idle_stats.in_use =
1384 info->idle_stats.recv_idle =
1385 info->idle_stats.xmit_idle = jiffies;
1386
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001387 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001391 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392#endif
1393 return 0;
1394
1395errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001396 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001398} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Jiri Slaby02f11752006-12-08 02:39:28 -08001400static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
Jiri Slaby875b2062007-05-08 00:36:49 -07001402 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001403 unsigned long flags;
1404 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001405 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Jiri Slaby02f11752006-12-08 02:39:28 -08001407 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001408 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001409 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001410 chip = channel >> 2;
1411 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001412 index = card->bus_index;
1413 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001415 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001416 cy_writeb(base_addr + (CyCAR << index), channel);
1417 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001418 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001419 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001420 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001422 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001424 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001425 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001426 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001427 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1428 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001429 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001430 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001431#else /* CONFIG_CYZ_INTR */
1432 /* Don't have to do anything at this time */
1433#endif /* CONFIG_CYZ_INTR */
1434 }
1435} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437/*
1438 * This routine shuts down a serial port; interrupts are disabled,
1439 * and DTR is dropped if the hangup on close termio flag is on.
1440 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001441static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442{
Jiri Slaby875b2062007-05-08 00:36:49 -07001443 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001444 unsigned long flags;
1445 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001446 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
Alan Cox77451e52008-07-16 21:57:02 +01001448 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001449 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Jiri Slaby02f11752006-12-08 02:39:28 -08001451 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001452 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001453 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001454 chip = channel >> 2;
1455 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001456 index = card->bus_index;
1457 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001460 printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
1461 "channel %d, base_addr %p\n",
1462 card, chip, channel, base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001465 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001466
1467 /* Clear delta_msr_wait queue to avoid mem leaks. */
1468 wake_up_interruptible(&info->delta_msr_wait);
1469
Alan Cox77451e52008-07-16 21:57:02 +01001470 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001471 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001472 temp = info->port.xmit_buf;
1473 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001474 free_page((unsigned long)temp);
1475 }
1476 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001477 if (tty->termios->c_cflag & HUPCL) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001478 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
1479 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
1480#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07001481 printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
1482 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001483 readb(base_addr + (CyMSVR1 << index)),
1484 readb(base_addr + (CyMSVR2 << index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08001485#endif
1486 }
1487 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
1488 /* it may be appropriate to clear _XMIT at
1489 some later date (after testing)!!! */
1490
Jiri Slabyd13549f2009-09-19 13:13:12 -07001491 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001492 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001493 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001494 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001495 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001496 int retval;
1497
Jiri Slaby02f11752006-12-08 02:39:28 -08001498#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001499 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001500 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001501#endif
1502
Jiri Slaby2693f482009-06-11 12:31:06 +01001503 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001504 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001505
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001506 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001507
Alan Cox77451e52008-07-16 21:57:02 +01001508 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001509 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001510 temp = info->port.xmit_buf;
1511 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001512 free_page((unsigned long)temp);
1513 }
1514
Jiri Slabyd13549f2009-09-19 13:13:12 -07001515 if (tty->termios->c_cflag & HUPCL) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001516 cy_writel(&ch_ctrl->rs_control,
1517 readl(&ch_ctrl->rs_control) &
1518 ~(C_RS_RTS | C_RS_DTR));
Jiri Slaby875b2062007-05-08 00:36:49 -07001519 retval = cyz_issue_cmd(info->card, channel,
Jiri Slaby02f11752006-12-08 02:39:28 -08001520 C_CM_IOCTLM, 0L);
1521 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001522 printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
1523 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001524 }
1525#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07001526 printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001527#endif
1528 }
1529
Jiri Slabyd13549f2009-09-19 13:13:12 -07001530 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001531 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001532
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001533 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001534 }
1535
1536#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001537 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001538#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001539} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
1541/*
1542 * ------------------------------------------------------------
1543 * cy_open() and friends
1544 * ------------------------------------------------------------
1545 */
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547/*
1548 * This routine is called whenever a serial port is opened. It
1549 * performs the serial-specific initialization for the tty structure.
1550 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001551static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552{
Jiri Slaby02f11752006-12-08 02:39:28 -08001553 struct cyclades_port *info;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001554 unsigned int i, line;
1555 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
Jiri Slaby02f11752006-12-08 02:39:28 -08001557 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001558 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001560
Jiri Slabydd025c02007-05-08 00:37:02 -07001561 for (i = 0; i < NR_CARDS; i++)
1562 if (line < cy_card[i].first_line + cy_card[i].nports &&
1563 line >= cy_card[i].first_line)
1564 break;
1565 if (i >= NR_CARDS)
1566 return -ENODEV;
1567 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001568 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001569 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001570
1571 /* If the card's firmware hasn't been loaded,
1572 treat it as absent from the system. This
1573 will make the user pay attention.
1574 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001575 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001576 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001577 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1578
Jiri Slaby2693f482009-06-11 12:31:06 +01001579 if (!cyz_is_loaded(cinfo)) {
1580 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001581 readl(&firm_id->signature) ==
1582 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001583 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1584 "need an external power supply for "
1585 "this number of ports.\nFirmware "
1586 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001587 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001588 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1589 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001590 }
1591 return -ENODEV;
1592 }
1593#ifdef CONFIG_CYZ_INTR
1594 else {
1595 /* In case this Z board is operating in interrupt mode, its
1596 interrupts should be enabled as soon as the first open
1597 happens to one of its ports. */
1598 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001599 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001600
Jiri Slaby02f11752006-12-08 02:39:28 -08001601 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001602 intr = readw(&cinfo->ctl_addr.p9060->
1603 intr_ctrl_stat) | 0x0900;
1604 cy_writew(&cinfo->ctl_addr.p9060->
1605 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001606 /* Enable interrupts on the FW */
1607 retval = cyz_issue_cmd(cinfo, 0,
1608 C_CM_IRQ_ENBL, 0L);
1609 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001610 printk(KERN_ERR "cyc:IRQ enable retval "
1611 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001613 cinfo->intr_enabled = 1;
1614 }
1615 }
1616#endif /* CONFIG_CYZ_INTR */
1617 /* Make sure this Z port really exists in hardware */
1618 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1619 return -ENODEV;
1620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001622 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001624 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001625 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001626 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001629 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001630 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631#endif
Alan Cox77451e52008-07-16 21:57:02 +01001632 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001634 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001635 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
Jiri Slaby02f11752006-12-08 02:39:28 -08001638 /*
1639 * If the port is the middle of closing, bail out now
1640 */
Alan Cox77451e52008-07-16 21:57:02 +01001641 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1642 wait_event_interruptible(info->port.close_wait,
1643 !(info->port.flags & ASYNC_CLOSING));
1644 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Jiri Slaby02f11752006-12-08 02:39:28 -08001647 /*
1648 * Start up serial port
1649 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001650 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001651 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001652 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Jiri Slabyf0737572009-09-19 13:13:12 -07001654 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001655 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001657 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1658 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001660 return retval;
1661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
Jiri Slaby02f11752006-12-08 02:39:28 -08001663 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001664 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001667 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001669 return 0;
1670} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672/*
1673 * cy_wait_until_sent() --- wait until the transmitter is empty
1674 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001675static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676{
Jiri Slaby875b2062007-05-08 00:36:49 -07001677 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001678 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001679 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001680 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001681 unsigned long orig_jiffies;
1682 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
Jiri Slaby02f11752006-12-08 02:39:28 -08001684 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1685 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Jiri Slaby02f11752006-12-08 02:39:28 -08001687 if (info->xmit_fifo_size == 0)
1688 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Jiri Slaby02f11752006-12-08 02:39:28 -08001690 orig_jiffies = jiffies;
Alan Cox978e5952008-04-30 00:53:59 -07001691 lock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08001692 /*
1693 * Set the check interval to be 1/5 of the estimated time to
1694 * send a single character, and make it at least 1. The check
1695 * interval should also be less than the timeout.
1696 *
1697 * Note: we have to use pretty tight timings here to satisfy
1698 * the NIST-PCTS.
1699 */
1700 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1701 char_time = char_time / 5;
1702 if (char_time <= 0)
1703 char_time = 1;
1704 if (timeout < 0)
1705 timeout = 0;
1706 if (timeout)
1707 char_time = min(char_time, timeout);
1708 /*
1709 * If the transmitter hasn't cleared in twice the approximate
1710 * amount of time to send the entire FIFO, it probably won't
1711 * ever clear. This assumes the UART isn't doing flow
1712 * control, which is currently the case. Hence, if it ever
1713 * takes longer than info->timeout, this is probably due to a
1714 * UART bug of some kind. So, we clamp the timeout parameter at
1715 * 2*info->timeout.
1716 */
1717 if (!timeout || timeout > 2 * info->timeout)
1718 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001720 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1721 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001723 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001724 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01001725 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001726 chip = channel >> 2;
1727 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001728 index = card->bus_index;
1729 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001730 while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001732 printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001734 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1735 break;
1736 if (timeout && time_after(jiffies, orig_jiffies +
1737 timeout))
1738 break;
1739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001741 /* Run one more char cycle */
1742 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Alan Cox978e5952008-04-30 00:53:59 -07001743 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001745 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746#endif
1747}
1748
Alan Cox978e5952008-04-30 00:53:59 -07001749static void cy_flush_buffer(struct tty_struct *tty)
1750{
1751 struct cyclades_port *info = tty->driver_data;
1752 struct cyclades_card *card;
1753 int channel, retval;
1754 unsigned long flags;
1755
1756#ifdef CY_DEBUG_IO
1757 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1758#endif
1759
1760 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1761 return;
1762
1763 card = info->card;
1764 channel = info->line - card->first_line;
1765
1766 spin_lock_irqsave(&card->card_lock, flags);
1767 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1768 spin_unlock_irqrestore(&card->card_lock, flags);
1769
Jiri Slaby2693f482009-06-11 12:31:06 +01001770 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001771 buffers as well */
1772 spin_lock_irqsave(&card->card_lock, flags);
1773 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1774 if (retval != 0) {
1775 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1776 "was %x\n", info->line, retval);
1777 }
1778 spin_unlock_irqrestore(&card->card_lock, flags);
1779 }
1780 tty_wakeup(tty);
1781} /* cy_flush_buffer */
1782
1783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784/*
1785 * This routine is called when a particular tty device is closed.
1786 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001787static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001789 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001790 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001791 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Alan Cox15ed6cc2008-04-30 00:53:55 -07001793 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001794 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001796 card = info->card;
1797
Jiri Slaby23342262009-09-19 13:13:13 -07001798 if (!tty_port_close_start(&info->port, tty, filp))
Jiri Slaby02f11752006-12-08 02:39:28 -08001799 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001800
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001801 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001802
Jiri Slaby2693f482009-06-11 12:31:06 +01001803 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001804 int channel = info->line - card->first_line;
1805 int index = card->bus_index;
1806 void __iomem *base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001807 (cy_chip_offset[channel >> 2] << index);
1808 /* Stop accepting input */
1809 channel &= 0x03;
1810 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1811 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001812 readb(base_addr + (CySRER << index)) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001813 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001814 /* Waiting for on-board buffers to be empty before
1815 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001816 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001817 cy_wait_until_sent(tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001818 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001819 }
1820 } else {
1821#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001822 /* Waiting for on-board buffers to be empty before closing
1823 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001824 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001825 int channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001826 int retval;
1827
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001828 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001829 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001830 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001831 printk(KERN_DEBUG "cyc:cy_close retval on "
1832 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001833 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001834 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001835 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001836 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001837 }
1838#endif
1839 }
1840
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001841 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001842 cy_shutdown(info, tty);
Alan Cox978e5952008-04-30 00:53:59 -07001843 cy_flush_buffer(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001844
Jiri Slabyd13549f2009-09-19 13:13:12 -07001845 tty_port_tty_set(&info->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
Jiri Slaby23342262009-09-19 13:13:13 -07001847 tty_port_close_end(&info->port, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001848} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850/* This routine gets called when tty_write has put something into
1851 * the write_queue. The characters may come from user space or
1852 * kernel space.
1853 *
1854 * This routine will return the number of characters actually
1855 * accepted for writing.
1856 *
1857 * If the port is not already transmitting stuff, start it off by
1858 * enabling interrupts. The interrupt service routine will then
1859 * ensure that the characters are sent.
1860 * If the port is already active, there is no need to kick it.
1861 *
1862 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001863static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001865 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001866 unsigned long flags;
1867 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
1869#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001870 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871#endif
1872
Alan Cox15ed6cc2008-04-30 00:53:55 -07001873 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001874 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
Alan Cox77451e52008-07-16 21:57:02 +01001876 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001877 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001879 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001880 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001881 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1882 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
Jiri Slaby02f11752006-12-08 02:39:28 -08001884 if (c <= 0)
1885 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
Alan Cox77451e52008-07-16 21:57:02 +01001887 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001888 info->xmit_head = (info->xmit_head + c) &
1889 (SERIAL_XMIT_SIZE - 1);
1890 info->xmit_cnt += c;
1891 buf += c;
1892 count -= c;
1893 ret += c;
1894 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001895 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Jiri Slaby02f11752006-12-08 02:39:28 -08001897 info->idle_stats.xmit_bytes += ret;
1898 info->idle_stats.xmit_idle = jiffies;
1899
Alan Cox15ed6cc2008-04-30 00:53:55 -07001900 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001901 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001902
Jiri Slaby02f11752006-12-08 02:39:28 -08001903 return ret;
1904} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906/*
1907 * This routine is called by the kernel to write a single
1908 * character to the tty device. If the kernel uses this routine,
1909 * it must call the flush_chars() routine (if defined) when it is
1910 * done stuffing characters into the driver. If there is no room
1911 * in the queue, the character is ignored.
1912 */
Alan Cox76b25a52008-04-30 00:54:03 -07001913static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001915 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001916 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001919 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920#endif
1921
Jiri Slaby02f11752006-12-08 02:39:28 -08001922 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001923 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
Alan Cox77451e52008-07-16 21:57:02 +01001925 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001926 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001928 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001929 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001930 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001931 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Alan Cox77451e52008-07-16 21:57:02 +01001934 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001935 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1936 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 info->idle_stats.xmit_bytes++;
1938 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001939 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001940 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001941} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943/*
1944 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001945 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001947static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001949 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001952 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953#endif
1954
Jiri Slaby02f11752006-12-08 02:39:28 -08001955 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1956 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Jiri Slaby02f11752006-12-08 02:39:28 -08001958 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001959 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001960 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
Jiri Slaby02f11752006-12-08 02:39:28 -08001962 start_xmit(info);
1963} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
1965/*
1966 * This routine returns the numbers of characters the tty driver
1967 * will accept for queuing to be written. This number is subject
1968 * to change as output buffers get emptied, or if the output flow
1969 * control is activated.
1970 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001971static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001973 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001974 int ret;
1975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001977 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978#endif
1979
Jiri Slaby02f11752006-12-08 02:39:28 -08001980 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1981 return 0;
1982 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1983 if (ret < 0)
1984 ret = 0;
1985 return ret;
1986} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Jiri Slaby02f11752006-12-08 02:39:28 -08001988static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001990 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
Jiri Slaby02f11752006-12-08 02:39:28 -08001992 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1993 return 0;
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001996 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001997#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001999 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2000 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002002 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002004 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002005 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002006 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07002007 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
Alan Cox978e5952008-04-30 00:53:59 -07002009 lock_kernel();
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002010 tx_get = readl(&buf_ctrl->tx_get);
2011 tx_put = readl(&buf_ctrl->tx_put);
2012 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08002013 if (tx_put >= tx_get)
2014 char_count = tx_put - tx_get;
2015 else
2016 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002018 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2019 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020#endif
Alan Cox978e5952008-04-30 00:53:59 -07002021 unlock_kernel();
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002022 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08002023 }
2024#endif /* Z_EXT_CHARS_IN_BUFFER */
2025} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
2027/*
2028 * ------------------------------------------------------------
2029 * cy_ioctl() and friends
2030 * ------------------------------------------------------------
2031 */
2032
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002033static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034{
Jiri Slaby02f11752006-12-08 02:39:28 -08002035 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002036 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08002037 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038
Jiri Slaby02f11752006-12-08 02:39:28 -08002039 if (baud == 0) {
2040 info->tbpr = info->tco = info->rbpr = info->rco = 0;
2041 return;
2042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Jiri Slaby02f11752006-12-08 02:39:28 -08002044 /* determine which prescaler to use */
2045 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
2046 if (cy_clock / co_val / baud > 63)
2047 break;
2048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Jiri Slaby02f11752006-12-08 02:39:28 -08002050 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
2051 if (bpr > 255)
2052 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Jiri Slaby02f11752006-12-08 02:39:28 -08002054 info->tbpr = info->rbpr = bpr;
2055 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056}
2057
2058/*
2059 * This routine finds or computes the various line characteristics.
2060 * It used to be called config_setup
2061 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002062static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063{
Jiri Slaby875b2062007-05-08 00:36:49 -07002064 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002065 unsigned long flags;
2066 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002067 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002068 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002069 int baud, baud_rate = 0;
2070 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Jiri Slabyd13549f2009-09-19 13:13:12 -07002072 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002073 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002074
2075 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002076 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002077
Jiri Slabyd13549f2009-09-19 13:13:12 -07002078 cflag = tty->termios->c_cflag;
2079 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Jiri Slaby02f11752006-12-08 02:39:28 -08002081 /*
2082 * Set up the tty->alt_speed kludge
2083 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002084 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2085 tty->alt_speed = 57600;
2086 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2087 tty->alt_speed = 115200;
2088 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2089 tty->alt_speed = 230400;
2090 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2091 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Jiri Slaby02f11752006-12-08 02:39:28 -08002093 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002094 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002095
Jiri Slaby2693f482009-06-11 12:31:06 +01002096 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002097
Jiri Slaby875b2062007-05-08 00:36:49 -07002098 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002099
2100 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002101 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002102 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002103 ASYNC_SPD_CUST) {
2104 if (info->custom_divisor)
2105 baud_rate = info->baud / info->custom_divisor;
2106 else
2107 baud_rate = info->baud;
2108 } else if (baud > CD1400_MAX_SPEED) {
2109 baud = CD1400_MAX_SPEED;
2110 }
2111 /* find the baud index */
2112 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002113 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002114 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002115 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002116 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002117 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002118
Alan Cox77451e52008-07-16 21:57:02 +01002119 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002120 ASYNC_SPD_CUST) {
2121 cyy_baud_calc(info, baud_rate);
2122 } else {
2123 if (info->chip_rev >= CD1400_REV_J) {
2124 /* It is a CD1400 rev. J or later */
2125 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2126 info->tco = baud_co_60[i]; /* Tx CO */
2127 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2128 info->rco = baud_co_60[i]; /* Rx CO */
2129 } else {
2130 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2131 info->tco = baud_co_25[i]; /* Tx CO */
2132 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2133 info->rco = baud_co_25[i]; /* Rx CO */
2134 }
2135 }
2136 if (baud_table[i] == 134) {
2137 /* get it right for 134.5 baud */
2138 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2139 2;
Alan Cox77451e52008-07-16 21:57:02 +01002140 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002141 ASYNC_SPD_CUST) {
2142 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2143 baud_rate) + 2;
2144 } else if (baud_table[i]) {
2145 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2146 baud_table[i]) + 2;
2147 /* this needs to be propagated into the card info */
2148 } else {
2149 info->timeout = 0;
2150 }
2151 /* By tradition (is it a standard?) a baud rate of zero
2152 implies the line should be/has been closed. A bit
2153 later in this routine such a test is performed. */
2154
2155 /* byte size and parity */
2156 info->cor5 = 0;
2157 info->cor4 = 0;
2158 /* receive threshold */
2159 info->cor3 = (info->default_threshold ?
2160 info->default_threshold : baud_cor3[i]);
2161 info->cor2 = CyETC;
2162 switch (cflag & CSIZE) {
2163 case CS5:
2164 info->cor1 = Cy_5_BITS;
2165 break;
2166 case CS6:
2167 info->cor1 = Cy_6_BITS;
2168 break;
2169 case CS7:
2170 info->cor1 = Cy_7_BITS;
2171 break;
2172 case CS8:
2173 info->cor1 = Cy_8_BITS;
2174 break;
2175 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002176 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002177 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002178
Jiri Slaby02f11752006-12-08 02:39:28 -08002179 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002180 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002181 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002182 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002183 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002184 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002185 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002186
2187 /* CTS flow control flag */
2188 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002189 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002190 info->cor2 |= CyCtsAE;
2191 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002192 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002193 info->cor2 &= ~CyCtsAE;
2194 }
2195 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002196 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002197 else
Alan Cox77451e52008-07-16 21:57:02 +01002198 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
2200 /***********************************************
2201 The hardware option, CyRtsAO, presents RTS when
2202 the chip has characters to send. Since most modems
2203 use RTS as reverse (inbound) flow control, this
2204 option is not used. If inbound flow control is
2205 necessary, DTR can be programmed to provide the
2206 appropriate signals for use with a non-standard
2207 cable. Contact Marcio Saito for details.
2208 ***********************************************/
2209
Jiri Slaby02f11752006-12-08 02:39:28 -08002210 chip = channel >> 2;
2211 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002212 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002214 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002215 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
Jiri Slaby02f11752006-12-08 02:39:28 -08002217 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Jiri Slaby02f11752006-12-08 02:39:28 -08002219 cy_writeb(base_addr + (CyTCOR << index), info->tco);
2220 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
2221 cy_writeb(base_addr + (CyRCOR << index), info->rco);
2222 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
Jiri Slaby02f11752006-12-08 02:39:28 -08002224 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Jiri Slabyd13549f2009-09-19 13:13:12 -07002226 cy_writeb(base_addr + (CySCHR1 << index), START_CHAR(tty));
2227 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(tty));
Jiri Slaby02f11752006-12-08 02:39:28 -08002228 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
2229 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
2230 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2231 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
2232 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Jiri Slaby02f11752006-12-08 02:39:28 -08002234 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2235 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Alan Cox15ed6cc2008-04-30 00:53:55 -07002237 /* !!! Is this needed? */
2238 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08002239 cy_writeb(base_addr + (CyRTPR << index),
2240 (info->default_timeout ? info->default_timeout : 0x02));
2241 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Jiri Slabyd13549f2009-09-19 13:13:12 -07002243 if (C_CLOCAL(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002244 /* without modem intr */
2245 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002246 readb(base_addr + (CySRER << index)) | CyMdmCh);
Jiri Slaby02f11752006-12-08 02:39:28 -08002247 /* act on 1->0 modem transitions */
2248 if ((cflag & CRTSCTS) && info->rflow) {
2249 cy_writeb(base_addr + (CyMCOR1 << index),
2250 (CyCTS | rflow_thr[i]));
2251 } else {
2252 cy_writeb(base_addr + (CyMCOR1 << index),
2253 CyCTS);
2254 }
2255 /* act on 0->1 modem transitions */
2256 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002258 /* without modem intr */
2259 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002260 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002261 (CySRER << index)) | CyMdmCh);
2262 /* act on 1->0 modem transitions */
2263 if ((cflag & CRTSCTS) && info->rflow) {
2264 cy_writeb(base_addr + (CyMCOR1 << index),
2265 (CyDSR | CyCTS | CyRI | CyDCD |
2266 rflow_thr[i]));
2267 } else {
2268 cy_writeb(base_addr + (CyMCOR1 << index),
2269 CyDSR | CyCTS | CyRI | CyDCD);
2270 }
2271 /* act on 0->1 modem transitions */
2272 cy_writeb(base_addr + (CyMCOR2 << index),
2273 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002275
2276 if (i == 0) { /* baud rate is zero, turn off line */
2277 if (info->rtsdtr_inv) {
2278 cy_writeb(base_addr + (CyMSVR1 << index),
2279 ~CyRTS);
2280 } else {
2281 cy_writeb(base_addr + (CyMSVR2 << index),
2282 ~CyDTR);
2283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002285 printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
2286 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002287 readb(base_addr + (CyMSVR1 << index)),
2288 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002290 } else {
2291 if (info->rtsdtr_inv) {
2292 cy_writeb(base_addr + (CyMSVR1 << index),
2293 CyRTS);
2294 } else {
2295 cy_writeb(base_addr + (CyMSVR2 << index),
2296 CyDTR);
2297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002299 printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
2300 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002301 readb(base_addr + (CyMSVR1 << index)),
2302 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
Jiri Slabyd13549f2009-09-19 13:13:12 -07002306 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002307 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002310 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002311 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002312 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Jiri Slaby2693f482009-06-11 12:31:06 +01002314 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002315 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
Jiri Slaby02f11752006-12-08 02:39:28 -08002317 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002318 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002319 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002320 ASYNC_SPD_CUST) {
2321 if (info->custom_divisor)
2322 baud_rate = info->baud / info->custom_divisor;
2323 else
2324 baud_rate = info->baud;
2325 } else if (baud > CYZ_MAX_SPEED) {
2326 baud = CYZ_MAX_SPEED;
2327 }
2328 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Jiri Slaby02f11752006-12-08 02:39:28 -08002330 if (baud == 134) {
2331 /* get it right for 134.5 baud */
2332 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2333 2;
Alan Cox77451e52008-07-16 21:57:02 +01002334 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002335 ASYNC_SPD_CUST) {
2336 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2337 baud_rate) + 2;
2338 } else if (baud) {
2339 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2340 baud) + 2;
2341 /* this needs to be propagated into the card info */
2342 } else {
2343 info->timeout = 0;
2344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Jiri Slaby02f11752006-12-08 02:39:28 -08002346 /* byte size and parity */
2347 switch (cflag & CSIZE) {
2348 case CS5:
2349 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2350 break;
2351 case CS6:
2352 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2353 break;
2354 case CS7:
2355 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2356 break;
2357 case CS8:
2358 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2359 break;
2360 }
2361 if (cflag & CSTOPB) {
2362 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002363 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002364 } else {
2365 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002366 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002367 }
2368 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002369 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002370 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002371 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002372 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002373 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002374 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
Jiri Slaby02f11752006-12-08 02:39:28 -08002376 /* CTS flow control flag */
2377 if (cflag & CRTSCTS) {
2378 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002379 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002380 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002381 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2382 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002383 }
2384 /* As the HW flow control is done in firmware, the driver
2385 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002386 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002387
2388 /* XON/XOFF/XANY flow control flags */
2389 sw_flow = 0;
2390 if (iflag & IXON) {
2391 sw_flow |= C_FL_OXX;
2392 if (iflag & IXANY)
2393 sw_flow |= C_FL_OIXANY;
2394 }
2395 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2396
Jiri Slaby875b2062007-05-08 00:36:49 -07002397 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002398 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002399 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2400 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002401 }
2402
2403 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002404 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002405 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002406 else
Alan Cox77451e52008-07-16 21:57:02 +01002407 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002408
2409 if (baud == 0) { /* baud rate is zero, turn off line */
2410 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002411 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002413 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002415 } else {
2416 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002417 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002419 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
Alan Cox15ed6cc2008-04-30 00:53:55 -07002423 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002424 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002425 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2426 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Jiri Slabyd13549f2009-09-19 13:13:12 -07002429 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002431} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
2433static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002434get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002435 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436{
Jiri Slaby02f11752006-12-08 02:39:28 -08002437 struct serial_struct tmp;
Jiri Slaby875b2062007-05-08 00:36:49 -07002438 struct cyclades_card *cinfo = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Jiri Slaby02f11752006-12-08 02:39:28 -08002440 if (!retinfo)
2441 return -EFAULT;
2442 memset(&tmp, 0, sizeof(tmp));
2443 tmp.type = info->type;
2444 tmp.line = info->line;
Jiri Slaby875b2062007-05-08 00:36:49 -07002445 tmp.port = (info->card - cy_card) * 0x100 + info->line -
2446 cinfo->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002447 tmp.irq = cinfo->irq;
Alan Cox77451e52008-07-16 21:57:02 +01002448 tmp.flags = info->port.flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01002449 tmp.close_delay = info->port.close_delay;
2450 tmp.closing_wait = info->port.closing_wait;
Jiri Slaby02f11752006-12-08 02:39:28 -08002451 tmp.baud_base = info->baud;
2452 tmp.custom_divisor = info->custom_divisor;
2453 tmp.hub6 = 0; /*!!! */
2454 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
2455} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
2457static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002458cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002459 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460{
Jiri Slaby02f11752006-12-08 02:39:28 -08002461 struct serial_struct new_serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
Jiri Slaby02f11752006-12-08 02:39:28 -08002463 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2464 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Jiri Slaby02f11752006-12-08 02:39:28 -08002466 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002467 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002468 new_serial.baud_base != info->baud ||
2469 (new_serial.flags & ASYNC_FLAGS &
2470 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002471 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Jiri Slaby02f11752006-12-08 02:39:28 -08002472 return -EPERM;
Alan Cox77451e52008-07-16 21:57:02 +01002473 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002474 (new_serial.flags & ASYNC_USR_MASK);
2475 info->baud = new_serial.baud_base;
2476 info->custom_divisor = new_serial.custom_divisor;
2477 goto check_and_exit;
2478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
Jiri Slaby02f11752006-12-08 02:39:28 -08002480 /*
2481 * OK, past this point, all the error checking has been done.
2482 * At this point, we start making changes.....
2483 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484
Jiri Slaby02f11752006-12-08 02:39:28 -08002485 info->baud = new_serial.baud_base;
2486 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002487 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002488 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002489 info->port.close_delay = new_serial.close_delay * HZ / 100;
2490 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002493 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002494 cy_set_line_char(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002495 return 0;
2496 } else {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002497 return cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002498 }
2499} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501/*
2502 * get_lsr_info - get line status register info
2503 *
2504 * Purpose: Let user call ioctl() to get info when the UART physically
2505 * is emptied. On bus types like RS485, the transmitter must
2506 * release the bus after transmitting. This must be done when
2507 * the transmit shift register is empty, not be done when the
2508 * transmit holding register is empty. This functionality
2509 * allows an RS485 driver to be written in user space.
2510 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002511static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512{
Jiri Slaby875b2062007-05-08 00:36:49 -07002513 struct cyclades_card *card;
2514 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002515 unsigned char status;
2516 unsigned int result;
2517 unsigned long flags;
2518 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
Jiri Slaby02f11752006-12-08 02:39:28 -08002520 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002521 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002522 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002523 chip = channel >> 2;
2524 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002525 index = card->bus_index;
2526 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002528 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002529 status = readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002530 (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002531 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002532 result = (status ? 0 : TIOCSER_TEMT);
2533 } else {
2534 /* Not supported yet */
2535 return -EINVAL;
2536 }
2537 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538}
2539
Jiri Slaby02f11752006-12-08 02:39:28 -08002540static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002542 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002543 struct cyclades_card *card;
2544 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002545 void __iomem *base_addr;
2546 unsigned long flags;
2547 unsigned char status;
2548 unsigned long lstatus;
2549 unsigned int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002551 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002552 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553
Alan Cox7b130c02008-04-30 00:53:16 -07002554 lock_kernel();
2555
Jiri Slaby02f11752006-12-08 02:39:28 -08002556 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002557 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002558 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002559 chip = channel >> 2;
2560 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002561 index = card->bus_index;
2562 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002564 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002565 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002566 status = readb(base_addr + (CyMSVR1 << index));
2567 status |= readb(base_addr + (CyMSVR2 << index));
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002568 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
Jiri Slaby02f11752006-12-08 02:39:28 -08002570 if (info->rtsdtr_inv) {
2571 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2572 ((status & CyDTR) ? TIOCM_RTS : 0);
2573 } else {
2574 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2575 ((status & CyDTR) ? TIOCM_DTR : 0);
2576 }
2577 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2578 ((status & CyRI) ? TIOCM_RNG : 0) |
2579 ((status & CyDSR) ? TIOCM_DSR : 0) |
2580 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002582 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002583 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby02f11752006-12-08 02:39:28 -08002584 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2585 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2586 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2587 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2588 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2589 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
2590 } else {
2591 result = 0;
Alan Cox7b130c02008-04-30 00:53:16 -07002592 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002593 return -ENODEV;
2594 }
2595
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 }
Alan Cox7b130c02008-04-30 00:53:16 -07002597 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002598 return result;
2599} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
2601static int
2602cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08002603 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002605 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002606 struct cyclades_card *card;
2607 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002608 unsigned long flags;
Jiri Slaby02f11752006-12-08 02:39:28 -08002609 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002611 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002612 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
Jiri Slaby02f11752006-12-08 02:39:28 -08002614 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002615 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002616 if (!cy_is_Z(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002617 void __iomem *base_addr;
Jiri Slaby02f11752006-12-08 02:39:28 -08002618 chip = channel >> 2;
2619 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002620 index = card->bus_index;
2621 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
Jiri Slaby02f11752006-12-08 02:39:28 -08002623 if (set & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002624 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002625 cy_writeb(base_addr + (CyCAR << index),
2626 (u_char) channel);
2627 if (info->rtsdtr_inv) {
2628 cy_writeb(base_addr + (CyMSVR2 << index),
2629 CyDTR);
2630 } else {
2631 cy_writeb(base_addr + (CyMSVR1 << index),
2632 CyRTS);
2633 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002634 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002635 }
2636 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002637 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002638 cy_writeb(base_addr + (CyCAR << index),
2639 (u_char) channel);
2640 if (info->rtsdtr_inv) {
2641 cy_writeb(base_addr + (CyMSVR2 << index),
2642 ~CyDTR);
2643 } else {
2644 cy_writeb(base_addr + (CyMSVR1 << index),
2645 ~CyRTS);
2646 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002647 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002648 }
2649 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002650 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002651 cy_writeb(base_addr + (CyCAR << index),
2652 (u_char) channel);
2653 if (info->rtsdtr_inv) {
2654 cy_writeb(base_addr + (CyMSVR1 << index),
2655 CyRTS);
2656 } else {
2657 cy_writeb(base_addr + (CyMSVR2 << index),
2658 CyDTR);
2659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002661 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
2662 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002663 readb(base_addr + (CyMSVR1 << index)),
2664 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002666 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002667 }
2668 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002669 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002670 cy_writeb(base_addr + (CyCAR << index),
2671 (u_char) channel);
2672 if (info->rtsdtr_inv) {
2673 cy_writeb(base_addr + (CyMSVR1 << index),
2674 ~CyRTS);
2675 } else {
2676 cy_writeb(base_addr + (CyMSVR2 << index),
2677 ~CyDTR);
2678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002681 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
2682 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002683 readb(base_addr + (CyMSVR1 << index)),
2684 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002686 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002687 }
2688 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002689 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002690 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002691
2692 if (set & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002693 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002694 cy_writel(&ch_ctrl->rs_control,
2695 readl(&ch_ctrl->rs_control) | C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002696 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002697 }
2698 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002699 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002700 cy_writel(&ch_ctrl->rs_control,
2701 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002702 ~C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002703 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002704 }
2705 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002706 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002707 cy_writel(&ch_ctrl->rs_control,
2708 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002709#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002710 printk(KERN_DEBUG "cyc:set_modem_info raising "
2711 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002712#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002713 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002714 }
2715 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002716 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002717 cy_writel(&ch_ctrl->rs_control,
2718 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002719 ~C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002720#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002721 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2722 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002723#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002724 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002725 }
2726 } else {
2727 return -ENODEV;
2728 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002729 spin_lock_irqsave(&card->card_lock, flags);
2730 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002731 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002732 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2733 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002735 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002737 return 0;
2738} /* cy_tiocmset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740/*
2741 * cy_break() --- routine which turns the break handling on or off
2742 */
Alan Cox9e989662008-07-22 11:18:03 +01002743static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002745 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002746 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002747 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002748 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
Jiri Slaby02f11752006-12-08 02:39:28 -08002750 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002751 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002753 card = info->card;
2754
2755 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002756 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002757 /* Let the transmit ISR take care of this (since it
2758 requires stuffing characters into the output stream).
2759 */
2760 if (break_state == -1) {
2761 if (!info->breakon) {
2762 info->breakon = 1;
2763 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002764 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002765 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002766 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002767 }
2768 }
2769 } else {
2770 if (!info->breakoff) {
2771 info->breakoff = 1;
2772 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002773 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002774 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002775 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002776 }
2777 }
2778 }
2779 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002780 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002781 retval = cyz_issue_cmd(card,
2782 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002783 C_CM_SET_BREAK, 0L);
2784 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002785 printk(KERN_ERR "cyc:cy_break (set) retval on "
2786 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002787 }
2788 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002789 retval = cyz_issue_cmd(card,
2790 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002791 C_CM_CLR_BREAK, 0L);
2792 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002793 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2794 "on ttyC%d was %x\n", info->line,
2795 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002796 }
2797 }
2798 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002799 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002800 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002801} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Alan Cox15ed6cc2008-04-30 00:53:55 -07002803static int get_mon_info(struct cyclades_port *info,
2804 struct cyclades_monitor __user *mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805{
Jiri Slaby02f11752006-12-08 02:39:28 -08002806 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
2807 return -EFAULT;
2808 info->mon.int_count = 0;
2809 info->mon.char_count = 0;
2810 info->mon.char_max = 0;
2811 info->mon.char_last = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002813} /* get_mon_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Jiri Slaby02f11752006-12-08 02:39:28 -08002815static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816{
Jiri Slaby875b2062007-05-08 00:36:49 -07002817 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002818 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002819 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002820 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
Jiri Slaby02f11752006-12-08 02:39:28 -08002822 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002823 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002824 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002825 chip = channel >> 2;
2826 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002827 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002828 base_addr =
Jiri Slaby875b2062007-05-08 00:36:49 -07002829 card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
Jiri Slaby02f11752006-12-08 02:39:28 -08002831 info->cor3 &= ~CyREC_FIFO;
2832 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002834 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002835 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2836 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002837 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002840} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
Alan Cox15ed6cc2008-04-30 00:53:55 -07002842static int get_threshold(struct cyclades_port *info,
2843 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844{
Jiri Slaby875b2062007-05-08 00:36:49 -07002845 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002846 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002847 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002848 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
Jiri Slaby02f11752006-12-08 02:39:28 -08002850 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002851 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002852 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002853 chip = channel >> 2;
2854 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002855 index = card->bus_index;
2856 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002857
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002858 tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002859 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002860 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002861 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002862} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
Alan Cox15ed6cc2008-04-30 00:53:55 -07002864static int set_default_threshold(struct cyclades_port *info,
2865 unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866{
Jiri Slaby02f11752006-12-08 02:39:28 -08002867 info->default_threshold = value & 0x0f;
2868 return 0;
2869} /* set_default_threshold */
2870
Alan Cox15ed6cc2008-04-30 00:53:55 -07002871static int get_default_threshold(struct cyclades_port *info,
2872 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002873{
2874 return put_user(info->default_threshold, value);
2875} /* get_default_threshold */
2876
2877static int set_timeout(struct cyclades_port *info, unsigned long value)
2878{
Jiri Slaby875b2062007-05-08 00:36:49 -07002879 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002880 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002881 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002882 unsigned long flags;
2883
2884 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002885 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002886 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002887 chip = channel >> 2;
2888 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002889 index = card->bus_index;
2890 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002891
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002892 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002893 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002894 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002895 }
2896 return 0;
2897} /* set_timeout */
2898
Alan Cox15ed6cc2008-04-30 00:53:55 -07002899static int get_timeout(struct cyclades_port *info,
2900 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002901{
Jiri Slaby875b2062007-05-08 00:36:49 -07002902 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002903 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002904 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002905 unsigned long tmp;
2906
2907 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002908 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002909 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002910 chip = channel >> 2;
2911 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002912 index = card->bus_index;
2913 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002914
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002915 tmp = readb(base_addr + (CyRTPR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08002916 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002917 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002918 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002919} /* get_timeout */
2920
2921static int set_default_timeout(struct cyclades_port *info, unsigned long value)
2922{
2923 info->default_timeout = value & 0xff;
2924 return 0;
2925} /* set_default_timeout */
2926
Alan Cox15ed6cc2008-04-30 00:53:55 -07002927static int get_default_timeout(struct cyclades_port *info,
2928 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002929{
2930 return put_user(info->default_timeout, value);
2931} /* get_default_timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932
2933/*
2934 * This routine allows the tty driver to implement device-
2935 * specific ioctl's. If the ioctl number passed in cmd is
2936 * not recognized by the driver, it should return ENOIOCTLCMD.
2937 */
2938static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002939cy_ioctl(struct tty_struct *tty, struct file *file,
2940 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002942 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002943 struct cyclades_icount cprev, cnow; /* kernel counter temps */
2944 struct serial_icounter_struct __user *p_cuser; /* user space */
2945 int ret_val = 0;
2946 unsigned long flags;
2947 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
Jiri Slaby02f11752006-12-08 02:39:28 -08002949 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2950 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
2952#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002953 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2954 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955#endif
Alan Cox7b130c02008-04-30 00:53:16 -07002956 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957
Jiri Slaby02f11752006-12-08 02:39:28 -08002958 switch (cmd) {
2959 case CYGETMON:
2960 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002962 case CYGETTHRESH:
2963 ret_val = get_threshold(info, argp);
2964 break;
2965 case CYSETTHRESH:
2966 ret_val = set_threshold(info, arg);
2967 break;
2968 case CYGETDEFTHRESH:
2969 ret_val = get_default_threshold(info, argp);
2970 break;
2971 case CYSETDEFTHRESH:
2972 ret_val = set_default_threshold(info, arg);
2973 break;
2974 case CYGETTIMEOUT:
2975 ret_val = get_timeout(info, argp);
2976 break;
2977 case CYSETTIMEOUT:
2978 ret_val = set_timeout(info, arg);
2979 break;
2980 case CYGETDEFTIMEOUT:
2981 ret_val = get_default_timeout(info, argp);
2982 break;
2983 case CYSETDEFTIMEOUT:
2984 ret_val = set_default_timeout(info, arg);
2985 break;
2986 case CYSETRFLOW:
2987 info->rflow = (int)arg;
2988 ret_val = 0;
2989 break;
2990 case CYGETRFLOW:
2991 ret_val = info->rflow;
2992 break;
2993 case CYSETRTSDTR_INV:
2994 info->rtsdtr_inv = (int)arg;
2995 ret_val = 0;
2996 break;
2997 case CYGETRTSDTR_INV:
2998 ret_val = info->rtsdtr_inv;
2999 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08003001 ret_val = info->chip_rev;
3002 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003#ifndef CONFIG_CYZ_INTR
3004 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08003005 cyz_polling_cycle = (arg * HZ) / 1000;
3006 ret_val = 0;
3007 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08003009 ret_val = (cyz_polling_cycle * 1000) / HZ;
3010 break;
3011#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01003013 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08003014 ret_val = 0;
3015 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01003017 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08003018 break;
3019 case TIOCGSERIAL:
3020 ret_val = get_serial_info(info, argp);
3021 break;
3022 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07003023 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08003024 break;
3025 case TIOCSERGETLSR: /* Get line status register */
3026 ret_val = get_lsr_info(info, argp);
3027 break;
3028 /*
3029 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
3030 * - mask passed in arg for lines of interest
3031 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
3032 * Caller should use TIOCGICOUNT to see which one it was
3033 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003035 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003036 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003037 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003038 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003039 ret_val = wait_event_interruptible(info->delta_msr_wait, ({
3040 cprev = cnow;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003041 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003042 cnow = info->icount; /* atomic copy */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003043 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003045 ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
3046 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
3047 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
3048 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
3049 }));
3050 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003051
3052 /*
3053 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
3054 * Return: write counters to the user passed counter struct
3055 * NB: both 1->0 and 0->1 transitions are counted except for
3056 * RI where only 0->1 is counted.
3057 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 case TIOCGICOUNT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003059 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003060 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003061 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003062 p_cuser = argp;
3063 ret_val = put_user(cnow.cts, &p_cuser->cts);
3064 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003065 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003066 ret_val = put_user(cnow.dsr, &p_cuser->dsr);
3067 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003068 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003069 ret_val = put_user(cnow.rng, &p_cuser->rng);
3070 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003071 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003072 ret_val = put_user(cnow.dcd, &p_cuser->dcd);
3073 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003074 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003075 ret_val = put_user(cnow.rx, &p_cuser->rx);
3076 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003077 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003078 ret_val = put_user(cnow.tx, &p_cuser->tx);
3079 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003080 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003081 ret_val = put_user(cnow.frame, &p_cuser->frame);
3082 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003083 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003084 ret_val = put_user(cnow.overrun, &p_cuser->overrun);
3085 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003086 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003087 ret_val = put_user(cnow.parity, &p_cuser->parity);
3088 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003089 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003090 ret_val = put_user(cnow.brk, &p_cuser->brk);
3091 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003092 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003093 ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
3094 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003095 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003096 ret_val = 0;
3097 break;
3098 default:
3099 ret_val = -ENOIOCTLCMD;
3100 }
Alan Cox7b130c02008-04-30 00:53:16 -07003101 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102
3103#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003104 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003106 return ret_val;
3107} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108
3109/*
3110 * This routine allows the tty driver to be notified when
3111 * device's termios settings have changed. Note that a
3112 * well-designed tty driver should be prepared to accept the case
3113 * where old == NULL, and try to do something rational.
3114 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003115static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003117 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118
3119#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003120 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121#endif
3122
Jiri Slabyd13549f2009-09-19 13:13:12 -07003123 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
Jiri Slaby02f11752006-12-08 02:39:28 -08003125 if ((old_termios->c_cflag & CRTSCTS) &&
3126 !(tty->termios->c_cflag & CRTSCTS)) {
3127 tty->hw_stopped = 0;
3128 cy_start(tty);
3129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08003131 /*
3132 * No need to wake up processes in open wait, since they
3133 * sample the CLOCAL flag once, and don't recheck it.
3134 * XXX It's not clear whether the current behavior is correct
3135 * or not. Hence, this may change.....
3136 */
3137 if (!(old_termios->c_cflag & CLOCAL) &&
3138 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01003139 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003141} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
3143/* This function is used to send a high-priority XON/XOFF character to
3144 the device.
3145*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003146static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003148 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003149 struct cyclades_card *card;
3150 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
Jiri Slaby02f11752006-12-08 02:39:28 -08003152 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 return;
3154
Jiri Slaby02f11752006-12-08 02:39:28 -08003155 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
3157 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08003158 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159
3160 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003161 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Jiri Slaby2693f482009-06-11 12:31:06 +01003163 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003164 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003165 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003166 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003167 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 }
3169}
3170
3171/* This routine is called by the upper-layer tty layer to signal
3172 that incoming characters should be throttled because the input
3173 buffers are close to full.
3174 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003175static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003177 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003178 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003179 unsigned long flags;
3180 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07003181 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
3183#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003184 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Jiri Slaby21719192007-05-08 00:36:42 -07003186 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08003187 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188#endif
3189
Alan Cox15ed6cc2008-04-30 00:53:55 -07003190 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003191 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
Jiri Slaby02f11752006-12-08 02:39:28 -08003193 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Jiri Slaby02f11752006-12-08 02:39:28 -08003195 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003196 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08003197 cy_send_xchar(tty, STOP_CHAR(tty));
3198 else
3199 info->throttle = 1;
3200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
Jiri Slaby02f11752006-12-08 02:39:28 -08003202 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby875b2062007-05-08 00:36:49 -07003203 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003204 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003205 chip = channel >> 2;
3206 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003207 index = card->bus_index;
3208 base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003209 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003211 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003212 cy_writeb(base_addr + (CyCAR << index),
3213 (u_char) channel);
3214 if (info->rtsdtr_inv) {
3215 cy_writeb(base_addr + (CyMSVR2 << index),
3216 ~CyDTR);
3217 } else {
3218 cy_writeb(base_addr + (CyMSVR1 << index),
3219 ~CyRTS);
3220 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003221 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003222 } else {
3223 info->throttle = 1;
3224 }
3225 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003226} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
3228/*
3229 * This routine notifies the tty driver that it should signal
3230 * that characters can now be sent to the tty without fear of
3231 * overrunning the input buffers of the line disciplines.
3232 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003233static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003235 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003236 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003237 unsigned long flags;
3238 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07003239 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
3241#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003242 char buf[64];
3243
Jiri Slaby21719192007-05-08 00:36:42 -07003244 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07003245 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246#endif
3247
Alan Cox15ed6cc2008-04-30 00:53:55 -07003248 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003249 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250
Jiri Slaby02f11752006-12-08 02:39:28 -08003251 if (I_IXOFF(tty)) {
3252 if (info->x_char)
3253 info->x_char = 0;
3254 else
3255 cy_send_xchar(tty, START_CHAR(tty));
3256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
Jiri Slaby02f11752006-12-08 02:39:28 -08003258 if (tty->termios->c_cflag & CRTSCTS) {
3259 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003260 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003261 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003262 chip = channel >> 2;
3263 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003264 index = card->bus_index;
3265 base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003266 (cy_chip_offset[chip] << index);
3267
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003268 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003269 cy_writeb(base_addr + (CyCAR << index),
3270 (u_char) channel);
3271 if (info->rtsdtr_inv) {
3272 cy_writeb(base_addr + (CyMSVR2 << index),
3273 CyDTR);
3274 } else {
3275 cy_writeb(base_addr + (CyMSVR1 << index),
3276 CyRTS);
3277 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003278 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003279 } else {
3280 info->throttle = 0;
3281 }
3282 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003283} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
3285/* cy_start and cy_stop provide software output flow control as a
3286 function of XON/XOFF, software CTS, and other such stuff.
3287*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003288static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289{
Jiri Slaby02f11752006-12-08 02:39:28 -08003290 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003291 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003292 void __iomem *base_addr;
3293 int chip, channel, index;
3294 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
3296#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003297 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298#endif
3299
Jiri Slaby02f11752006-12-08 02:39:28 -08003300 if (serial_paranoia_check(info, tty->name, "cy_stop"))
3301 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
Jiri Slaby875b2062007-05-08 00:36:49 -07003303 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003304 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003305 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003306 index = cinfo->bus_index;
3307 chip = channel >> 2;
3308 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003309 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003311 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003312 cy_writeb(base_addr + (CyCAR << index),
3313 (u_char)(channel & 0x0003)); /* index channel */
3314 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003315 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003316 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003318} /* cy_stop */
3319
3320static void cy_start(struct tty_struct *tty)
3321{
3322 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003323 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003324 void __iomem *base_addr;
3325 int chip, channel, index;
3326 unsigned long flags;
3327
3328#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003329 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08003330#endif
3331
3332 if (serial_paranoia_check(info, tty->name, "cy_start"))
3333 return;
3334
Jiri Slaby875b2062007-05-08 00:36:49 -07003335 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003336 channel = info->line - cinfo->first_line;
3337 index = cinfo->bus_index;
Jiri Slaby2693f482009-06-11 12:31:06 +01003338 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003339 chip = channel >> 2;
3340 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003341 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003342
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003343 spin_lock_irqsave(&cinfo->card_lock, flags);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003344 cy_writeb(base_addr + (CyCAR << index),
3345 (u_char) (channel & 0x0003)); /* index channel */
Jiri Slaby02f11752006-12-08 02:39:28 -08003346 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003347 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003348 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003349 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003350} /* cy_start */
3351
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352/*
3353 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3354 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003355static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003357 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003360 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361#endif
3362
Jiri Slaby02f11752006-12-08 02:39:28 -08003363 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3364 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
Jiri Slaby02f11752006-12-08 02:39:28 -08003366 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003367 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003368 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003369} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Jiri Slabyf0737572009-09-19 13:13:12 -07003371static int cyy_carrier_raised(struct tty_port *port)
3372{
3373 struct cyclades_port *info = container_of(port, struct cyclades_port,
3374 port);
3375 struct cyclades_card *cinfo = info->card;
3376 void __iomem *base = cinfo->base_addr;
3377 unsigned long flags;
3378 int channel = info->line - cinfo->first_line;
3379 int chip = channel >> 2, index = cinfo->bus_index;
3380 u32 cd;
3381
3382 channel &= 0x03;
3383 base += cy_chip_offset[chip] << index;
3384
3385 spin_lock_irqsave(&cinfo->card_lock, flags);
3386 cy_writeb(base + (CyCAR << index), (u8)channel);
3387 cd = readb(base + (CyMSVR1 << index)) & CyDCD;
3388 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3389
3390 return cd;
3391}
3392
3393static void cyy_dtr_rts(struct tty_port *port, int raise)
3394{
3395 struct cyclades_port *info = container_of(port, struct cyclades_port,
3396 port);
3397 struct cyclades_card *cinfo = info->card;
3398 void __iomem *base = cinfo->base_addr;
3399 unsigned long flags;
3400 int channel = info->line - cinfo->first_line;
3401 int chip = channel >> 2, index = cinfo->bus_index;
3402
3403 channel &= 0x03;
3404 base += cy_chip_offset[chip] << index;
3405
3406 spin_lock_irqsave(&cinfo->card_lock, flags);
3407 cy_writeb(base + (CyCAR << index), (u8)channel);
3408 cy_writeb(base + (CyMSVR1 << index), raise ? CyRTS : ~CyRTS);
3409 cy_writeb(base + (CyMSVR2 << index), raise ? CyDTR : ~CyDTR);
3410#ifdef CY_DEBUG_DTR
3411 printk(KERN_DEBUG "%s: raising DTR\n", __func__);
3412 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
3413 readb(base + (CyMSVR1 << index)),
3414 readb(base + (CyMSVR2 << index)));
3415#endif
3416 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3417}
3418
3419static int cyz_carrier_raised(struct tty_port *port)
3420{
3421 struct cyclades_port *info = container_of(port, struct cyclades_port,
3422 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003423
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003424 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003425}
3426
3427static void cyz_dtr_rts(struct tty_port *port, int raise)
3428{
3429 struct cyclades_port *info = container_of(port, struct cyclades_port,
3430 port);
3431 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003432 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003433 int ret, channel = info->line - cinfo->first_line;
3434 u32 rs;
3435
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003436 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003437 if (raise)
3438 rs |= C_RS_RTS | C_RS_DTR;
3439 else
3440 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003441 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003442 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3443 if (ret != 0)
3444 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3445 __func__, info->line, ret);
3446#ifdef CY_DEBUG_DTR
3447 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3448#endif
3449}
3450
3451static const struct tty_port_operations cyy_port_ops = {
3452 .carrier_raised = cyy_carrier_raised,
3453 .dtr_rts = cyy_dtr_rts,
3454};
3455
3456static const struct tty_port_operations cyz_port_ops = {
3457 .carrier_raised = cyz_carrier_raised,
3458 .dtr_rts = cyz_dtr_rts,
3459};
3460
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461/*
3462 * ---------------------------------------------------------------------
3463 * cy_init() and friends
3464 *
3465 * cy_init() is called at boot-time to initialize the serial driver.
3466 * ---------------------------------------------------------------------
3467 */
3468
Jiri Slabydd025c02007-05-08 00:37:02 -07003469static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003470{
3471 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003472 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003473
Jiri Slaby3046d502007-05-08 00:36:46 -07003474 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003475 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003476
Jiri Slaby963118e2009-06-11 12:34:27 +01003477 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3478 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003479 if (cinfo->ports == NULL) {
3480 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3481 return -ENOMEM;
3482 }
3483
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003484 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3485 channel++, port++) {
3486 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003487 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003488 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003489 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003490 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003491
Alan Cox44b7d1b2008-07-16 21:57:18 +01003492 info->port.closing_wait = CLOSING_WAIT_DELAY;
3493 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003494 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003495 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003496 init_waitqueue_head(&info->delta_msr_wait);
3497
Jiri Slaby2693f482009-06-11 12:31:06 +01003498 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003499 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3500 struct ZFW_CTRL *zfw_ctrl;
3501
Jiri Slabyf0737572009-09-19 13:13:12 -07003502 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003503 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003504
3505 zfw_ctrl = cinfo->base_addr +
3506 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3507 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3508 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3509
Jiri Slaby101b8152009-06-11 12:30:10 +01003510 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003511 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3512 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003513 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003514#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003515 setup_timer(&cyz_rx_full_timer[port],
3516 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003517#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003518 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003519 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003520 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003521
Jiri Slabyf0737572009-09-19 13:13:12 -07003522 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003523 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003524 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003525 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003526 info->cor2 = CyETC;
3527 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003528
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003529 chip_number = channel / CyPORTS_PER_CHIP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07003530 info->chip_rev = readb(cinfo->base_addr +
3531 (cy_chip_offset[chip_number] << index) +
3532 (CyGFRCR << index));
3533
3534 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003535 /* It is a CD1400 rev. J or later */
3536 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3537 info->tco = baud_co_60[13]; /* Tx CO */
3538 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3539 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003540 info->rtsdtr_inv = 1;
3541 } else {
3542 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3543 info->tco = baud_co_25[13]; /* Tx CO */
3544 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3545 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003546 info->rtsdtr_inv = 0;
3547 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003548 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3549 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003550 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003551
Jiri Slaby0809e262007-05-08 00:36:14 -07003552 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003553
3554#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003555 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003556 mod_timer(&cyz_timerlist, jiffies + 1);
3557#ifdef CY_PCI_DEBUG
3558 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3559#endif
3560 }
3561#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003562 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003563}
3564
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565/* initialize chips on Cyclom-Y card -- return number of valid
3566 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003567static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3568 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569{
Jiri Slaby02f11752006-12-08 02:39:28 -08003570 unsigned int chip_number;
3571 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
Jiri Slaby02f11752006-12-08 02:39:28 -08003573 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3574 /* Cy_HwReset is 0x1400 */
3575 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3576 /* Cy_ClrIntr is 0x1800 */
3577 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578
Alan Cox15ed6cc2008-04-30 00:53:55 -07003579 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3580 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003581 base_addr =
3582 true_base_addr + (cy_chip_offset[chip_number] << index);
3583 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003584 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003585 /*************
3586 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3587 chip_number, (unsigned long)base_addr);
3588 *************/
3589 return chip_number;
3590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
Jiri Slaby02f11752006-12-08 02:39:28 -08003592 cy_writeb(base_addr + (CyGFRCR << index), 0);
3593 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
Jiri Slaby02f11752006-12-08 02:39:28 -08003595 /* The Cyclom-16Y does not decode address bit 9 and therefore
3596 cannot distinguish between references to chip 0 and a non-
3597 existent chip 4. If the preceding clearing of the supposed
3598 chip 4 GFRCR register appears at chip 0, there is no chip 4
3599 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3600 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003601 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003602 (cy_chip_offset[0] << index) +
3603 (CyGFRCR << index)) == 0) {
3604 return chip_number;
3605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
Jiri Slaby02f11752006-12-08 02:39:28 -08003607 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3608 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003610 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003611 /*
3612 printk(" chip #%d at %#6lx is not responding ",
3613 chip_number, (unsigned long)base_addr);
3614 printk("(GFRCR stayed 0)\n",
3615 */
3616 return chip_number;
3617 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003618 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003619 0x40) {
3620 /*
3621 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3622 "%#2x)\n",
3623 chip_number, (unsigned long)base_addr,
3624 base_addr[CyGFRCR<<index]);
3625 */
3626 return chip_number;
3627 }
3628 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003629 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003630 /* It is a CD1400 rev. J or later */
3631 /* Impossible to reach 5ms with this chip.
3632 Changed to 2ms instead (f = 500 Hz). */
3633 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3634 } else {
3635 /* f = 200 Hz */
3636 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3637 }
3638
3639 /*
3640 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3641 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003642 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003643 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003645 return chip_number;
3646} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648/*
3649 * ---------------------------------------------------------------------
3650 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3651 * sets global variables and return the number of ISA boards found.
3652 * ---------------------------------------------------------------------
3653 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003654static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655{
3656#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003657 unsigned short cy_isa_irq, nboard;
3658 void __iomem *cy_isa_address;
3659 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08003661 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662#endif
3663
Jiri Slaby02f11752006-12-08 02:39:28 -08003664 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665
3666#ifdef MODULE
3667 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003668 for (i = 0; i < NR_CARDS; i++) {
3669 if (maddr[i] || i) {
3670 isparam = 1;
3671 cy_isa_addresses[i] = maddr[i];
3672 }
3673 if (!maddr[i])
3674 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 }
3676#endif
3677
Jiri Slaby02f11752006-12-08 02:39:28 -08003678 /* scan the address table probing for Cyclom-Y/ISA boards */
3679 for (i = 0; i < NR_ISA_ADDRS; i++) {
3680 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003681 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003682 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
Jiri Slaby02f11752006-12-08 02:39:28 -08003684 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003685 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003686 if (cy_isa_address == NULL) {
3687 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3688 "address\n");
3689 continue;
3690 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003691 cy_isa_nchan = CyPORTS_PER_CHIP *
3692 cyy_init_card(cy_isa_address, 0);
3693 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003694 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003695 continue;
3696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697#ifdef MODULE
3698 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003699 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 else
3701#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003702 /* find out the board's irq by probing */
3703 cy_isa_irq = detect_isa_irq(cy_isa_address);
3704 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003705 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3706 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003707 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003708 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003709 continue;
3710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711
Jiri Slaby02f11752006-12-08 02:39:28 -08003712 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003713 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3714 "more channels are available. Change NR_PORTS "
3715 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003716 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003717 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003718 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003719 }
3720 /* fill the next cy_card structure available */
3721 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003722 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003723 break;
3724 }
3725 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003726 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3727 "more cards can be used. Change NR_CARDS in "
3728 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003729 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003730 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003731 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
Jiri Slaby02f11752006-12-08 02:39:28 -08003734 /* allocate IRQ */
3735 if (request_irq(cy_isa_irq, cyy_interrupt,
3736 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003737 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3738 "could not allocate IRQ#%d.\n",
3739 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003740 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003741 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743
Jiri Slaby02f11752006-12-08 02:39:28 -08003744 /* set cy_card */
3745 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003746 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003747 cy_card[j].irq = (int)cy_isa_irq;
3748 cy_card[j].bus_index = 0;
3749 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003750 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3751 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003752 if (cy_init_card(&cy_card[j])) {
3753 cy_card[j].base_addr = NULL;
3754 free_irq(cy_isa_irq, &cy_card[j]);
3755 iounmap(cy_isa_address);
3756 continue;
3757 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003758 nboard++;
3759
Jiri Slaby21719192007-05-08 00:36:42 -07003760 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3761 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003762 j + 1, (unsigned long)cy_isa_address,
3763 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003764 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3765
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003766 for (j = cy_next_channel;
3767 j < cy_next_channel + cy_isa_nchan; j++)
3768 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003769 cy_next_channel += cy_isa_nchan;
3770 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003771 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003773 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003774#endif /* CONFIG_ISA */
3775} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Jiri Slaby58936d82007-05-08 00:36:13 -07003777#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003778static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3779{
3780 unsigned int a;
3781
3782 for (a = 0; a < size && *str; a++, str++)
3783 if (*str & 0x80)
3784 return -EINVAL;
3785
3786 for (; a < size; a++, str++)
3787 if (*str)
3788 return -EINVAL;
3789
3790 return 0;
3791}
3792
David Woodhousef61e7612008-05-23 23:57:19 +01003793static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003794 unsigned int size)
3795{
3796 for (; size > 0; size--) {
3797 cy_writel(fpga, *data++);
3798 udelay(10);
3799 }
3800}
3801
3802static void __devinit plx_init(struct pci_dev *pdev, int irq,
3803 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804{
Jiri Slaby02f11752006-12-08 02:39:28 -08003805 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003806 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003807 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003808 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809
Jiri Slaby02f11752006-12-08 02:39:28 -08003810 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003811 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003812 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003813 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3814
3815 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3816 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3817 * registers. This will remain here until we find a permanent fix.
3818 */
3819 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3820}
3821
3822static int __devinit __cyz_load_fw(const struct firmware *fw,
3823 const char *name, const u32 mailbox, void __iomem *base,
3824 void __iomem *fpga)
3825{
David Woodhousef61e7612008-05-23 23:57:19 +01003826 const void *ptr = fw->data;
3827 const struct zfile_header *h = ptr;
3828 const struct zfile_config *c, *cs;
3829 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003830 unsigned int a, tmp, len = fw->size;
3831#define BAD_FW KERN_ERR "Bad firmware: "
3832 if (len < sizeof(*h)) {
3833 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3834 return -EINVAL;
3835 }
3836
3837 cs = ptr + h->config_offset;
3838 bs = ptr + h->block_offset;
3839
3840 if ((void *)(cs + h->n_config) > ptr + len ||
3841 (void *)(bs + h->n_blocks) > ptr + len) {
3842 printk(BAD_FW "too short");
3843 return -EINVAL;
3844 }
3845
3846 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3847 cyc_isfwstr(h->date, sizeof(h->date))) {
3848 printk(BAD_FW "bad formatted header string\n");
3849 return -EINVAL;
3850 }
3851
3852 if (strncmp(name, h->name, sizeof(h->name))) {
3853 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3854 return -EINVAL;
3855 }
3856
3857 tmp = 0;
3858 for (c = cs; c < cs + h->n_config; c++) {
3859 for (a = 0; a < c->n_blocks; a++)
3860 if (c->block_list[a] > h->n_blocks) {
3861 printk(BAD_FW "bad block ref number in cfgs\n");
3862 return -EINVAL;
3863 }
3864 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3865 tmp++;
3866 }
3867 if (!tmp) {
3868 printk(BAD_FW "nothing appropriate\n");
3869 return -EINVAL;
3870 }
3871
3872 for (b = bs; b < bs + h->n_blocks; b++)
3873 if (b->file_offset + b->size > len) {
3874 printk(BAD_FW "bad block data offset\n");
3875 return -EINVAL;
3876 }
3877
3878 /* everything is OK, let's seek'n'load it */
3879 for (c = cs; c < cs + h->n_config; c++)
3880 if (c->mailbox == mailbox && c->function == 0)
3881 break;
3882
3883 for (a = 0; a < c->n_blocks; a++) {
3884 b = &bs[c->block_list[a]];
3885 if (b->type == ZBLOCK_FPGA) {
3886 if (fpga != NULL)
3887 cyz_fpga_copy(fpga, ptr + b->file_offset,
3888 b->size);
3889 } else {
3890 if (base != NULL)
3891 memcpy_toio(base + b->ram_offset,
3892 ptr + b->file_offset, b->size);
3893 }
3894 }
3895#undef BAD_FW
3896 return 0;
3897}
3898
3899static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3900 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3901{
3902 const struct firmware *fw;
3903 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3904 struct CUSTOM_REG __iomem *cust = base_addr;
3905 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003906 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003907 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003908 unsigned int i;
3909 int retval;
3910
3911 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3912 if (retval) {
3913 dev_err(&pdev->dev, "can't get firmware\n");
3914 goto err;
3915 }
3916
3917 /* Check whether the firmware is already loaded and running. If
3918 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003919 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003920 u32 cntval = readl(base_addr + 0x190);
3921
3922 udelay(100);
3923 if (cntval != readl(base_addr + 0x190)) {
3924 /* FW counter is working, FW is running */
3925 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3926 "Skipping board.\n");
3927 retval = 0;
3928 goto err_rel;
3929 }
3930 }
3931
3932 /* start boot */
3933 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3934 ~0x00030800UL);
3935
3936 mailbox = readl(&ctl_addr->mail_box_0);
3937
Jiri Slaby2693f482009-06-11 12:31:06 +01003938 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003939 /* stops CPU and set window to beginning of RAM */
3940 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3941 cy_writel(&cust->cpu_stop, 0);
3942 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3943 udelay(100);
3944 }
3945
3946 plx_init(pdev, irq, ctl_addr);
3947
3948 if (mailbox != 0) {
3949 /* load FPGA */
3950 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3951 base_addr);
3952 if (retval)
3953 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003954 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003955 dev_err(&pdev->dev, "fw upload successful, but fw is "
3956 "not loaded\n");
3957 goto err_rel;
3958 }
3959 }
3960
3961 /* stops CPU and set window to beginning of RAM */
3962 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3963 cy_writel(&cust->cpu_stop, 0);
3964 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3965 udelay(100);
3966
3967 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003968 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003969 cy_writeb(tmp, 255);
3970 if (mailbox != 0) {
3971 /* set window to last 512K of RAM */
3972 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003973 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003974 cy_writeb(tmp, 255);
3975 /* set window to beginning of RAM */
3976 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003977 }
3978
3979 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3980 release_firmware(fw);
3981 if (retval)
3982 goto err;
3983
3984 /* finish boot and start boards */
3985 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3986 cy_writel(&cust->cpu_start, 0);
3987 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3988 i = 0;
3989 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3990 msleep(100);
3991 if (status != ZFIRM_ID) {
3992 if (status == ZFIRM_HLT) {
3993 dev_err(&pdev->dev, "you need an external power supply "
3994 "for this number of ports. Firmware halted and "
3995 "board reset.\n");
3996 retval = -EIO;
3997 goto err;
3998 }
3999 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
4000 "some more time\n", status);
4001 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
4002 i++ < 200)
4003 msleep(100);
4004 if (status != ZFIRM_ID) {
4005 dev_err(&pdev->dev, "Board not started in 20 seconds! "
4006 "Giving up. (fid->signature = 0x%x)\n",
4007 status);
4008 dev_info(&pdev->dev, "*** Warning ***: if you are "
4009 "upgrading the FW, please power cycle the "
4010 "system before loading the new FW to the "
4011 "Cyclades-Z.\n");
4012
Jiri Slaby2693f482009-06-11 12:31:06 +01004013 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07004014 plx_init(pdev, irq, ctl_addr);
4015
4016 retval = -EIO;
4017 goto err;
4018 }
4019 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
4020 i / 10);
4021 }
4022 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
4023
4024 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
4025 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
4026 base_addr + readl(&fid->zfwctrl_addr));
4027
Jiri Slaby963118e2009-06-11 12:34:27 +01004028 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07004029 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01004030 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07004031
Jiri Slaby963118e2009-06-11 12:34:27 +01004032 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07004033 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
4034 "check the connection between the Z host card and the "
4035 "serial expanders.\n");
4036
Jiri Slaby2693f482009-06-11 12:31:06 +01004037 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07004038 plx_init(pdev, irq, ctl_addr);
4039
4040 dev_info(&pdev->dev, "Null number of ports detected. Board "
4041 "reset.\n");
4042 retval = 0;
4043 goto err;
4044 }
4045
4046 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
4047 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
4048
4049 /*
4050 Early firmware failed to start looking for commands.
4051 This enables firmware interrupts for those commands.
4052 */
4053 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
4054 (1 << 17));
4055 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
4056 0x00030800UL);
4057
Jiri Slaby963118e2009-06-11 12:34:27 +01004058 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07004059err_rel:
4060 release_firmware(fw);
4061err:
4062 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063}
4064
Jiri Slaby58936d82007-05-08 00:36:13 -07004065static int __devinit cy_pci_probe(struct pci_dev *pdev,
4066 const struct pci_device_id *ent)
4067{
Jiri Slaby31375532007-05-08 00:37:04 -07004068 void __iomem *addr0 = NULL, *addr2 = NULL;
4069 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01004070 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07004071 unsigned int device_id, nchan = 0, card_no, i;
4072 unsigned char plx_ver;
4073 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07004074
4075 retval = pci_enable_device(pdev);
4076 if (retval) {
4077 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004078 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07004079 }
4080
4081 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07004082 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07004083 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
4084
Jiri Slaby31375532007-05-08 00:37:04 -07004085#if defined(__alpha__)
4086 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
4087 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
4088 "addresses on Alpha systems.\n");
4089 retval = -EIO;
4090 goto err_dis;
4091 }
4092#endif
4093 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
4094 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
4095 "addresses\n");
4096 retval = -EIO;
4097 goto err_dis;
4098 }
4099
4100 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
4101 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
4102 "it...\n");
4103 pdev->resource[2].flags &= ~IORESOURCE_IO;
4104 }
4105
4106 retval = pci_request_regions(pdev, "cyclades");
4107 if (retval) {
4108 dev_err(&pdev->dev, "failed to reserve resources\n");
4109 goto err_dis;
4110 }
4111
4112 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07004113 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4114 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07004115 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07004116
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004117 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
4118 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07004119 if (addr0 == NULL) {
4120 dev_err(&pdev->dev, "can't remap ctl region\n");
4121 goto err_reg;
4122 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004123 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
4124 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07004125 if (addr2 == NULL) {
4126 dev_err(&pdev->dev, "can't remap base region\n");
4127 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004128 }
4129
Jiri Slaby31375532007-05-08 00:37:04 -07004130 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
4131 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07004132 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
4133 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00004134 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004135 }
Jiri Slaby31375532007-05-08 00:37:04 -07004136 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
4137 struct RUNTIME_9060 __iomem *ctl_addr;
4138
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004139 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
4140 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07004141 if (addr0 == NULL) {
4142 dev_err(&pdev->dev, "can't remap ctl region\n");
4143 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07004144 }
4145
Jiri Slaby31375532007-05-08 00:37:04 -07004146 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004147 cy_writew(&ctl_addr->intr_ctrl_stat,
4148 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07004149
Jiri Slaby054f5b02007-07-17 04:05:16 -07004150 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004151
Jiri Slaby101b8152009-06-11 12:30:10 +01004152 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07004153
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004154 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
4155 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07004156 if (addr2 == NULL) {
4157 dev_err(&pdev->dev, "can't remap base region\n");
4158 goto err_unmap;
4159 }
4160
4161 if (mailbox == ZE_V1) {
4162 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07004163 } else {
4164 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07004165#ifdef CY_PCI_DEBUG
4166 if (mailbox == ZO_V1) {
4167 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
4168 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
4169 "id %lx, ver %lx\n", (ulong)(0xff &
4170 readl(&((struct CUSTOM_REG *)addr2)->
4171 fpga_id)), (ulong)(0xff &
4172 readl(&((struct CUSTOM_REG *)addr2)->
4173 fpga_version)));
4174 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4175 } else {
4176 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
4177 "Cyclades-Z board. FPGA not loaded\n");
4178 }
4179#endif
4180 /* The following clears the firmware id word. This
4181 ensures that the driver will not attempt to talk to
4182 the board until it has been properly initialized.
4183 */
4184 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
4185 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07004186 }
Jiri Slabyace08c32009-06-11 12:20:38 +01004187
4188 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01004189 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01004190 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01004191 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07004192 }
4193
4194 if ((cy_next_channel + nchan) > NR_PORTS) {
4195 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4196 "channels are available. Change NR_PORTS in "
4197 "cyclades.c and recompile kernel.\n");
4198 goto err_unmap;
4199 }
4200 /* fill the next cy_card structure available */
4201 for (card_no = 0; card_no < NR_CARDS; card_no++) {
4202 if (cy_card[card_no].base_addr == NULL)
4203 break;
4204 }
4205 if (card_no == NR_CARDS) { /* no more cy_cards available */
4206 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4207 "more cards can be used. Change NR_CARDS in "
4208 "cyclades.c and recompile kernel.\n");
4209 goto err_unmap;
4210 }
4211
4212 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4213 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004214 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07004215 retval = request_irq(irq, cyy_interrupt,
4216 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07004217 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07004218 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004219 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004220 }
Jiri Slaby963118e2009-06-11 12:34:27 +01004221 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07004222 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004223 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
4224 struct ZFW_CTRL __iomem *zfw_ctrl;
4225
4226 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4227
Jiri Slaby101b8152009-06-11 12:30:10 +01004228 cy_card[card_no].hw_ver = mailbox;
4229 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004230 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07004231#ifdef CONFIG_CYZ_INTR
4232 /* allocate IRQ only if board has an IRQ */
4233 if (irq != 0 && irq != 255) {
4234 retval = request_irq(irq, cyz_interrupt,
4235 IRQF_SHARED, "Cyclades-Z",
4236 &cy_card[card_no]);
4237 if (retval) {
4238 dev_err(&pdev->dev, "could not allocate IRQ\n");
4239 goto err_unmap;
4240 }
4241 }
4242#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07004243 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004244
Jiri Slaby31375532007-05-08 00:37:04 -07004245 /* set cy_card */
4246 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01004247 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07004248 cy_card[card_no].irq = irq;
4249 cy_card[card_no].bus_index = 1;
4250 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01004251 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07004252 retval = cy_init_card(&cy_card[card_no]);
4253 if (retval)
4254 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07004255
Jiri Slaby31375532007-05-08 00:37:04 -07004256 pci_set_drvdata(pdev, &cy_card[card_no]);
4257
4258 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4259 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004260 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07004261 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07004262 switch (plx_ver) {
4263 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07004264 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07004265 break;
4266
4267 case PLX_9060:
4268 case PLX_9080:
4269 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004270 {
4271 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
4272 plx_init(pdev, irq, ctl_addr);
4273 cy_writew(&ctl_addr->intr_ctrl_stat,
4274 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07004275 break;
4276 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01004277 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004278 }
4279
Jiri Slaby31375532007-05-08 00:37:04 -07004280 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
4281 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
4282 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
4283 tty_register_device(cy_serial_driver, i, &pdev->dev);
4284 cy_next_channel += nchan;
4285
Jiri Slaby58936d82007-05-08 00:36:13 -07004286 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07004287err_null:
4288 cy_card[card_no].base_addr = NULL;
4289 free_irq(irq, &cy_card[card_no]);
4290err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004291 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004292 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004293 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07004294err_reg:
4295 pci_release_regions(pdev);
4296err_dis:
4297 pci_disable_device(pdev);
4298err:
4299 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07004300}
Jiri Slaby58936d82007-05-08 00:36:13 -07004301
Jiri Slaby6747cd92007-05-08 00:36:34 -07004302static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303{
Jiri Slaby38d09092007-05-08 00:36:10 -07004304 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07004305 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07004306
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004307 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01004308 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07004309 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01004310 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004311 else
4312#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004313 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004314#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01004315 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
4316 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
4317 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004318
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004319 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004320 if (cinfo->ctl_addr.p9050)
4321 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07004322 if (cinfo->irq
4323#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004324 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07004325#endif /* CONFIG_CYZ_INTR */
4326 )
4327 free_irq(cinfo->irq, cinfo);
4328 pci_release_regions(pdev);
4329
4330 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004331 for (i = cinfo->first_line; i < cinfo->first_line +
4332 cinfo->nports; i++)
4333 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07004334 cinfo->nports = 0;
4335 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07004336}
4337
Jiri Slaby6747cd92007-05-08 00:36:34 -07004338static struct pci_driver cy_pci_driver = {
4339 .name = "cyclades",
4340 .id_table = cy_pci_dev_id,
4341 .probe = cy_pci_probe,
4342 .remove = __devexit_p(cy_pci_remove)
4343};
4344#endif
4345
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004346static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347{
Jiri Slaby02f11752006-12-08 02:39:28 -08004348 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07004349 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08004350 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004352 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08004353 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354
Jiri Slaby02f11752006-12-08 02:39:28 -08004355 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07004356 for (i = 0; i < NR_CARDS; i++)
4357 for (j = 0; j < cy_card[i].nports; j++) {
4358 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08004359
Jiri Slabyd13549f2009-09-19 13:13:12 -07004360 if (info->port.count) {
4361 /* XXX is the ldisc num worth this? */
4362 struct tty_struct *tty;
4363 struct tty_ldisc *ld;
4364 int num = 0;
4365 tty = tty_port_tty_get(&info->port);
4366 if (tty) {
4367 ld = tty_ldisc_ref(tty);
4368 if (ld) {
4369 num = ld->ops->num;
4370 tty_ldisc_deref(ld);
4371 }
4372 tty_kref_put(tty);
4373 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004374 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004375 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004376 (cur_jifs - info->idle_stats.in_use) /
4377 HZ, info->idle_stats.xmit_bytes,
4378 (cur_jifs - info->idle_stats.xmit_idle)/
4379 HZ, info->idle_stats.recv_bytes,
4380 (cur_jifs - info->idle_stats.recv_idle)/
4381 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004382 num);
4383 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004384 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004385 "%10lu %8lu %9lu %6ld\n",
4386 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004387 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004388 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389}
4390
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004391static int cyclades_proc_open(struct inode *inode, struct file *file)
4392{
4393 return single_open(file, cyclades_proc_show, NULL);
4394}
4395
4396static const struct file_operations cyclades_proc_fops = {
4397 .owner = THIS_MODULE,
4398 .open = cyclades_proc_open,
4399 .read = seq_read,
4400 .llseek = seq_lseek,
4401 .release = single_release,
4402};
4403
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404/* The serial driver boot-time initialization code!
4405 Hardware I/O ports are mapped to character special devices on a
4406 first found, first allocated manner. That is, this code searches
4407 for Cyclom cards in the system. As each is found, it is probed
4408 to discover how many chips (and thus how many ports) are present.
4409 These ports are mapped to the tty ports 32 and upward in monotonic
4410 fashion. If an 8-port card is replaced with a 16-port card, the
4411 port mapping on a following card will shift.
4412
4413 This approach is different from what is used in the other serial
4414 device driver because the Cyclom is more properly a multiplexer,
4415 not just an aggregation of serial ports on one card.
4416
4417 If there are more cards with more ports than have been
4418 statically allocated above, a warning is printed and the
4419 extra ports are ignored.
4420 */
4421
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004422static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004423 .open = cy_open,
4424 .close = cy_close,
4425 .write = cy_write,
4426 .put_char = cy_put_char,
4427 .flush_chars = cy_flush_chars,
4428 .write_room = cy_write_room,
4429 .chars_in_buffer = cy_chars_in_buffer,
4430 .flush_buffer = cy_flush_buffer,
4431 .ioctl = cy_ioctl,
4432 .throttle = cy_throttle,
4433 .unthrottle = cy_unthrottle,
4434 .set_termios = cy_set_termios,
4435 .stop = cy_stop,
4436 .start = cy_start,
4437 .hangup = cy_hangup,
4438 .break_ctl = cy_break,
4439 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004440 .tiocmget = cy_tiocmget,
4441 .tiocmset = cy_tiocmset,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004442 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443};
4444
Jiri Slaby02f11752006-12-08 02:39:28 -08004445static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446{
Jiri Slabydd025c02007-05-08 00:37:02 -07004447 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004448 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
Jiri Slaby02f11752006-12-08 02:39:28 -08004450 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4451 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004452 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004453
4454 printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
4455 __DATE__, __TIME__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
Jiri Slaby02f11752006-12-08 02:39:28 -08004457 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
Jiri Slaby02f11752006-12-08 02:39:28 -08004459 cy_serial_driver->owner = THIS_MODULE;
4460 cy_serial_driver->driver_name = "cyclades";
4461 cy_serial_driver->name = "ttyC";
4462 cy_serial_driver->major = CYCLADES_MAJOR;
4463 cy_serial_driver->minor_start = 0;
4464 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4465 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4466 cy_serial_driver->init_termios = tty_std_termios;
4467 cy_serial_driver->init_termios.c_cflag =
4468 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004469 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004470 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004472 retval = tty_register_driver(cy_serial_driver);
4473 if (retval) {
4474 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4475 goto err_frtty;
4476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477
Jiri Slaby02f11752006-12-08 02:39:28 -08004478 /* the code below is responsible to find the boards. Each different
4479 type of board has its own detection routine. If a board is found,
4480 the next cy_card structure available is set by the detection
4481 routine. These functions are responsible for checking the
4482 availability of cy_card and cy_port data structures and updating
4483 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484
Jiri Slaby02f11752006-12-08 02:39:28 -08004485 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004486 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
Jiri Slaby6747cd92007-05-08 00:36:34 -07004488#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004489 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004490 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004491 if (retval && !nboards) {
4492 tty_unregister_driver(cy_serial_driver);
4493 goto err_frtty;
4494 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004495#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004496
4497 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004498err_frtty:
4499 put_tty_driver(cy_serial_driver);
4500err:
4501 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004502} /* cy_init */
4503
4504static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505{
Jiri Slabydd025c02007-05-08 00:37:02 -07004506 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004507 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508
4509#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004510 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511#endif /* CONFIG_CYZ_INTR */
4512
Alan Cox15ed6cc2008-04-30 00:53:55 -07004513 e1 = tty_unregister_driver(cy_serial_driver);
4514 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004515 printk(KERN_ERR "failed to unregister Cyclades serial "
4516 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517
Jiri Slaby6747cd92007-05-08 00:36:34 -07004518#ifdef CONFIG_PCI
4519 pci_unregister_driver(&cy_pci_driver);
4520#endif
4521
Jiri Slaby02f11752006-12-08 02:39:28 -08004522 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004523 card = &cy_card[i];
4524 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004525 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004526 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4527 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004528 if (card->ctl_addr.p9050)
4529 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004530 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004532 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004534 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004535 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004536 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004537 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004538 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004539 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004540 }
4541 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004542
4543 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544} /* cy_cleanup_module */
4545
4546module_init(cy_init);
4547module_exit(cy_cleanup_module);
4548
4549MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004550MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad2009-04-06 17:33:04 +01004551MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);