blob: 47cd7b8d4d97a5bb3efb9385db82c2bcb72725c5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#undef BLOCKMOVE
2#define Z_WAKE
3#undef Z_EXT_CHARS_IN_BUFFER
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5/*
6 * linux/drivers/char/cyclades.c
7 *
8 * This file contains the driver for the Cyclades async multiport
9 * serial boards.
10 *
11 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
12 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Jiri Slabyebdb5132009-09-19 13:13:14 -070014 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
16 * Much of the design and some of the code came from serial.c
17 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
18 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
19 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070020 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 */
23
Jiri Slabyebdb5132009-09-19 13:13:14 -070024#define CY_VERSION "2.6"
Jiri Slaby096dcfc2006-12-08 02:39:30 -080025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026/* If you need to install more boards than NR_CARDS, change the constant
27 in the definition below. No other change is necessary to support up to
28 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
29
Jiri Slaby02f11752006-12-08 02:39:28 -080030#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32/*
33 If the total number of ports is larger than NR_PORTS, change this
34 constant in the definition below. No other change is necessary to
35 support more boards/ports. */
36
Jiri Slaby02f11752006-12-08 02:39:28 -080037#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define ZO_V1 0
40#define ZO_V2 1
41#define ZE_V1 2
42
43#define SERIAL_PARANOIA_CHECK
44#undef CY_DEBUG_OPEN
45#undef CY_DEBUG_THROTTLE
46#undef CY_DEBUG_OTHER
47#undef CY_DEBUG_IO
48#undef CY_DEBUG_COUNT
49#undef CY_DEBUG_DTR
50#undef CY_DEBUG_WAIT_UNTIL_SENT
51#undef CY_DEBUG_INTERRUPTS
52#undef CY_16Y_HACK
53#undef CY_ENABLE_MONITORING
54#undef CY_PCI_DEBUG
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/*
Alan Cox15ed6cc2008-04-30 00:53:55 -070057 * Include section
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <linux/module.h>
60#include <linux/errno.h>
61#include <linux/signal.h>
62#include <linux/sched.h>
63#include <linux/timer.h>
64#include <linux/interrupt.h>
65#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -080066#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/serial.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040068#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include <linux/major.h>
70#include <linux/string.h>
71#include <linux/fcntl.h>
72#include <linux/ptrace.h>
73#include <linux/cyclades.h>
74#include <linux/mm.h>
75#include <linux/ioport.h>
76#include <linux/init.h>
77#include <linux/delay.h>
78#include <linux/spinlock.h>
79#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -070080#include <linux/firmware.h>
Scott James Remnant9f56fad72009-04-06 17:33:04 +010081#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Alan Cox15ed6cc2008-04-30 00:53:55 -070083#include <linux/io.h>
Alan Cox15ed6cc2008-04-30 00:53:55 -070084#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#include <linux/kernel.h>
87#include <linux/pci.h>
88
89#include <linux/stat.h>
90#include <linux/proc_fs.h>
Alexey Dobriyan444697d2009-03-31 15:19:15 -070091#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Jiri Slaby02f11752006-12-08 02:39:28 -080093static void cy_throttle(struct tty_struct *tty);
94static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifndef SERIAL_XMIT_SIZE
97#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
98#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100#define STD_COM_FLAGS (0)
101
Jiri Slaby054f5b02007-07-17 04:05:16 -0700102/* firmware stuff */
103#define ZL_MAX_BLOCKS 16
104#define DRIVER_VERSION 0x02010203
105#define RAM_SIZE 0x80000
106
Jiri Slaby054f5b02007-07-17 04:05:16 -0700107enum zblock_type {
108 ZBLOCK_PRG = 0,
109 ZBLOCK_FPGA = 1
110};
111
112struct zfile_header {
113 char name[64];
114 char date[32];
115 char aux[32];
116 u32 n_config;
117 u32 config_offset;
118 u32 n_blocks;
119 u32 block_offset;
120 u32 reserved[9];
121} __attribute__ ((packed));
122
123struct zfile_config {
124 char name[64];
125 u32 mailbox;
126 u32 function;
127 u32 n_blocks;
128 u32 block_list[ZL_MAX_BLOCKS];
129} __attribute__ ((packed));
130
131struct zfile_block {
132 u32 type;
133 u32 file_offset;
134 u32 ram_offset;
135 u32 size;
136} __attribute__ ((packed));
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static struct tty_driver *cy_serial_driver;
139
140#ifdef CONFIG_ISA
141/* This is the address lookup table. The driver will probe for
142 Cyclom-Y/ISA boards at all addresses in here. If you want the
143 driver to probe addresses at a different address, add it to
144 this table. If the driver is probing some other board and
145 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146*/
147
148static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800149 0xD0000,
150 0xD2000,
151 0xD4000,
152 0xD6000,
153 0xD8000,
154 0xDA000,
155 0xDC000,
156 0xDE000,
157 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158};
Jiri Slaby02f11752006-12-08 02:39:28 -0800159
Tobias Klauserfe971072006-01-09 20:54:02 -0800160#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162#ifdef MODULE
Jiri Slaby3046d502007-05-08 00:36:46 -0700163static long maddr[NR_CARDS];
164static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166module_param_array(maddr, long, NULL, 0);
167module_param_array(irq, int, NULL, 0);
168#endif
169
Jiri Slaby02f11752006-12-08 02:39:28 -0800170#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172/* This is the per-card data structure containing address, irq, number of
173 channels, etc. This driver supports a maximum of NR_CARDS cards.
174*/
175static struct cyclades_card cy_card[NR_CARDS];
176
Jiri Slaby02f11752006-12-08 02:39:28 -0800177static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 * This is used to look up the divisor speeds and the timeouts
181 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100182 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
184 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
185 * HI VHI
186 * 20
187 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700188static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800189 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
190 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
191 230400, 0
192};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Jiri Slabyebdb5132009-09-19 13:13:14 -0700194static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800195 /* value => 00 01 02 03 04 */
196 /* divide by 8 32 128 512 2048 */
197 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
198 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
199};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Jiri Slabyebdb5132009-09-19 13:13:14 -0700201static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800202 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
203 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
204};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Jiri Slabyebdb5132009-09-19 13:13:14 -0700206static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800207 /* value => 00 01 02 03 04 */
208 /* divide by 8 32 128 512 2048 */
209 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
210 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00
212};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Jiri Slabyebdb5132009-09-19 13:13:14 -0700214static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800215 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
216 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
217 0x21
218};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Jiri Slabyebdb5132009-09-19 13:13:14 -0700220static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800221 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
222 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
223 0x07
224};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226/*
227 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700228 * The cyclades_port structure member rflow and the vector rflow_thr
229 * allows us to take advantage of a special feature in the CD1400 to avoid
230 * data loss even when the system interrupt latency is too high. These flags
231 * are to be used only with very special applications. Setting these flags
232 * requires the use of a special cable (DTR and RTS reversed). In the new
233 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 * cables.
235 */
236
Jiri Slabyebdb5132009-09-19 13:13:14 -0700237static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
240 0x0a
241};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243/* The Cyclom-Ye has placed the sequential chips in non-sequential
244 * address order. This look-up table overcomes that problem.
245 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700246static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800247 0x0400,
248 0x0800,
249 0x0C00,
250 0x0200,
251 0x0600,
252 0x0A00,
253 0x0E00
254};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256/* PCI related definitions */
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700259static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700260 /* PCI < 1Mb */
261 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
262 /* PCI > 1Mb */
263 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
264 /* 4Y PCI < 1Mb */
265 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
266 /* 4Y PCI > 1Mb */
267 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
268 /* 8Y PCI < 1Mb */
269 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
270 /* 8Y PCI > 1Mb */
271 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
272 /* Z PCI < 1Mb */
273 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
274 /* Z PCI > 1Mb */
275 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800276 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800277};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800278MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#endif
280
281static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700282static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700283static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284#ifdef CONFIG_ISA
285static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800286#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288#ifndef CONFIG_CYZ_INTR
289static void cyz_poll(unsigned long);
290
291/* The Cyclades-Z polling cycle is defined by this variable */
292static long cyz_polling_cycle = CZ_DEF_POLL;
293
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700294static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Jiri Slaby02f11752006-12-08 02:39:28 -0800296#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297static void cyz_rx_restart(unsigned long);
298static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800299#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Jiri Slaby2693f482009-06-11 12:31:06 +0100301static inline bool cy_is_Z(struct cyclades_card *card)
302{
303 return card->num_chips == (unsigned int)-1;
304}
305
306static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
307{
308 return readl(&ctl_addr->init_ctrl) & (1 << 17);
309}
310
311static inline bool cyz_fpga_loaded(struct cyclades_card *card)
312{
313 return __cyz_fpga_loaded(card->ctl_addr.p9060);
314}
315
316static inline bool cyz_is_loaded(struct cyclades_card *card)
317{
318 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
319
320 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
321 readl(&fw_id->signature) == ZFIRM_ID;
322}
323
Jiri Slaby02f11752006-12-08 02:39:28 -0800324static inline int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700325 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800328 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700329 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
330 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800331 return 1;
332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jiri Slaby02f11752006-12-08 02:39:28 -0800334 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700335 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
336 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800337 return 1;
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800340 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700341}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343/***********************************************************/
344/********* Start of block of Cyclom-Y specific code ********/
345
346/* This routine waits up to 1000 micro-seconds for the previous
347 command to the Cirrus chip to complete and then issues the
348 new command. An error is returned if the previous command
349 didn't finish within the time limit.
350
351 This function is only called from inside spinlock-protected code.
352 */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700353static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Jiri Slabyad39c302007-05-08 00:35:49 -0700355 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Jiri Slaby02f11752006-12-08 02:39:28 -0800357 /* Check to see that the previous command has completed */
358 for (i = 0; i < 100; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700359 if (readb(base_addr + (CyCCR << index)) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800360 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800361 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800363 /* if the CCR never cleared, the previous command
364 didn't finish within the "reasonable time" */
365 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800366 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Jiri Slaby02f11752006-12-08 02:39:28 -0800368 /* Issue the new command */
369 cy_writeb(base_addr + (CyCCR << index), cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800371 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800372} /* cyy_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374#ifdef CONFIG_ISA
375/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700376static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
Jiri Slaby02f11752006-12-08 02:39:28 -0800378 int irq;
379 unsigned long irqs, flags;
380 int save_xir, save_car;
381 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Jiri Slaby02f11752006-12-08 02:39:28 -0800383 /* forget possible initially masked and pending IRQ */
384 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Jiri Slaby02f11752006-12-08 02:39:28 -0800386 /* Clear interrupts on the board first */
387 cy_writeb(address + (Cy_ClrIntr << index), 0);
388 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Jiri Slaby02f11752006-12-08 02:39:28 -0800390 irqs = probe_irq_on();
391 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700392 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Jiri Slaby02f11752006-12-08 02:39:28 -0800394 /* Enable the Tx interrupts on the CD1400 */
395 local_irq_save(flags);
396 cy_writeb(address + (CyCAR << index), 0);
397 cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Jiri Slaby02f11752006-12-08 02:39:28 -0800399 cy_writeb(address + (CyCAR << index), 0);
400 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700401 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800402 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Jiri Slaby02f11752006-12-08 02:39:28 -0800404 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700405 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Jiri Slaby02f11752006-12-08 02:39:28 -0800407 /* Check which interrupt is in use */
408 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Jiri Slaby02f11752006-12-08 02:39:28 -0800410 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700411 save_xir = (u_char) readb(address + (CyTIR << index));
412 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800413 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
414 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700415 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800416 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
417 cy_writeb(address + (CyCAR << index), (save_car));
418 cy_writeb(address + (Cy_ClrIntr << index), 0);
419 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Jiri Slaby02f11752006-12-08 02:39:28 -0800421 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
Jiri Slaby02f11752006-12-08 02:39:28 -0800423#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Jiri Slabyce97a092007-10-18 03:06:21 -0700425static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
426 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800427{
428 struct cyclades_port *info;
429 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700430 int len, index = cinfo->bus_index;
431 u8 save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800432
Jiri Slabye9410272006-12-08 02:39:28 -0800433#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700434 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800435#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700436 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700437 save_xir = readb(base_addr + (CyRIR << index));
438 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700439 info = &cinfo->ports[channel + chip * 4];
440 save_car = readb(base_addr + (CyCAR << index));
441 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800442
Jiri Slabyd13549f2009-09-19 13:13:12 -0700443 tty = tty_port_tty_get(&info->port);
Jiri Slabyce97a092007-10-18 03:06:21 -0700444 /* if there is nowhere to put the data, discard it */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700445 if (tty == NULL) {
Jiri Slaby65f76a82007-10-18 03:06:22 -0700446 if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
447 CyIVRRxEx) { /* exception */
Jiri Slabyce97a092007-10-18 03:06:21 -0700448 data = readb(base_addr + (CyRDSR << index));
449 } else { /* normal character reception */
450 char_count = readb(base_addr + (CyRDCR << index));
451 while (char_count--)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700452 data = readb(base_addr + (CyRDSR << index));
Jiri Slabyce97a092007-10-18 03:06:21 -0700453 }
454 goto end;
455 }
456 /* there is an open port for this data */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700457 if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
458 CyIVRRxEx) { /* exception */
Jiri Slabyce97a092007-10-18 03:06:21 -0700459 data = readb(base_addr + (CyRDSR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800460
Jiri Slabyce97a092007-10-18 03:06:21 -0700461 /* For statistics only */
462 if (data & CyBREAK)
463 info->icount.brk++;
464 else if (data & CyFRAME)
465 info->icount.frame++;
466 else if (data & CyPARITY)
467 info->icount.parity++;
468 else if (data & CyOVERRUN)
469 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800470
Jiri Slabyce97a092007-10-18 03:06:21 -0700471 if (data & info->ignore_status_mask) {
472 info->icount.rx++;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700473 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700474 return;
475 }
476 if (tty_buffer_request_room(tty, 1)) {
477 if (data & info->read_status_mask) {
478 if (data & CyBREAK) {
479 tty_insert_flip_char(tty,
480 readb(base_addr + (CyRDSR <<
481 index)), TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800482 info->icount.rx++;
Alan Cox77451e52008-07-16 21:57:02 +0100483 if (info->port.flags & ASYNC_SAK)
Jiri Slabyce97a092007-10-18 03:06:21 -0700484 do_SAK(tty);
485 } else if (data & CyFRAME) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700486 tty_insert_flip_char(tty,
Jiri Slabyce97a092007-10-18 03:06:21 -0700487 readb(base_addr + (CyRDSR <<
488 index)), TTY_FRAME);
489 info->icount.rx++;
490 info->idle_stats.frame_errs++;
491 } else if (data & CyPARITY) {
492 /* Pieces of seven... */
493 tty_insert_flip_char(tty,
494 readb(base_addr + (CyRDSR <<
495 index)), TTY_PARITY);
496 info->icount.rx++;
497 info->idle_stats.parity_errs++;
498 } else if (data & CyOVERRUN) {
499 tty_insert_flip_char(tty, 0,
500 TTY_OVERRUN);
501 info->icount.rx++;
502 /* If the flip buffer itself is
503 overflowing, we still lose
504 the next incoming character.
505 */
506 tty_insert_flip_char(tty,
507 readb(base_addr + (CyRDSR <<
508 index)), TTY_FRAME);
509 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800510 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700511 /* These two conditions may imply */
512 /* a normal read should be done. */
513 /* } else if(data & CyTIMEOUT) { */
514 /* } else if(data & CySPECHAR) { */
515 } else {
516 tty_insert_flip_char(tty, 0,
517 TTY_NORMAL);
518 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800519 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700520 } else {
521 tty_insert_flip_char(tty, 0, TTY_NORMAL);
522 info->icount.rx++;
523 }
524 } else {
525 /* there was a software buffer overrun and nothing
526 * could be done about it!!! */
527 info->icount.buf_overrun++;
528 info->idle_stats.overruns++;
529 }
530 } else { /* normal character reception */
531 /* load # chars available from the chip */
532 char_count = readb(base_addr + (CyRDCR << index));
Jiri Slabye9410272006-12-08 02:39:28 -0800533
534#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700535 ++info->mon.int_count;
536 info->mon.char_count += char_count;
537 if (char_count > info->mon.char_max)
538 info->mon.char_max = char_count;
539 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800540#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700541 len = tty_buffer_request_room(tty, char_count);
542 while (len--) {
543 data = readb(base_addr + (CyRDSR << index));
544 tty_insert_flip_char(tty, data, TTY_NORMAL);
545 info->idle_stats.recv_bytes++;
546 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800547#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700548 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800549#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800550 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700551 info->idle_stats.recv_idle = jiffies;
552 }
553 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700554 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700555end:
556 /* end of service */
557 cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
558 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700559}
560
Jiri Slaby65f76a82007-10-18 03:06:22 -0700561static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700562 void __iomem *base_addr)
563{
564 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700565 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700566 int char_count, index = cinfo->bus_index;
567 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700568
569 /* Since we only get here when the transmit buffer
570 is empty, we know we can always stuff a dozen
571 characters. */
572#ifdef CY_DEBUG_INTERRUPTS
573 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
574#endif
575
576 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700577 save_xir = readb(base_addr + (CyTIR << index));
578 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700579 save_car = readb(base_addr + (CyCAR << index));
580 cy_writeb(base_addr + (CyCAR << index), save_xir);
581
582 /* validate the port# (as configured and open) */
583 if (channel + chip * 4 >= cinfo->nports) {
584 cy_writeb(base_addr + (CySRER << index),
585 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
586 goto end;
587 }
588 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700589 tty = tty_port_tty_get(&info->port);
590 if (tty == NULL) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700591 cy_writeb(base_addr + (CySRER << index),
592 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
593 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800594 }
595
Jiri Slabyce97a092007-10-18 03:06:21 -0700596 /* load the on-chip space for outbound data */
597 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800598
Jiri Slabyce97a092007-10-18 03:06:21 -0700599 if (info->x_char) { /* send special char */
600 outch = info->x_char;
601 cy_writeb(base_addr + (CyTDR << index), outch);
602 char_count--;
603 info->icount.tx++;
604 info->x_char = 0;
605 }
Jiri Slabye9410272006-12-08 02:39:28 -0800606
Jiri Slabyce97a092007-10-18 03:06:21 -0700607 if (info->breakon || info->breakoff) {
608 if (info->breakon) {
609 cy_writeb(base_addr + (CyTDR << index), 0);
610 cy_writeb(base_addr + (CyTDR << index), 0x81);
611 info->breakon = 0;
612 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800613 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700614 if (info->breakoff) {
615 cy_writeb(base_addr + (CyTDR << index), 0);
616 cy_writeb(base_addr + (CyTDR << index), 0x83);
617 info->breakoff = 0;
618 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800619 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700620 }
Jiri Slabye9410272006-12-08 02:39:28 -0800621
Jiri Slabyce97a092007-10-18 03:06:21 -0700622 while (char_count-- > 0) {
623 if (!info->xmit_cnt) {
624 if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
625 cy_writeb(base_addr + (CySRER << index),
626 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800627 ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700628 } else {
629 cy_writeb(base_addr + (CySRER << index),
630 (readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800631 ~CyTxRdy) | CyTxMpty);
Jiri Slaby02f11752006-12-08 02:39:28 -0800632 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700633 goto done;
634 }
Alan Cox77451e52008-07-16 21:57:02 +0100635 if (info->port.xmit_buf == NULL) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700636 cy_writeb(base_addr + (CySRER << index),
637 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800638 ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700639 goto done;
640 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700641 if (tty->stopped || tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700642 cy_writeb(base_addr + (CySRER << index),
643 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800644 ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700645 goto done;
646 }
647 /* Because the Embedded Transmit Commands have been enabled,
648 * we must check to see if the escape character, NULL, is being
649 * sent. If it is, we must ensure that there is room for it to
650 * be doubled in the output stream. Therefore we no longer
651 * advance the pointer when the character is fetched, but
652 * rather wait until after the check for a NULL output
653 * character. This is necessary because there may not be room
654 * for the two chars needed to send a NULL.)
655 */
Alan Cox77451e52008-07-16 21:57:02 +0100656 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700657 if (outch) {
658 info->xmit_cnt--;
659 info->xmit_tail = (info->xmit_tail + 1) &
660 (SERIAL_XMIT_SIZE - 1);
661 cy_writeb(base_addr + (CyTDR << index), outch);
662 info->icount.tx++;
663 } else {
664 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800665 info->xmit_cnt--;
666 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700667 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800668 cy_writeb(base_addr + (CyTDR << index), outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700669 cy_writeb(base_addr + (CyTDR << index), 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800670 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700671 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800672 }
673 }
Jiri Slabye9410272006-12-08 02:39:28 -0800674 }
675
Jiri Slabyce97a092007-10-18 03:06:21 -0700676done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700677 tty_wakeup(tty);
678 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700679end:
680 /* end of service */
681 cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
682 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700683}
Jiri Slabye9410272006-12-08 02:39:28 -0800684
Jiri Slabyce97a092007-10-18 03:06:21 -0700685static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
686 void __iomem *base_addr)
687{
688 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700689 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700690 int index = cinfo->bus_index;
691 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800692
Jiri Slabyce97a092007-10-18 03:06:21 -0700693 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700694 save_xir = readb(base_addr + (CyMIR << index));
695 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700696 info = &cinfo->ports[channel + chip * 4];
697 save_car = readb(base_addr + (CyCAR << index));
698 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800699
Jiri Slabyce97a092007-10-18 03:06:21 -0700700 mdm_change = readb(base_addr + (CyMISR << index));
701 mdm_status = readb(base_addr + (CyMSVR1 << index));
Jiri Slabye9410272006-12-08 02:39:28 -0800702
Jiri Slabyd13549f2009-09-19 13:13:12 -0700703 tty = tty_port_tty_get(&info->port);
704 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700705 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800706
Jiri Slabyce97a092007-10-18 03:06:21 -0700707 if (mdm_change & CyANY_DELTA) {
708 /* For statistics only */
709 if (mdm_change & CyDCD)
710 info->icount.dcd++;
711 if (mdm_change & CyCTS)
712 info->icount.cts++;
713 if (mdm_change & CyDSR)
714 info->icount.dsr++;
715 if (mdm_change & CyRI)
716 info->icount.rng++;
717
718 wake_up_interruptible(&info->delta_msr_wait);
719 }
720
Alan Cox77451e52008-07-16 21:57:02 +0100721 if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700722 if (mdm_status & CyDCD)
723 wake_up_interruptible(&info->port.open_wait);
724 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700725 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800726 }
Alan Cox77451e52008-07-16 21:57:02 +0100727 if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700728 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700729 if (mdm_status & CyCTS) {
730 /* cy_start isn't used
731 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700732 tty->hw_stopped = 0;
Jiri Slabyce97a092007-10-18 03:06:21 -0700733 cy_writeb(base_addr + (CySRER << index),
734 readb(base_addr + (CySRER << index)) |
735 CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700736 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700737 }
738 } else {
739 if (!(mdm_status & CyCTS)) {
740 /* cy_stop isn't used
741 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700742 tty->hw_stopped = 1;
Jiri Slabyce97a092007-10-18 03:06:21 -0700743 cy_writeb(base_addr + (CySRER << index),
744 readb(base_addr + (CySRER << index)) &
745 ~CyTxRdy);
746 }
747 }
748 }
749/* if (mdm_change & CyDSR) {
750 }
751 if (mdm_change & CyRI) {
752 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700753 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700754end:
755 /* end of service */
756 cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
757 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760/* The real interrupt service routine is called
761 whenever the card wants its hand held--chars
762 received, out buffer empty, modem change, etc.
763 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800764static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Jiri Slaby02f11752006-12-08 02:39:28 -0800766 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700767 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800768 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700769 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800770 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800771
Jiri Slabyf7429032007-05-08 00:36:59 -0700772 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700774 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
775 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800777 return IRQ_NONE; /* spurious interrupt */
778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Jiri Slaby02f11752006-12-08 02:39:28 -0800780 card_base_addr = cinfo->base_addr;
781 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700783 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
784 if (unlikely(card_base_addr == NULL))
785 return IRQ_HANDLED;
786
Jiri Slaby02f11752006-12-08 02:39:28 -0800787 /* This loop checks all chips in the card. Make a note whenever
788 _any_ chip had some work to do, as this is considered an
789 indication that there will be more to do. Only when no chip
790 has any work does this outermost loop exit.
791 */
792 do {
793 had_work = 0;
794 for (chip = 0; chip < cinfo->num_chips; chip++) {
795 base_addr = cinfo->base_addr +
796 (cy_chip_offset[chip] << index);
797 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700798 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800799 (CySVRR << index))) != 0x00) {
800 had_work++;
801 /* The purpose of the following test is to ensure that
802 no chip can monopolize the driver. This forces the
803 chips to be checked in a round-robin fashion (after
804 draining each of a bunch (1000) of characters).
805 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700806 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800807 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700808 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700809 if (status & CySRReceive) /* rx intr */
810 cyy_chip_rx(cinfo, chip, base_addr);
811 if (status & CySRTransmit) /* tx intr */
812 cyy_chip_tx(cinfo, chip, base_addr);
813 if (status & CySRModem) /* modem intr */
814 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700815 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800816 }
817 }
818 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Jiri Slaby02f11752006-12-08 02:39:28 -0800820 /* clear interrupts */
821 spin_lock(&cinfo->card_lock);
822 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
823 /* Cy_ClrIntr is 0x1800 */
824 spin_unlock(&cinfo->card_lock);
825 return IRQ_HANDLED;
826} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Jiri Slaby4d768202009-09-19 13:13:15 -0700828static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
829 unsigned int clear)
830{
831 struct cyclades_card *card = info->card;
832 void __iomem *base_addr;
833 int chip, channel, index;
834
835 channel = info->line - card->first_line;
836 chip = channel >> 2;
837 channel &= 0x03;
838 index = card->bus_index;
839 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
840
841 if (set & TIOCM_RTS) {
842 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
843 if (info->rtsdtr_inv) {
844 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
845 } else {
846 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
847 }
848 }
849 if (clear & TIOCM_RTS) {
850 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
851 if (info->rtsdtr_inv) {
852 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
853 } else {
854 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
855 }
856 }
857 if (set & TIOCM_DTR) {
858 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
859 if (info->rtsdtr_inv) {
860 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
861 } else {
862 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
863 }
864#ifdef CY_DEBUG_DTR
865 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
866 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
867 readb(base_addr + (CyMSVR1 << index)),
868 readb(base_addr + (CyMSVR2 << index)));
869#endif
870 }
871 if (clear & TIOCM_DTR) {
872 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
873 if (info->rtsdtr_inv) {
874 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
875 } else {
876 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
877 }
878
879#ifdef CY_DEBUG_DTR
880 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
881 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
882 readb(base_addr + (CyMSVR1 << index)),
883 readb(base_addr + (CyMSVR2 << index)));
884#endif
885 }
886}
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888/***********************************************************/
889/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700890/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891/***********************************************************/
892
893static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800894cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700895 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700897 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800898 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
Jiri Slaby97e87f82009-06-11 12:29:27 +0100900 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800901 if (loc_doorbell) {
902 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700903 *channel = readl(&board_ctrl->fwcmd_channel);
904 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100905 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800906 return 1;
907 }
908 return 0;
909} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800912cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700913 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700915 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700916 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700917 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Jiri Slaby2693f482009-06-11 12:31:06 +0100919 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800920 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700921
Jiri Slaby02f11752006-12-08 02:39:28 -0800922 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100923 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700924 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700925 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700926 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800927 udelay(50L);
928 }
929 cy_writel(&board_ctrl->hcmd_channel, channel);
930 cy_writel(&board_ctrl->hcmd_param, param);
931 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800933 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800934} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700936static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700938 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700939 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700940 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800941 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700943 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800945 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700947 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700949 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
950 rx_put = readl(&buf_ctrl->rx_put);
951 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
952 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800953 if (rx_put >= rx_get)
954 char_count = rx_put - rx_get;
955 else
956 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Jiri Slaby02f11752006-12-08 02:39:28 -0800958 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800960 info->mon.int_count++;
961 info->mon.char_count += char_count;
962 if (char_count > info->mon.char_max)
963 info->mon.char_max = char_count;
964 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700966 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800967 /* flush received characters */
968 new_rx_get = (new_rx_get + char_count) &
969 (rx_bufsize - 1);
970 info->rflush_count++;
971 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800973 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
974 for performance, but because of buffer boundaries, there
975 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700976 while (1) {
977 len = tty_prepare_flip_string(tty, &buf,
978 char_count);
979 if (!len)
980 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700982 len = min_t(unsigned int, min(len, char_count),
983 rx_bufsize - new_rx_get);
984
985 memcpy_fromio(buf, cinfo->base_addr +
986 rx_bufaddr + new_rx_get, len);
987
988 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800989 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700990 char_count -= len;
991 info->icount.rx += len;
992 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800995 len = tty_buffer_request_room(tty, char_count);
996 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700997 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800998 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700999 new_rx_get = (new_rx_get + 1) &
1000 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001001 tty_insert_flip_char(tty, data, TTY_NORMAL);
1002 info->idle_stats.recv_bytes++;
1003 info->icount.rx++;
1004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005#endif
1006#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001007 /* Recalculate the number of chars in the RX buffer and issue
1008 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001009 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001010 if (rx_put >= rx_get)
1011 char_count = rx_put - rx_get;
1012 else
1013 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001014 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -07001015 !timer_pending(&cyz_rx_full_timer[
1016 info->line]))
1017 mod_timer(&cyz_rx_full_timer[info->line],
1018 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001020 info->idle_stats.recv_idle = jiffies;
1021 tty_schedule_flip(tty);
1022 }
1023 /* Update rx_get */
1024 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026}
1027
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001028static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001030 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001031 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001032 u8 data;
1033 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001035 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001037 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Jiri Slaby02f11752006-12-08 02:39:28 -08001039 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1040 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001042 tx_get = readl(&buf_ctrl->tx_get);
1043 tx_put = readl(&buf_ctrl->tx_put);
1044 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1045 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001046 if (tx_put >= tx_get)
1047 char_count = tx_get - tx_put - 1 + tx_bufsize;
1048 else
1049 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Jiri Slaby02f11752006-12-08 02:39:28 -08001051 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Jiri Slabyf7429032007-05-08 00:36:59 -07001053 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001054 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001055
1056 if (info->x_char) { /* send special char */
1057 data = info->x_char;
1058
1059 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1060 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1061 info->x_char = 0;
1062 char_count--;
1063 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001064 }
1065#ifdef BLOCKMOVE
1066 while (0 < (small_count = min_t(unsigned int,
1067 tx_bufsize - tx_put, min_t(unsigned int,
1068 (SERIAL_XMIT_SIZE - info->xmit_tail),
1069 min_t(unsigned int, info->xmit_cnt,
1070 char_count))))) {
1071
1072 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1073 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001074 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001075 small_count);
1076
1077 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1078 char_count -= small_count;
1079 info->icount.tx += small_count;
1080 info->xmit_cnt -= small_count;
1081 info->xmit_tail = (info->xmit_tail + small_count) &
1082 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001083 }
1084#else
1085 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001086 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001087 info->xmit_cnt--;
1088 info->xmit_tail = (info->xmit_tail + 1) &
1089 (SERIAL_XMIT_SIZE - 1);
1090
1091 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1092 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1093 char_count--;
1094 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001097 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001098ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001099 /* Update tx_put */
1100 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102}
1103
Jiri Slaby02f11752006-12-08 02:39:28 -08001104static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001106 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001107 struct tty_struct *tty;
1108 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001109 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001110 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001111 int special_count;
1112 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001114 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Jiri Slaby02f11752006-12-08 02:39:28 -08001116 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1117 special_count = 0;
1118 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001119 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001120 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001121 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001122 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001123
Jiri Slaby02f11752006-12-08 02:39:28 -08001124 switch (cmd) {
1125 case C_CM_PR_ERROR:
1126 tty_insert_flip_char(tty, 0, TTY_PARITY);
1127 info->icount.rx++;
1128 special_count++;
1129 break;
1130 case C_CM_FR_ERROR:
1131 tty_insert_flip_char(tty, 0, TTY_FRAME);
1132 info->icount.rx++;
1133 special_count++;
1134 break;
1135 case C_CM_RXBRK:
1136 tty_insert_flip_char(tty, 0, TTY_BREAK);
1137 info->icount.rx++;
1138 special_count++;
1139 break;
1140 case C_CM_MDCD:
1141 info->icount.dcd++;
1142 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001143 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001144 u32 dcd = fw_ver > 241 ? param :
1145 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001146 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001147 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001148 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001149 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001150 }
1151 break;
1152 case C_CM_MCTS:
1153 info->icount.cts++;
1154 delta_count++;
1155 break;
1156 case C_CM_MRI:
1157 info->icount.rng++;
1158 delta_count++;
1159 break;
1160 case C_CM_MDSR:
1161 info->icount.dsr++;
1162 delta_count++;
1163 break;
1164#ifdef Z_WAKE
1165 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001166 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001167 break;
1168#endif
1169#ifdef CONFIG_CYZ_INTR
1170 case C_CM_RXHIWM:
1171 case C_CM_RXNNDT:
1172 case C_CM_INTBACK2:
1173 /* Reception Interrupt */
1174#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001175 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1176 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001177#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001178 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001179 break;
1180 case C_CM_TXBEMPTY:
1181 case C_CM_TXLOWWM:
1182 case C_CM_INTBACK:
1183 /* Transmission Interrupt */
1184#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001185 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1186 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001187#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001188 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001189 break;
1190#endif /* CONFIG_CYZ_INTR */
1191 case C_CM_FATAL:
1192 /* should do something with this !!! */
1193 break;
1194 default:
1195 break;
1196 }
1197 if (delta_count)
Jiri Slabyebafeef2007-10-18 03:06:20 -07001198 wake_up_interruptible(&info->delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001199 if (special_count)
1200 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001201 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001202 }
1203}
1204
1205#ifdef CONFIG_CYZ_INTR
1206static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1207{
Jiri Slabyf7429032007-05-08 00:36:59 -07001208 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001209
Jiri Slaby2693f482009-06-11 12:31:06 +01001210 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001211#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001212 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1213 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001214#endif
1215 return IRQ_NONE;
1216 }
1217
1218 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 cyz_handle_cmd(cinfo);
1220
Jiri Slaby02f11752006-12-08 02:39:28 -08001221 return IRQ_HANDLED;
1222} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
Jiri Slaby02f11752006-12-08 02:39:28 -08001224static void cyz_rx_restart(unsigned long arg)
1225{
1226 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001227 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001228 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001229 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001230 unsigned long flags;
1231
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001232 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001233 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001234 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001235 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001236 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001238 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001239}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Jiri Slaby02f11752006-12-08 02:39:28 -08001241#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jiri Slaby02f11752006-12-08 02:39:28 -08001243static void cyz_poll(unsigned long arg)
1244{
1245 struct cyclades_card *cinfo;
1246 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001247 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001248 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001249
Jiri Slaby02f11752006-12-08 02:39:28 -08001250 for (card = 0; card < NR_CARDS; card++) {
1251 cinfo = &cy_card[card];
1252
Jiri Slaby2693f482009-06-11 12:31:06 +01001253 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001254 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001255 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001256 continue;
1257
Jiri Slaby02f11752006-12-08 02:39:28 -08001258 /* Skip first polling cycle to avoid racing conditions with the FW */
1259 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001260 cinfo->intr_enabled = 1;
1261 continue;
1262 }
1263
1264 cyz_handle_cmd(cinfo);
1265
1266 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001267 struct tty_struct *tty;
1268
Jiri Slabydd025c02007-05-08 00:37:02 -07001269 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001270 tty = tty_port_tty_get(&info->port);
1271 /* OK to pass NULL to the handle functions below.
1272 They need to drop the data in that case. */
1273
Jiri Slaby02f11752006-12-08 02:39:28 -08001274 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001275 cyz_handle_rx(info, tty);
1276 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001277 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001278 }
1279 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001280 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001281 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001282 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001283} /* cyz_poll */
1284
1285#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
1287/********** End of block of Cyclades-Z specific code *********/
1288/***********************************************************/
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290/* This is called whenever a port becomes active;
1291 interrupts are enabled and DTR & RTS are turned on.
1292 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001293static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
Jiri Slaby875b2062007-05-08 00:36:49 -07001295 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001296 unsigned long flags;
1297 int retval = 0;
1298 void __iomem *base_addr;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001299 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001300 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Jiri Slaby02f11752006-12-08 02:39:28 -08001302 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001303 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Jiri Slaby02f11752006-12-08 02:39:28 -08001305 page = get_zeroed_page(GFP_KERNEL);
1306 if (!page)
1307 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001309 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001311 if (info->port.flags & ASYNC_INITIALIZED)
Jiri Slaby02f11752006-12-08 02:39:28 -08001312 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001313
1314 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001315 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001316 goto errout;
1317 }
1318
Alan Cox77451e52008-07-16 21:57:02 +01001319 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001320 free_page(page);
1321 else
Alan Cox77451e52008-07-16 21:57:02 +01001322 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001324 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Jiri Slabyd13549f2009-09-19 13:13:12 -07001326 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Jiri Slaby2693f482009-06-11 12:31:06 +01001328 if (!cy_is_Z(card)) {
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001329 int chip = channel >> 2;
1330 int index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001331 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001332 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001335 printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
1336 "base_addr %p\n",
1337 card, chip, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001338#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001339 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001340
1341 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1342
1343 cy_writeb(base_addr + (CyRTPR << index),
1344 (info->default_timeout ? info->default_timeout : 0x02));
1345 /* 10ms rx timeout */
1346
1347 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
1348 index);
1349
Jiri Slaby4d768202009-09-19 13:13:15 -07001350 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jiri Slaby02f11752006-12-08 02:39:28 -08001352 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001353 readb(base_addr + (CySRER << index)) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001354 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001355 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001356
Jiri Slaby2693f482009-06-11 12:31:06 +01001357 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001358 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001359
Jiri Slaby02f11752006-12-08 02:39:28 -08001360#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001361 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001362 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001363#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001364 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001365
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001366 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367#ifdef Z_WAKE
1368#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001369 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001370 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1371 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001373 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001374 C_IN_IOCTLW | C_IN_MDCD);
1375#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376#else
1377#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001378 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001379 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1380 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001382 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001383#endif /* CONFIG_CYZ_INTR */
1384#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Jiri Slaby875b2062007-05-08 00:36:49 -07001386 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001387 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001388 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1389 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Jiri Slaby02f11752006-12-08 02:39:28 -08001392 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001393 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001394 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001395 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1396 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Jiri Slaby02f11752006-12-08 02:39:28 -08001399 /* set timeout !!! */
1400 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001401 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Jiri Slaby02f11752006-12-08 02:39:28 -08001403 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001406 info->port.flags |= ASYNC_INITIALIZED;
1407
1408 clear_bit(TTY_IO_ERROR, &tty->flags);
1409 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1410 info->breakon = info->breakoff = 0;
1411 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1412 info->idle_stats.in_use =
1413 info->idle_stats.recv_idle =
1414 info->idle_stats.xmit_idle = jiffies;
1415
1416 spin_unlock_irqrestore(&card->card_lock, flags);
1417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001419 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420#endif
1421 return 0;
1422
1423errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001424 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001425 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001427} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Jiri Slaby02f11752006-12-08 02:39:28 -08001429static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430{
Jiri Slaby875b2062007-05-08 00:36:49 -07001431 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001432 unsigned long flags;
1433 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001434 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Jiri Slaby02f11752006-12-08 02:39:28 -08001436 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001437 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001438 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001439 chip = channel >> 2;
1440 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001441 index = card->bus_index;
1442 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001444 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001445 cy_writeb(base_addr + (CyCAR << index), channel);
1446 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001447 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001448 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001449 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001451 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001453 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001454 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001455 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001456 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1457 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001458 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001459 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001460#else /* CONFIG_CYZ_INTR */
1461 /* Don't have to do anything at this time */
1462#endif /* CONFIG_CYZ_INTR */
1463 }
1464} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466/*
1467 * This routine shuts down a serial port; interrupts are disabled,
1468 * and DTR is dropped if the hangup on close termio flag is on.
1469 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001470static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
Jiri Slaby875b2062007-05-08 00:36:49 -07001472 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001473 unsigned long flags;
1474 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001475 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Alan Cox77451e52008-07-16 21:57:02 +01001477 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001478 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Jiri Slaby02f11752006-12-08 02:39:28 -08001480 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001481 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001482 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001483 chip = channel >> 2;
1484 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001485 index = card->bus_index;
1486 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001489 printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
1490 "channel %d, base_addr %p\n",
1491 card, chip, channel, base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001494 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001495
1496 /* Clear delta_msr_wait queue to avoid mem leaks. */
1497 wake_up_interruptible(&info->delta_msr_wait);
1498
Alan Cox77451e52008-07-16 21:57:02 +01001499 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001500 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001501 temp = info->port.xmit_buf;
1502 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001503 free_page((unsigned long)temp);
1504 }
Jiri Slaby4d768202009-09-19 13:13:15 -07001505 if (tty->termios->c_cflag & HUPCL)
1506 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1507
Jiri Slaby02f11752006-12-08 02:39:28 -08001508 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
1509 /* it may be appropriate to clear _XMIT at
1510 some later date (after testing)!!! */
1511
Jiri Slabyd13549f2009-09-19 13:13:12 -07001512 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001513 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001514 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001515 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001516#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001517 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001518 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001519#endif
1520
Jiri Slaby2693f482009-06-11 12:31:06 +01001521 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001522 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001523
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001524 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001525
Alan Cox77451e52008-07-16 21:57:02 +01001526 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001527 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001528 temp = info->port.xmit_buf;
1529 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001530 free_page((unsigned long)temp);
1531 }
1532
Jiri Slaby4d768202009-09-19 13:13:15 -07001533 if (tty->termios->c_cflag & HUPCL)
1534 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001535
Jiri Slabyd13549f2009-09-19 13:13:12 -07001536 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001537 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001538
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001539 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001540 }
1541
1542#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001543 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001544#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001545} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547/*
1548 * ------------------------------------------------------------
1549 * cy_open() and friends
1550 * ------------------------------------------------------------
1551 */
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553/*
1554 * This routine is called whenever a serial port is opened. It
1555 * performs the serial-specific initialization for the tty structure.
1556 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001557static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558{
Jiri Slaby02f11752006-12-08 02:39:28 -08001559 struct cyclades_port *info;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001560 unsigned int i, line;
1561 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Jiri Slaby02f11752006-12-08 02:39:28 -08001563 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001564 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001566
Jiri Slabydd025c02007-05-08 00:37:02 -07001567 for (i = 0; i < NR_CARDS; i++)
1568 if (line < cy_card[i].first_line + cy_card[i].nports &&
1569 line >= cy_card[i].first_line)
1570 break;
1571 if (i >= NR_CARDS)
1572 return -ENODEV;
1573 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001574 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001575 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001576
1577 /* If the card's firmware hasn't been loaded,
1578 treat it as absent from the system. This
1579 will make the user pay attention.
1580 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001581 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001582 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001583 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1584
Jiri Slaby2693f482009-06-11 12:31:06 +01001585 if (!cyz_is_loaded(cinfo)) {
1586 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001587 readl(&firm_id->signature) ==
1588 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001589 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1590 "need an external power supply for "
1591 "this number of ports.\nFirmware "
1592 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001593 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001594 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1595 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001596 }
1597 return -ENODEV;
1598 }
1599#ifdef CONFIG_CYZ_INTR
1600 else {
1601 /* In case this Z board is operating in interrupt mode, its
1602 interrupts should be enabled as soon as the first open
1603 happens to one of its ports. */
1604 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001605 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001606
Jiri Slaby02f11752006-12-08 02:39:28 -08001607 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001608 intr = readw(&cinfo->ctl_addr.p9060->
1609 intr_ctrl_stat) | 0x0900;
1610 cy_writew(&cinfo->ctl_addr.p9060->
1611 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 /* Enable interrupts on the FW */
1613 retval = cyz_issue_cmd(cinfo, 0,
1614 C_CM_IRQ_ENBL, 0L);
1615 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001616 printk(KERN_ERR "cyc:IRQ enable retval "
1617 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001618 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001619 cinfo->intr_enabled = 1;
1620 }
1621 }
1622#endif /* CONFIG_CYZ_INTR */
1623 /* Make sure this Z port really exists in hardware */
1624 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1625 return -ENODEV;
1626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001628 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001630 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001631 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001632 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001635 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001636 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637#endif
Alan Cox77451e52008-07-16 21:57:02 +01001638 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001640 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001641 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Jiri Slaby02f11752006-12-08 02:39:28 -08001644 /*
1645 * If the port is the middle of closing, bail out now
1646 */
Alan Cox77451e52008-07-16 21:57:02 +01001647 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1648 wait_event_interruptible(info->port.close_wait,
1649 !(info->port.flags & ASYNC_CLOSING));
1650 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Jiri Slaby02f11752006-12-08 02:39:28 -08001653 /*
1654 * Start up serial port
1655 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001656 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001657 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001658 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Jiri Slabyf0737572009-09-19 13:13:12 -07001660 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001661 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001663 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1664 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001666 return retval;
1667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Jiri Slaby02f11752006-12-08 02:39:28 -08001669 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001670 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001673 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001675 return 0;
1676} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678/*
1679 * cy_wait_until_sent() --- wait until the transmitter is empty
1680 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001681static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
Jiri Slaby875b2062007-05-08 00:36:49 -07001683 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001684 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001685 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001686 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001687 unsigned long orig_jiffies;
1688 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Jiri Slaby02f11752006-12-08 02:39:28 -08001690 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1691 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Jiri Slaby02f11752006-12-08 02:39:28 -08001693 if (info->xmit_fifo_size == 0)
1694 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Jiri Slaby02f11752006-12-08 02:39:28 -08001696 orig_jiffies = jiffies;
Alan Cox978e5952008-04-30 00:53:59 -07001697 lock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08001698 /*
1699 * Set the check interval to be 1/5 of the estimated time to
1700 * send a single character, and make it at least 1. The check
1701 * interval should also be less than the timeout.
1702 *
1703 * Note: we have to use pretty tight timings here to satisfy
1704 * the NIST-PCTS.
1705 */
1706 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1707 char_time = char_time / 5;
1708 if (char_time <= 0)
1709 char_time = 1;
1710 if (timeout < 0)
1711 timeout = 0;
1712 if (timeout)
1713 char_time = min(char_time, timeout);
1714 /*
1715 * If the transmitter hasn't cleared in twice the approximate
1716 * amount of time to send the entire FIFO, it probably won't
1717 * ever clear. This assumes the UART isn't doing flow
1718 * control, which is currently the case. Hence, if it ever
1719 * takes longer than info->timeout, this is probably due to a
1720 * UART bug of some kind. So, we clamp the timeout parameter at
1721 * 2*info->timeout.
1722 */
1723 if (!timeout || timeout > 2 * info->timeout)
1724 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001726 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1727 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001729 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001730 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01001731 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001732 chip = channel >> 2;
1733 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001734 index = card->bus_index;
1735 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001736 while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001738 printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001740 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1741 break;
1742 if (timeout && time_after(jiffies, orig_jiffies +
1743 timeout))
1744 break;
1745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001747 /* Run one more char cycle */
1748 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Alan Cox978e5952008-04-30 00:53:59 -07001749 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001751 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752#endif
1753}
1754
Alan Cox978e5952008-04-30 00:53:59 -07001755static void cy_flush_buffer(struct tty_struct *tty)
1756{
1757 struct cyclades_port *info = tty->driver_data;
1758 struct cyclades_card *card;
1759 int channel, retval;
1760 unsigned long flags;
1761
1762#ifdef CY_DEBUG_IO
1763 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1764#endif
1765
1766 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1767 return;
1768
1769 card = info->card;
1770 channel = info->line - card->first_line;
1771
1772 spin_lock_irqsave(&card->card_lock, flags);
1773 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1774 spin_unlock_irqrestore(&card->card_lock, flags);
1775
Jiri Slaby2693f482009-06-11 12:31:06 +01001776 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001777 buffers as well */
1778 spin_lock_irqsave(&card->card_lock, flags);
1779 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1780 if (retval != 0) {
1781 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1782 "was %x\n", info->line, retval);
1783 }
1784 spin_unlock_irqrestore(&card->card_lock, flags);
1785 }
1786 tty_wakeup(tty);
1787} /* cy_flush_buffer */
1788
1789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790/*
1791 * This routine is called when a particular tty device is closed.
1792 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001793static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001795 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001796 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001797 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Alan Cox15ed6cc2008-04-30 00:53:55 -07001799 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001800 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001802 card = info->card;
1803
Jiri Slaby23342262009-09-19 13:13:13 -07001804 if (!tty_port_close_start(&info->port, tty, filp))
Jiri Slaby02f11752006-12-08 02:39:28 -08001805 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001806
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001807 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001808
Jiri Slaby2693f482009-06-11 12:31:06 +01001809 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001810 int channel = info->line - card->first_line;
1811 int index = card->bus_index;
1812 void __iomem *base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 (cy_chip_offset[channel >> 2] << index);
1814 /* Stop accepting input */
1815 channel &= 0x03;
1816 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1817 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001818 readb(base_addr + (CySRER << index)) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001819 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001820 /* Waiting for on-board buffers to be empty before
1821 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001822 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001823 cy_wait_until_sent(tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001824 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001825 }
1826 } else {
1827#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001828 /* Waiting for on-board buffers to be empty before closing
1829 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001830 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001831 int channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001832 int retval;
1833
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001834 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001835 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001836 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001837 printk(KERN_DEBUG "cyc:cy_close retval on "
1838 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001839 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001840 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001841 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001842 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001843 }
1844#endif
1845 }
1846
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001847 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001848 cy_shutdown(info, tty);
Alan Cox978e5952008-04-30 00:53:59 -07001849 cy_flush_buffer(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001850
Jiri Slabyd13549f2009-09-19 13:13:12 -07001851 tty_port_tty_set(&info->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Jiri Slaby23342262009-09-19 13:13:13 -07001853 tty_port_close_end(&info->port, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001854} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
1856/* This routine gets called when tty_write has put something into
1857 * the write_queue. The characters may come from user space or
1858 * kernel space.
1859 *
1860 * This routine will return the number of characters actually
1861 * accepted for writing.
1862 *
1863 * If the port is not already transmitting stuff, start it off by
1864 * enabling interrupts. The interrupt service routine will then
1865 * ensure that the characters are sent.
1866 * If the port is already active, there is no need to kick it.
1867 *
1868 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001869static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001871 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001872 unsigned long flags;
1873 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001876 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877#endif
1878
Alan Cox15ed6cc2008-04-30 00:53:55 -07001879 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001880 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Alan Cox77451e52008-07-16 21:57:02 +01001882 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001883 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001885 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001886 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001887 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1888 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Jiri Slaby02f11752006-12-08 02:39:28 -08001890 if (c <= 0)
1891 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
Alan Cox77451e52008-07-16 21:57:02 +01001893 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001894 info->xmit_head = (info->xmit_head + c) &
1895 (SERIAL_XMIT_SIZE - 1);
1896 info->xmit_cnt += c;
1897 buf += c;
1898 count -= c;
1899 ret += c;
1900 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001901 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
Jiri Slaby02f11752006-12-08 02:39:28 -08001903 info->idle_stats.xmit_bytes += ret;
1904 info->idle_stats.xmit_idle = jiffies;
1905
Alan Cox15ed6cc2008-04-30 00:53:55 -07001906 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001908
Jiri Slaby02f11752006-12-08 02:39:28 -08001909 return ret;
1910} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912/*
1913 * This routine is called by the kernel to write a single
1914 * character to the tty device. If the kernel uses this routine,
1915 * it must call the flush_chars() routine (if defined) when it is
1916 * done stuffing characters into the driver. If there is no room
1917 * in the queue, the character is ignored.
1918 */
Alan Cox76b25a52008-04-30 00:54:03 -07001919static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001921 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001922 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001925 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926#endif
1927
Jiri Slaby02f11752006-12-08 02:39:28 -08001928 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001929 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
Alan Cox77451e52008-07-16 21:57:02 +01001931 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001932 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001934 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001935 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001936 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001937 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
Alan Cox77451e52008-07-16 21:57:02 +01001940 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001941 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1942 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 info->idle_stats.xmit_bytes++;
1944 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001945 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001946 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001947} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949/*
1950 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001951 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001953static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001955 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001956
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001958 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959#endif
1960
Jiri Slaby02f11752006-12-08 02:39:28 -08001961 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1962 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
Jiri Slaby02f11752006-12-08 02:39:28 -08001964 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001965 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001966 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Jiri Slaby02f11752006-12-08 02:39:28 -08001968 start_xmit(info);
1969} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971/*
1972 * This routine returns the numbers of characters the tty driver
1973 * will accept for queuing to be written. This number is subject
1974 * to change as output buffers get emptied, or if the output flow
1975 * control is activated.
1976 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001977static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001979 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001980 int ret;
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001983 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984#endif
1985
Jiri Slaby02f11752006-12-08 02:39:28 -08001986 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1987 return 0;
1988 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1989 if (ret < 0)
1990 ret = 0;
1991 return ret;
1992} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Jiri Slaby02f11752006-12-08 02:39:28 -08001994static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001996 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
Jiri Slaby02f11752006-12-08 02:39:28 -08001998 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1999 return 0;
2000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002002 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002003#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002005 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2006 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002008 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002010 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002011 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002012 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07002013 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Alan Cox978e5952008-04-30 00:53:59 -07002015 lock_kernel();
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002016 tx_get = readl(&buf_ctrl->tx_get);
2017 tx_put = readl(&buf_ctrl->tx_put);
2018 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08002019 if (tx_put >= tx_get)
2020 char_count = tx_put - tx_get;
2021 else
2022 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002024 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2025 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026#endif
Alan Cox978e5952008-04-30 00:53:59 -07002027 unlock_kernel();
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002028 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08002029 }
2030#endif /* Z_EXT_CHARS_IN_BUFFER */
2031} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033/*
2034 * ------------------------------------------------------------
2035 * cy_ioctl() and friends
2036 * ------------------------------------------------------------
2037 */
2038
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002039static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
Jiri Slaby02f11752006-12-08 02:39:28 -08002041 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002042 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08002043 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Jiri Slaby02f11752006-12-08 02:39:28 -08002045 if (baud == 0) {
2046 info->tbpr = info->tco = info->rbpr = info->rco = 0;
2047 return;
2048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Jiri Slaby02f11752006-12-08 02:39:28 -08002050 /* determine which prescaler to use */
2051 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
2052 if (cy_clock / co_val / baud > 63)
2053 break;
2054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
Jiri Slaby02f11752006-12-08 02:39:28 -08002056 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
2057 if (bpr > 255)
2058 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
Jiri Slaby02f11752006-12-08 02:39:28 -08002060 info->tbpr = info->rbpr = bpr;
2061 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062}
2063
2064/*
2065 * This routine finds or computes the various line characteristics.
2066 * It used to be called config_setup
2067 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002068static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069{
Jiri Slaby875b2062007-05-08 00:36:49 -07002070 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002071 unsigned long flags;
2072 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002073 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002074 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002075 int baud, baud_rate = 0;
2076 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Jiri Slabyd13549f2009-09-19 13:13:12 -07002078 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002079 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002080
2081 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002082 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002083
Jiri Slabyd13549f2009-09-19 13:13:12 -07002084 cflag = tty->termios->c_cflag;
2085 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Jiri Slaby02f11752006-12-08 02:39:28 -08002087 /*
2088 * Set up the tty->alt_speed kludge
2089 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002090 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2091 tty->alt_speed = 57600;
2092 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2093 tty->alt_speed = 115200;
2094 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2095 tty->alt_speed = 230400;
2096 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2097 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
Jiri Slaby02f11752006-12-08 02:39:28 -08002099 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002100 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002101
Jiri Slaby2693f482009-06-11 12:31:06 +01002102 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002103
Jiri Slaby875b2062007-05-08 00:36:49 -07002104 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002105
2106 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002107 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002108 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002109 ASYNC_SPD_CUST) {
2110 if (info->custom_divisor)
2111 baud_rate = info->baud / info->custom_divisor;
2112 else
2113 baud_rate = info->baud;
2114 } else if (baud > CD1400_MAX_SPEED) {
2115 baud = CD1400_MAX_SPEED;
2116 }
2117 /* find the baud index */
2118 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002119 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002120 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002121 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002122 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002123 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002124
Alan Cox77451e52008-07-16 21:57:02 +01002125 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002126 ASYNC_SPD_CUST) {
2127 cyy_baud_calc(info, baud_rate);
2128 } else {
2129 if (info->chip_rev >= CD1400_REV_J) {
2130 /* It is a CD1400 rev. J or later */
2131 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2132 info->tco = baud_co_60[i]; /* Tx CO */
2133 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2134 info->rco = baud_co_60[i]; /* Rx CO */
2135 } else {
2136 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2137 info->tco = baud_co_25[i]; /* Tx CO */
2138 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2139 info->rco = baud_co_25[i]; /* Rx CO */
2140 }
2141 }
2142 if (baud_table[i] == 134) {
2143 /* get it right for 134.5 baud */
2144 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2145 2;
Alan Cox77451e52008-07-16 21:57:02 +01002146 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002147 ASYNC_SPD_CUST) {
2148 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2149 baud_rate) + 2;
2150 } else if (baud_table[i]) {
2151 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2152 baud_table[i]) + 2;
2153 /* this needs to be propagated into the card info */
2154 } else {
2155 info->timeout = 0;
2156 }
2157 /* By tradition (is it a standard?) a baud rate of zero
2158 implies the line should be/has been closed. A bit
2159 later in this routine such a test is performed. */
2160
2161 /* byte size and parity */
2162 info->cor5 = 0;
2163 info->cor4 = 0;
2164 /* receive threshold */
2165 info->cor3 = (info->default_threshold ?
2166 info->default_threshold : baud_cor3[i]);
2167 info->cor2 = CyETC;
2168 switch (cflag & CSIZE) {
2169 case CS5:
2170 info->cor1 = Cy_5_BITS;
2171 break;
2172 case CS6:
2173 info->cor1 = Cy_6_BITS;
2174 break;
2175 case CS7:
2176 info->cor1 = Cy_7_BITS;
2177 break;
2178 case CS8:
2179 info->cor1 = Cy_8_BITS;
2180 break;
2181 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002182 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002183 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002184
Jiri Slaby02f11752006-12-08 02:39:28 -08002185 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002186 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002187 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002188 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002189 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002190 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002191 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002192
2193 /* CTS flow control flag */
2194 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002195 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002196 info->cor2 |= CyCtsAE;
2197 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002198 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002199 info->cor2 &= ~CyCtsAE;
2200 }
2201 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002202 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002203 else
Alan Cox77451e52008-07-16 21:57:02 +01002204 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206 /***********************************************
2207 The hardware option, CyRtsAO, presents RTS when
2208 the chip has characters to send. Since most modems
2209 use RTS as reverse (inbound) flow control, this
2210 option is not used. If inbound flow control is
2211 necessary, DTR can be programmed to provide the
2212 appropriate signals for use with a non-standard
2213 cable. Contact Marcio Saito for details.
2214 ***********************************************/
2215
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 chip = channel >> 2;
2217 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002218 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002220 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002221 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Jiri Slaby02f11752006-12-08 02:39:28 -08002223 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Jiri Slaby02f11752006-12-08 02:39:28 -08002225 cy_writeb(base_addr + (CyTCOR << index), info->tco);
2226 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
2227 cy_writeb(base_addr + (CyRCOR << index), info->rco);
2228 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Jiri Slaby02f11752006-12-08 02:39:28 -08002230 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Jiri Slabyd13549f2009-09-19 13:13:12 -07002232 cy_writeb(base_addr + (CySCHR1 << index), START_CHAR(tty));
2233 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(tty));
Jiri Slaby02f11752006-12-08 02:39:28 -08002234 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
2235 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
2236 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2237 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
2238 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Jiri Slaby02f11752006-12-08 02:39:28 -08002240 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2241 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Alan Cox15ed6cc2008-04-30 00:53:55 -07002243 /* !!! Is this needed? */
2244 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08002245 cy_writeb(base_addr + (CyRTPR << index),
2246 (info->default_timeout ? info->default_timeout : 0x02));
2247 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
Jiri Slabyd13549f2009-09-19 13:13:12 -07002249 if (C_CLOCAL(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002250 /* without modem intr */
2251 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002252 readb(base_addr + (CySRER << index)) | CyMdmCh);
Jiri Slaby02f11752006-12-08 02:39:28 -08002253 /* act on 1->0 modem transitions */
2254 if ((cflag & CRTSCTS) && info->rflow) {
2255 cy_writeb(base_addr + (CyMCOR1 << index),
2256 (CyCTS | rflow_thr[i]));
2257 } else {
2258 cy_writeb(base_addr + (CyMCOR1 << index),
2259 CyCTS);
2260 }
2261 /* act on 0->1 modem transitions */
2262 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002264 /* without modem intr */
2265 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002266 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002267 (CySRER << index)) | CyMdmCh);
2268 /* act on 1->0 modem transitions */
2269 if ((cflag & CRTSCTS) && info->rflow) {
2270 cy_writeb(base_addr + (CyMCOR1 << index),
2271 (CyDSR | CyCTS | CyRI | CyDCD |
2272 rflow_thr[i]));
2273 } else {
2274 cy_writeb(base_addr + (CyMCOR1 << index),
2275 CyDSR | CyCTS | CyRI | CyDCD);
2276 }
2277 /* act on 0->1 modem transitions */
2278 cy_writeb(base_addr + (CyMCOR2 << index),
2279 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002281
Jiri Slaby4d768202009-09-19 13:13:15 -07002282 if (i == 0) /* baud rate is zero, turn off line */
2283 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2284 else
2285 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Jiri Slabyd13549f2009-09-19 13:13:12 -07002287 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002288 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002291 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002292 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002293 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
Jiri Slaby2693f482009-06-11 12:31:06 +01002295 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002296 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
Jiri Slaby02f11752006-12-08 02:39:28 -08002298 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002299 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002300 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002301 ASYNC_SPD_CUST) {
2302 if (info->custom_divisor)
2303 baud_rate = info->baud / info->custom_divisor;
2304 else
2305 baud_rate = info->baud;
2306 } else if (baud > CYZ_MAX_SPEED) {
2307 baud = CYZ_MAX_SPEED;
2308 }
2309 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Jiri Slaby02f11752006-12-08 02:39:28 -08002311 if (baud == 134) {
2312 /* get it right for 134.5 baud */
2313 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2314 2;
Alan Cox77451e52008-07-16 21:57:02 +01002315 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002316 ASYNC_SPD_CUST) {
2317 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2318 baud_rate) + 2;
2319 } else if (baud) {
2320 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2321 baud) + 2;
2322 /* this needs to be propagated into the card info */
2323 } else {
2324 info->timeout = 0;
2325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
Jiri Slaby02f11752006-12-08 02:39:28 -08002327 /* byte size and parity */
2328 switch (cflag & CSIZE) {
2329 case CS5:
2330 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2331 break;
2332 case CS6:
2333 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2334 break;
2335 case CS7:
2336 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2337 break;
2338 case CS8:
2339 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2340 break;
2341 }
2342 if (cflag & CSTOPB) {
2343 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002344 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002345 } else {
2346 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002347 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002348 }
2349 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002350 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002351 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002352 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002353 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002354 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002355 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Jiri Slaby02f11752006-12-08 02:39:28 -08002357 /* CTS flow control flag */
2358 if (cflag & CRTSCTS) {
2359 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002360 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002361 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002362 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2363 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002364 }
2365 /* As the HW flow control is done in firmware, the driver
2366 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002367 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002368
2369 /* XON/XOFF/XANY flow control flags */
2370 sw_flow = 0;
2371 if (iflag & IXON) {
2372 sw_flow |= C_FL_OXX;
2373 if (iflag & IXANY)
2374 sw_flow |= C_FL_OIXANY;
2375 }
2376 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2377
Jiri Slaby875b2062007-05-08 00:36:49 -07002378 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002379 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002380 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2381 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002382 }
2383
2384 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002385 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002386 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002387 else
Alan Cox77451e52008-07-16 21:57:02 +01002388 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002389
2390 if (baud == 0) { /* baud rate is zero, turn off line */
2391 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002392 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002394 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002396 } else {
2397 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002398 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002400 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
Alan Cox15ed6cc2008-04-30 00:53:55 -07002404 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002405 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002406 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2407 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
Jiri Slabyd13549f2009-09-19 13:13:12 -07002410 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002412} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002415get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002416 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417{
Jiri Slaby02f11752006-12-08 02:39:28 -08002418 struct serial_struct tmp;
Jiri Slaby875b2062007-05-08 00:36:49 -07002419 struct cyclades_card *cinfo = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Jiri Slaby02f11752006-12-08 02:39:28 -08002421 if (!retinfo)
2422 return -EFAULT;
2423 memset(&tmp, 0, sizeof(tmp));
2424 tmp.type = info->type;
2425 tmp.line = info->line;
Jiri Slaby875b2062007-05-08 00:36:49 -07002426 tmp.port = (info->card - cy_card) * 0x100 + info->line -
2427 cinfo->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002428 tmp.irq = cinfo->irq;
Alan Cox77451e52008-07-16 21:57:02 +01002429 tmp.flags = info->port.flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01002430 tmp.close_delay = info->port.close_delay;
2431 tmp.closing_wait = info->port.closing_wait;
Jiri Slaby02f11752006-12-08 02:39:28 -08002432 tmp.baud_base = info->baud;
2433 tmp.custom_divisor = info->custom_divisor;
2434 tmp.hub6 = 0; /*!!! */
2435 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
2436} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002439cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002440 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441{
Jiri Slaby02f11752006-12-08 02:39:28 -08002442 struct serial_struct new_serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Jiri Slaby02f11752006-12-08 02:39:28 -08002444 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2445 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
Jiri Slaby02f11752006-12-08 02:39:28 -08002447 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002448 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002449 new_serial.baud_base != info->baud ||
2450 (new_serial.flags & ASYNC_FLAGS &
2451 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002452 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Jiri Slaby02f11752006-12-08 02:39:28 -08002453 return -EPERM;
Alan Cox77451e52008-07-16 21:57:02 +01002454 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002455 (new_serial.flags & ASYNC_USR_MASK);
2456 info->baud = new_serial.baud_base;
2457 info->custom_divisor = new_serial.custom_divisor;
2458 goto check_and_exit;
2459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Jiri Slaby02f11752006-12-08 02:39:28 -08002461 /*
2462 * OK, past this point, all the error checking has been done.
2463 * At this point, we start making changes.....
2464 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Jiri Slaby02f11752006-12-08 02:39:28 -08002466 info->baud = new_serial.baud_base;
2467 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002468 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002469 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002470 info->port.close_delay = new_serial.close_delay * HZ / 100;
2471 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002474 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002475 cy_set_line_char(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002476 return 0;
2477 } else {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002478 return cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002479 }
2480} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482/*
2483 * get_lsr_info - get line status register info
2484 *
2485 * Purpose: Let user call ioctl() to get info when the UART physically
2486 * is emptied. On bus types like RS485, the transmitter must
2487 * release the bus after transmitting. This must be done when
2488 * the transmit shift register is empty, not be done when the
2489 * transmit holding register is empty. This functionality
2490 * allows an RS485 driver to be written in user space.
2491 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002492static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493{
Jiri Slaby875b2062007-05-08 00:36:49 -07002494 struct cyclades_card *card;
2495 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002496 unsigned char status;
2497 unsigned int result;
2498 unsigned long flags;
2499 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
Jiri Slaby02f11752006-12-08 02:39:28 -08002501 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002502 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002503 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002504 chip = channel >> 2;
2505 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002506 index = card->bus_index;
2507 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002509 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002510 status = readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002511 (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002512 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002513 result = (status ? 0 : TIOCSER_TEMT);
2514 } else {
2515 /* Not supported yet */
2516 return -EINVAL;
2517 }
2518 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519}
2520
Jiri Slaby02f11752006-12-08 02:39:28 -08002521static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002523 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002524 struct cyclades_card *card;
2525 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002526 void __iomem *base_addr;
2527 unsigned long flags;
2528 unsigned char status;
2529 unsigned long lstatus;
2530 unsigned int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002532 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002533 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Alan Cox7b130c02008-04-30 00:53:16 -07002535 lock_kernel();
2536
Jiri Slaby02f11752006-12-08 02:39:28 -08002537 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002538 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002539 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002540 chip = channel >> 2;
2541 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002542 index = card->bus_index;
2543 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002545 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002546 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002547 status = readb(base_addr + (CyMSVR1 << index));
2548 status |= readb(base_addr + (CyMSVR2 << index));
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002549 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550
Jiri Slaby02f11752006-12-08 02:39:28 -08002551 if (info->rtsdtr_inv) {
2552 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2553 ((status & CyDTR) ? TIOCM_RTS : 0);
2554 } else {
2555 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2556 ((status & CyDTR) ? TIOCM_DTR : 0);
2557 }
2558 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2559 ((status & CyRI) ? TIOCM_RNG : 0) |
2560 ((status & CyDSR) ? TIOCM_DSR : 0) |
2561 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002563 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002564 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby02f11752006-12-08 02:39:28 -08002565 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2566 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2567 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2568 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2569 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2570 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
2571 } else {
2572 result = 0;
Alan Cox7b130c02008-04-30 00:53:16 -07002573 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002574 return -ENODEV;
2575 }
2576
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 }
Alan Cox7b130c02008-04-30 00:53:16 -07002578 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002579 return result;
2580} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582static int
2583cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08002584 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002586 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002587 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002588 unsigned long flags;
Jiri Slaby4d768202009-09-19 13:13:15 -07002589 int channel, retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002591 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002592 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
Jiri Slaby02f11752006-12-08 02:39:28 -08002594 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002595 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002596 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002597 spin_lock_irqsave(&card->card_lock, flags);
2598 cyy_change_rts_dtr(info, set, clear);
2599 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002600 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002601 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002602 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002603
2604 if (set & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002605 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002606 cy_writel(&ch_ctrl->rs_control,
2607 readl(&ch_ctrl->rs_control) | C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002608 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002609 }
2610 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002611 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002612 cy_writel(&ch_ctrl->rs_control,
2613 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002614 ~C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002615 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002616 }
2617 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002618 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002619 cy_writel(&ch_ctrl->rs_control,
2620 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002621#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002622 printk(KERN_DEBUG "cyc:set_modem_info raising "
2623 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002624#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002625 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002626 }
2627 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002628 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002629 cy_writel(&ch_ctrl->rs_control,
2630 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002631 ~C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002632#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002633 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2634 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002635#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002636 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002637 }
2638 } else {
2639 return -ENODEV;
2640 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002641 spin_lock_irqsave(&card->card_lock, flags);
2642 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002643 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002644 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2645 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002646 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002647 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002649 return 0;
2650} /* cy_tiocmset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
2652/*
2653 * cy_break() --- routine which turns the break handling on or off
2654 */
Alan Cox9e98966c2008-07-22 11:18:03 +01002655static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002657 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002658 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002659 unsigned long flags;
Alan Cox9e98966c2008-07-22 11:18:03 +01002660 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Jiri Slaby02f11752006-12-08 02:39:28 -08002662 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e98966c2008-07-22 11:18:03 +01002663 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002665 card = info->card;
2666
2667 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002668 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002669 /* Let the transmit ISR take care of this (since it
2670 requires stuffing characters into the output stream).
2671 */
2672 if (break_state == -1) {
2673 if (!info->breakon) {
2674 info->breakon = 1;
2675 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002676 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002677 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002678 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002679 }
2680 }
2681 } else {
2682 if (!info->breakoff) {
2683 info->breakoff = 1;
2684 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002685 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002686 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002687 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002688 }
2689 }
2690 }
2691 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002692 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002693 retval = cyz_issue_cmd(card,
2694 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002695 C_CM_SET_BREAK, 0L);
2696 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002697 printk(KERN_ERR "cyc:cy_break (set) retval on "
2698 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002699 }
2700 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002701 retval = cyz_issue_cmd(card,
2702 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002703 C_CM_CLR_BREAK, 0L);
2704 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002705 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2706 "on ttyC%d was %x\n", info->line,
2707 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002708 }
2709 }
2710 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002711 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e98966c2008-07-22 11:18:03 +01002712 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002713} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Alan Cox15ed6cc2008-04-30 00:53:55 -07002715static int get_mon_info(struct cyclades_port *info,
2716 struct cyclades_monitor __user *mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717{
Jiri Slaby02f11752006-12-08 02:39:28 -08002718 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
2719 return -EFAULT;
2720 info->mon.int_count = 0;
2721 info->mon.char_count = 0;
2722 info->mon.char_max = 0;
2723 info->mon.char_last = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002725} /* get_mon_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
Jiri Slaby02f11752006-12-08 02:39:28 -08002727static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728{
Jiri Slaby875b2062007-05-08 00:36:49 -07002729 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002730 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002731 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002732 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002735 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002736 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002737 chip = channel >> 2;
2738 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002739 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002740 base_addr =
Jiri Slaby875b2062007-05-08 00:36:49 -07002741 card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Jiri Slaby02f11752006-12-08 02:39:28 -08002743 info->cor3 &= ~CyREC_FIFO;
2744 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002746 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002747 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2748 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002749 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002752} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Alan Cox15ed6cc2008-04-30 00:53:55 -07002754static int get_threshold(struct cyclades_port *info,
2755 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756{
Jiri Slaby875b2062007-05-08 00:36:49 -07002757 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002758 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002759 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002760 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
Jiri Slaby02f11752006-12-08 02:39:28 -08002762 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002763 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002764 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002765 chip = channel >> 2;
2766 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002767 index = card->bus_index;
2768 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002769
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002770 tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002771 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002772 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002773 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002774} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
Alan Cox15ed6cc2008-04-30 00:53:55 -07002776static int set_default_threshold(struct cyclades_port *info,
2777 unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778{
Jiri Slaby02f11752006-12-08 02:39:28 -08002779 info->default_threshold = value & 0x0f;
2780 return 0;
2781} /* set_default_threshold */
2782
Alan Cox15ed6cc2008-04-30 00:53:55 -07002783static int get_default_threshold(struct cyclades_port *info,
2784 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002785{
2786 return put_user(info->default_threshold, value);
2787} /* get_default_threshold */
2788
2789static int set_timeout(struct cyclades_port *info, unsigned long value)
2790{
Jiri Slaby875b2062007-05-08 00:36:49 -07002791 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002792 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002793 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002794 unsigned long flags;
2795
2796 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002797 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002798 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002799 chip = channel >> 2;
2800 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002801 index = card->bus_index;
2802 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002803
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002804 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002805 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002806 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002807 }
2808 return 0;
2809} /* set_timeout */
2810
Alan Cox15ed6cc2008-04-30 00:53:55 -07002811static int get_timeout(struct cyclades_port *info,
2812 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002813{
Jiri Slaby875b2062007-05-08 00:36:49 -07002814 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002815 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002816 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002817 unsigned long tmp;
2818
2819 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002820 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002821 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002822 chip = channel >> 2;
2823 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002824 index = card->bus_index;
2825 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002826
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002827 tmp = readb(base_addr + (CyRTPR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08002828 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002829 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002830 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002831} /* get_timeout */
2832
2833static int set_default_timeout(struct cyclades_port *info, unsigned long value)
2834{
2835 info->default_timeout = value & 0xff;
2836 return 0;
2837} /* set_default_timeout */
2838
Alan Cox15ed6cc2008-04-30 00:53:55 -07002839static int get_default_timeout(struct cyclades_port *info,
2840 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002841{
2842 return put_user(info->default_timeout, value);
2843} /* get_default_timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
2845/*
2846 * This routine allows the tty driver to implement device-
2847 * specific ioctl's. If the ioctl number passed in cmd is
2848 * not recognized by the driver, it should return ENOIOCTLCMD.
2849 */
2850static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002851cy_ioctl(struct tty_struct *tty, struct file *file,
2852 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002854 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002855 struct cyclades_icount cprev, cnow; /* kernel counter temps */
2856 struct serial_icounter_struct __user *p_cuser; /* user space */
2857 int ret_val = 0;
2858 unsigned long flags;
2859 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
Jiri Slaby02f11752006-12-08 02:39:28 -08002861 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2862 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
2864#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002865 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2866 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867#endif
Alan Cox7b130c02008-04-30 00:53:16 -07002868 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
Jiri Slaby02f11752006-12-08 02:39:28 -08002870 switch (cmd) {
2871 case CYGETMON:
2872 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002874 case CYGETTHRESH:
2875 ret_val = get_threshold(info, argp);
2876 break;
2877 case CYSETTHRESH:
2878 ret_val = set_threshold(info, arg);
2879 break;
2880 case CYGETDEFTHRESH:
2881 ret_val = get_default_threshold(info, argp);
2882 break;
2883 case CYSETDEFTHRESH:
2884 ret_val = set_default_threshold(info, arg);
2885 break;
2886 case CYGETTIMEOUT:
2887 ret_val = get_timeout(info, argp);
2888 break;
2889 case CYSETTIMEOUT:
2890 ret_val = set_timeout(info, arg);
2891 break;
2892 case CYGETDEFTIMEOUT:
2893 ret_val = get_default_timeout(info, argp);
2894 break;
2895 case CYSETDEFTIMEOUT:
2896 ret_val = set_default_timeout(info, arg);
2897 break;
2898 case CYSETRFLOW:
2899 info->rflow = (int)arg;
2900 ret_val = 0;
2901 break;
2902 case CYGETRFLOW:
2903 ret_val = info->rflow;
2904 break;
2905 case CYSETRTSDTR_INV:
2906 info->rtsdtr_inv = (int)arg;
2907 ret_val = 0;
2908 break;
2909 case CYGETRTSDTR_INV:
2910 ret_val = info->rtsdtr_inv;
2911 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002913 ret_val = info->chip_rev;
2914 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915#ifndef CONFIG_CYZ_INTR
2916 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002917 cyz_polling_cycle = (arg * HZ) / 1000;
2918 ret_val = 0;
2919 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002921 ret_val = (cyz_polling_cycle * 1000) / HZ;
2922 break;
2923#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002925 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002926 ret_val = 0;
2927 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002929 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002930 break;
2931 case TIOCGSERIAL:
2932 ret_val = get_serial_info(info, argp);
2933 break;
2934 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002935 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002936 break;
2937 case TIOCSERGETLSR: /* Get line status register */
2938 ret_val = get_lsr_info(info, argp);
2939 break;
2940 /*
2941 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2942 * - mask passed in arg for lines of interest
2943 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2944 * Caller should use TIOCGICOUNT to see which one it was
2945 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002947 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002948 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002949 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002950 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002951 ret_val = wait_event_interruptible(info->delta_msr_wait, ({
2952 cprev = cnow;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002953 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002954 cnow = info->icount; /* atomic copy */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002955 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002957 ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2958 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2959 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2960 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
2961 }));
2962 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002963
2964 /*
2965 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2966 * Return: write counters to the user passed counter struct
2967 * NB: both 1->0 and 0->1 transitions are counted except for
2968 * RI where only 0->1 is counted.
2969 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 case TIOCGICOUNT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002971 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002972 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002973 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002974 p_cuser = argp;
2975 ret_val = put_user(cnow.cts, &p_cuser->cts);
2976 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002977 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002978 ret_val = put_user(cnow.dsr, &p_cuser->dsr);
2979 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002980 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002981 ret_val = put_user(cnow.rng, &p_cuser->rng);
2982 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002983 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002984 ret_val = put_user(cnow.dcd, &p_cuser->dcd);
2985 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002986 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002987 ret_val = put_user(cnow.rx, &p_cuser->rx);
2988 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002989 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002990 ret_val = put_user(cnow.tx, &p_cuser->tx);
2991 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002992 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002993 ret_val = put_user(cnow.frame, &p_cuser->frame);
2994 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002995 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002996 ret_val = put_user(cnow.overrun, &p_cuser->overrun);
2997 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002998 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002999 ret_val = put_user(cnow.parity, &p_cuser->parity);
3000 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003001 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003002 ret_val = put_user(cnow.brk, &p_cuser->brk);
3003 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003004 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003005 ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
3006 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003007 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003008 ret_val = 0;
3009 break;
3010 default:
3011 ret_val = -ENOIOCTLCMD;
3012 }
Alan Cox7b130c02008-04-30 00:53:16 -07003013 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
3015#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003016 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003018 return ret_val;
3019} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
3021/*
3022 * This routine allows the tty driver to be notified when
3023 * device's termios settings have changed. Note that a
3024 * well-designed tty driver should be prepared to accept the case
3025 * where old == NULL, and try to do something rational.
3026 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003027static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003029 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003032 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033#endif
3034
Jiri Slabyd13549f2009-09-19 13:13:12 -07003035 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Jiri Slaby02f11752006-12-08 02:39:28 -08003037 if ((old_termios->c_cflag & CRTSCTS) &&
3038 !(tty->termios->c_cflag & CRTSCTS)) {
3039 tty->hw_stopped = 0;
3040 cy_start(tty);
3041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08003043 /*
3044 * No need to wake up processes in open wait, since they
3045 * sample the CLOCAL flag once, and don't recheck it.
3046 * XXX It's not clear whether the current behavior is correct
3047 * or not. Hence, this may change.....
3048 */
3049 if (!(old_termios->c_cflag & CLOCAL) &&
3050 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01003051 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003053} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054
3055/* This function is used to send a high-priority XON/XOFF character to
3056 the device.
3057*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003058static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003060 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003061 struct cyclades_card *card;
3062 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
Jiri Slaby02f11752006-12-08 02:39:28 -08003064 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 return;
3066
Jiri Slaby02f11752006-12-08 02:39:28 -08003067 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
3069 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08003070 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071
3072 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003073 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074
Jiri Slaby2693f482009-06-11 12:31:06 +01003075 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003076 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003077 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003078 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003079 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 }
3081}
3082
3083/* This routine is called by the upper-layer tty layer to signal
3084 that incoming characters should be throttled because the input
3085 buffers are close to full.
3086 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003087static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003089 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003090 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003091 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
3093#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003094 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Jiri Slaby21719192007-05-08 00:36:42 -07003096 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08003097 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098#endif
3099
Alan Cox15ed6cc2008-04-30 00:53:55 -07003100 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003101 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102
Jiri Slaby02f11752006-12-08 02:39:28 -08003103 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104
Jiri Slaby02f11752006-12-08 02:39:28 -08003105 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003106 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08003107 cy_send_xchar(tty, STOP_CHAR(tty));
3108 else
3109 info->throttle = 1;
3110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
Jiri Slaby02f11752006-12-08 02:39:28 -08003112 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003113 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003114 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003115 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003116 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003117 } else {
3118 info->throttle = 1;
3119 }
3120 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003121} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
3123/*
3124 * This routine notifies the tty driver that it should signal
3125 * that characters can now be sent to the tty without fear of
3126 * overrunning the input buffers of the line disciplines.
3127 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003128static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003130 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003131 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003132 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003135 char buf[64];
3136
Jiri Slaby21719192007-05-08 00:36:42 -07003137 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07003138 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139#endif
3140
Alan Cox15ed6cc2008-04-30 00:53:55 -07003141 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003142 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
Jiri Slaby02f11752006-12-08 02:39:28 -08003144 if (I_IXOFF(tty)) {
3145 if (info->x_char)
3146 info->x_char = 0;
3147 else
3148 cy_send_xchar(tty, START_CHAR(tty));
3149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150
Jiri Slaby02f11752006-12-08 02:39:28 -08003151 if (tty->termios->c_cflag & CRTSCTS) {
3152 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01003153 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003154 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003155 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003156 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003157 } else {
3158 info->throttle = 0;
3159 }
3160 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003161} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163/* cy_start and cy_stop provide software output flow control as a
3164 function of XON/XOFF, software CTS, and other such stuff.
3165*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003166static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167{
Jiri Slaby02f11752006-12-08 02:39:28 -08003168 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003169 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003170 void __iomem *base_addr;
3171 int chip, channel, index;
3172 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173
3174#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003175 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176#endif
3177
Jiri Slaby02f11752006-12-08 02:39:28 -08003178 if (serial_paranoia_check(info, tty->name, "cy_stop"))
3179 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
Jiri Slaby875b2062007-05-08 00:36:49 -07003181 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003182 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003183 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003184 index = cinfo->bus_index;
3185 chip = channel >> 2;
3186 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003187 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003189 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003190 cy_writeb(base_addr + (CyCAR << index),
3191 (u_char)(channel & 0x0003)); /* index channel */
3192 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003193 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003194 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003196} /* cy_stop */
3197
3198static void cy_start(struct tty_struct *tty)
3199{
3200 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003201 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003202 void __iomem *base_addr;
3203 int chip, channel, index;
3204 unsigned long flags;
3205
3206#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003207 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08003208#endif
3209
3210 if (serial_paranoia_check(info, tty->name, "cy_start"))
3211 return;
3212
Jiri Slaby875b2062007-05-08 00:36:49 -07003213 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003214 channel = info->line - cinfo->first_line;
3215 index = cinfo->bus_index;
Jiri Slaby2693f482009-06-11 12:31:06 +01003216 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003217 chip = channel >> 2;
3218 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003219 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003220
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003221 spin_lock_irqsave(&cinfo->card_lock, flags);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003222 cy_writeb(base_addr + (CyCAR << index),
3223 (u_char) (channel & 0x0003)); /* index channel */
Jiri Slaby02f11752006-12-08 02:39:28 -08003224 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003225 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003226 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003227 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003228} /* cy_start */
3229
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230/*
3231 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3232 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003233static void cy_hangup(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 Slaby02f11752006-12-08 02:39:28 -08003236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003238 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239#endif
3240
Jiri Slaby02f11752006-12-08 02:39:28 -08003241 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3242 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
Jiri Slaby02f11752006-12-08 02:39:28 -08003244 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003245 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003246 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003247} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
Jiri Slabyf0737572009-09-19 13:13:12 -07003249static int cyy_carrier_raised(struct tty_port *port)
3250{
3251 struct cyclades_port *info = container_of(port, struct cyclades_port,
3252 port);
3253 struct cyclades_card *cinfo = info->card;
3254 void __iomem *base = cinfo->base_addr;
3255 unsigned long flags;
3256 int channel = info->line - cinfo->first_line;
3257 int chip = channel >> 2, index = cinfo->bus_index;
3258 u32 cd;
3259
3260 channel &= 0x03;
3261 base += cy_chip_offset[chip] << index;
3262
3263 spin_lock_irqsave(&cinfo->card_lock, flags);
3264 cy_writeb(base + (CyCAR << index), (u8)channel);
3265 cd = readb(base + (CyMSVR1 << index)) & CyDCD;
3266 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3267
3268 return cd;
3269}
3270
3271static void cyy_dtr_rts(struct tty_port *port, int raise)
3272{
3273 struct cyclades_port *info = container_of(port, struct cyclades_port,
3274 port);
3275 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003276 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003277
3278 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003279 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3280 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003281 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3282}
3283
3284static int cyz_carrier_raised(struct tty_port *port)
3285{
3286 struct cyclades_port *info = container_of(port, struct cyclades_port,
3287 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003288
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003289 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003290}
3291
3292static void cyz_dtr_rts(struct tty_port *port, int raise)
3293{
3294 struct cyclades_port *info = container_of(port, struct cyclades_port,
3295 port);
3296 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003297 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003298 int ret, channel = info->line - cinfo->first_line;
3299 u32 rs;
3300
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003301 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003302 if (raise)
3303 rs |= C_RS_RTS | C_RS_DTR;
3304 else
3305 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003306 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003307 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3308 if (ret != 0)
3309 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3310 __func__, info->line, ret);
3311#ifdef CY_DEBUG_DTR
3312 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3313#endif
3314}
3315
3316static const struct tty_port_operations cyy_port_ops = {
3317 .carrier_raised = cyy_carrier_raised,
3318 .dtr_rts = cyy_dtr_rts,
3319};
3320
3321static const struct tty_port_operations cyz_port_ops = {
3322 .carrier_raised = cyz_carrier_raised,
3323 .dtr_rts = cyz_dtr_rts,
3324};
3325
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326/*
3327 * ---------------------------------------------------------------------
3328 * cy_init() and friends
3329 *
3330 * cy_init() is called at boot-time to initialize the serial driver.
3331 * ---------------------------------------------------------------------
3332 */
3333
Jiri Slabydd025c02007-05-08 00:37:02 -07003334static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003335{
3336 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003337 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003338
Jiri Slaby3046d502007-05-08 00:36:46 -07003339 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003340 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003341
Jiri Slaby963118e2009-06-11 12:34:27 +01003342 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3343 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003344 if (cinfo->ports == NULL) {
3345 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3346 return -ENOMEM;
3347 }
3348
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003349 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3350 channel++, port++) {
3351 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003352 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003353 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003354 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003355 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003356
Alan Cox44b7d1b2008-07-16 21:57:18 +01003357 info->port.closing_wait = CLOSING_WAIT_DELAY;
3358 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003359 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003360 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003361 init_waitqueue_head(&info->delta_msr_wait);
3362
Jiri Slaby2693f482009-06-11 12:31:06 +01003363 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003364 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3365 struct ZFW_CTRL *zfw_ctrl;
3366
Jiri Slabyf0737572009-09-19 13:13:12 -07003367 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003368 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003369
3370 zfw_ctrl = cinfo->base_addr +
3371 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3372 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3373 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3374
Jiri Slaby101b8152009-06-11 12:30:10 +01003375 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003376 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3377 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003378 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003379#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003380 setup_timer(&cyz_rx_full_timer[port],
3381 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003382#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003383 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003384 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003385 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003386
Jiri Slabyf0737572009-09-19 13:13:12 -07003387 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003388 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003389 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003390 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003391 info->cor2 = CyETC;
3392 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003393
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003394 chip_number = channel / CyPORTS_PER_CHIP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07003395 info->chip_rev = readb(cinfo->base_addr +
3396 (cy_chip_offset[chip_number] << index) +
3397 (CyGFRCR << index));
3398
3399 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003400 /* It is a CD1400 rev. J or later */
3401 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3402 info->tco = baud_co_60[13]; /* Tx CO */
3403 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3404 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003405 info->rtsdtr_inv = 1;
3406 } else {
3407 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3408 info->tco = baud_co_25[13]; /* Tx CO */
3409 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3410 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003411 info->rtsdtr_inv = 0;
3412 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003413 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3414 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003415 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003416
Jiri Slaby0809e262007-05-08 00:36:14 -07003417 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003418
3419#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003420 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003421 mod_timer(&cyz_timerlist, jiffies + 1);
3422#ifdef CY_PCI_DEBUG
3423 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3424#endif
3425 }
3426#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003427 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003428}
3429
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430/* initialize chips on Cyclom-Y card -- return number of valid
3431 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003432static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3433 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434{
Jiri Slaby02f11752006-12-08 02:39:28 -08003435 unsigned int chip_number;
3436 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437
Jiri Slaby02f11752006-12-08 02:39:28 -08003438 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3439 /* Cy_HwReset is 0x1400 */
3440 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3441 /* Cy_ClrIntr is 0x1800 */
3442 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Alan Cox15ed6cc2008-04-30 00:53:55 -07003444 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3445 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003446 base_addr =
3447 true_base_addr + (cy_chip_offset[chip_number] << index);
3448 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003449 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003450 /*************
3451 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3452 chip_number, (unsigned long)base_addr);
3453 *************/
3454 return chip_number;
3455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
Jiri Slaby02f11752006-12-08 02:39:28 -08003457 cy_writeb(base_addr + (CyGFRCR << index), 0);
3458 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459
Jiri Slaby02f11752006-12-08 02:39:28 -08003460 /* The Cyclom-16Y does not decode address bit 9 and therefore
3461 cannot distinguish between references to chip 0 and a non-
3462 existent chip 4. If the preceding clearing of the supposed
3463 chip 4 GFRCR register appears at chip 0, there is no chip 4
3464 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3465 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003466 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003467 (cy_chip_offset[0] << index) +
3468 (CyGFRCR << index)) == 0) {
3469 return chip_number;
3470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
Jiri Slaby02f11752006-12-08 02:39:28 -08003472 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3473 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003475 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003476 /*
3477 printk(" chip #%d at %#6lx is not responding ",
3478 chip_number, (unsigned long)base_addr);
3479 printk("(GFRCR stayed 0)\n",
3480 */
3481 return chip_number;
3482 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003483 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003484 0x40) {
3485 /*
3486 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3487 "%#2x)\n",
3488 chip_number, (unsigned long)base_addr,
3489 base_addr[CyGFRCR<<index]);
3490 */
3491 return chip_number;
3492 }
3493 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003494 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003495 /* It is a CD1400 rev. J or later */
3496 /* Impossible to reach 5ms with this chip.
3497 Changed to 2ms instead (f = 500 Hz). */
3498 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3499 } else {
3500 /* f = 200 Hz */
3501 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3502 }
3503
3504 /*
3505 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3506 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003507 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003508 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003510 return chip_number;
3511} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
3513/*
3514 * ---------------------------------------------------------------------
3515 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3516 * sets global variables and return the number of ISA boards found.
3517 * ---------------------------------------------------------------------
3518 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003519static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520{
3521#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003522 unsigned short cy_isa_irq, nboard;
3523 void __iomem *cy_isa_address;
3524 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08003526 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527#endif
3528
Jiri Slaby02f11752006-12-08 02:39:28 -08003529 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
3531#ifdef MODULE
3532 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003533 for (i = 0; i < NR_CARDS; i++) {
3534 if (maddr[i] || i) {
3535 isparam = 1;
3536 cy_isa_addresses[i] = maddr[i];
3537 }
3538 if (!maddr[i])
3539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 }
3541#endif
3542
Jiri Slaby02f11752006-12-08 02:39:28 -08003543 /* scan the address table probing for Cyclom-Y/ISA boards */
3544 for (i = 0; i < NR_ISA_ADDRS; i++) {
3545 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003546 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003547 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
Jiri Slaby02f11752006-12-08 02:39:28 -08003549 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003550 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003551 if (cy_isa_address == NULL) {
3552 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3553 "address\n");
3554 continue;
3555 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003556 cy_isa_nchan = CyPORTS_PER_CHIP *
3557 cyy_init_card(cy_isa_address, 0);
3558 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003559 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003560 continue;
3561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562#ifdef MODULE
3563 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003564 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 else
3566#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003567 /* find out the board's irq by probing */
3568 cy_isa_irq = detect_isa_irq(cy_isa_address);
3569 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003570 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3571 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003572 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003573 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003574 continue;
3575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
Jiri Slaby02f11752006-12-08 02:39:28 -08003577 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003578 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3579 "more channels are available. Change NR_PORTS "
3580 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003581 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003582 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003583 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003584 }
3585 /* fill the next cy_card structure available */
3586 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003587 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003588 break;
3589 }
3590 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003591 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3592 "more cards can be used. Change NR_CARDS in "
3593 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003594 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003595 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003596 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
Jiri Slaby02f11752006-12-08 02:39:28 -08003599 /* allocate IRQ */
3600 if (request_irq(cy_isa_irq, cyy_interrupt,
3601 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003602 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3603 "could not allocate IRQ#%d.\n",
3604 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003605 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003606 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Jiri Slaby02f11752006-12-08 02:39:28 -08003609 /* set cy_card */
3610 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003611 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003612 cy_card[j].irq = (int)cy_isa_irq;
3613 cy_card[j].bus_index = 0;
3614 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003615 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3616 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003617 if (cy_init_card(&cy_card[j])) {
3618 cy_card[j].base_addr = NULL;
3619 free_irq(cy_isa_irq, &cy_card[j]);
3620 iounmap(cy_isa_address);
3621 continue;
3622 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003623 nboard++;
3624
Jiri Slaby21719192007-05-08 00:36:42 -07003625 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3626 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003627 j + 1, (unsigned long)cy_isa_address,
3628 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003629 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3630
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003631 for (j = cy_next_channel;
3632 j < cy_next_channel + cy_isa_nchan; j++)
3633 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003634 cy_next_channel += cy_isa_nchan;
3635 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003636 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003638 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003639#endif /* CONFIG_ISA */
3640} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
Jiri Slaby58936d82007-05-08 00:36:13 -07003642#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003643static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3644{
3645 unsigned int a;
3646
3647 for (a = 0; a < size && *str; a++, str++)
3648 if (*str & 0x80)
3649 return -EINVAL;
3650
3651 for (; a < size; a++, str++)
3652 if (*str)
3653 return -EINVAL;
3654
3655 return 0;
3656}
3657
David Woodhousef61e7612008-05-23 23:57:19 +01003658static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003659 unsigned int size)
3660{
3661 for (; size > 0; size--) {
3662 cy_writel(fpga, *data++);
3663 udelay(10);
3664 }
3665}
3666
3667static void __devinit plx_init(struct pci_dev *pdev, int irq,
3668 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669{
Jiri Slaby02f11752006-12-08 02:39:28 -08003670 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003671 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003672 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003673 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674
Jiri Slaby02f11752006-12-08 02:39:28 -08003675 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003676 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003677 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003678 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3679
3680 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3681 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3682 * registers. This will remain here until we find a permanent fix.
3683 */
3684 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3685}
3686
3687static int __devinit __cyz_load_fw(const struct firmware *fw,
3688 const char *name, const u32 mailbox, void __iomem *base,
3689 void __iomem *fpga)
3690{
David Woodhousef61e7612008-05-23 23:57:19 +01003691 const void *ptr = fw->data;
3692 const struct zfile_header *h = ptr;
3693 const struct zfile_config *c, *cs;
3694 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003695 unsigned int a, tmp, len = fw->size;
3696#define BAD_FW KERN_ERR "Bad firmware: "
3697 if (len < sizeof(*h)) {
3698 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3699 return -EINVAL;
3700 }
3701
3702 cs = ptr + h->config_offset;
3703 bs = ptr + h->block_offset;
3704
3705 if ((void *)(cs + h->n_config) > ptr + len ||
3706 (void *)(bs + h->n_blocks) > ptr + len) {
3707 printk(BAD_FW "too short");
3708 return -EINVAL;
3709 }
3710
3711 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3712 cyc_isfwstr(h->date, sizeof(h->date))) {
3713 printk(BAD_FW "bad formatted header string\n");
3714 return -EINVAL;
3715 }
3716
3717 if (strncmp(name, h->name, sizeof(h->name))) {
3718 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3719 return -EINVAL;
3720 }
3721
3722 tmp = 0;
3723 for (c = cs; c < cs + h->n_config; c++) {
3724 for (a = 0; a < c->n_blocks; a++)
3725 if (c->block_list[a] > h->n_blocks) {
3726 printk(BAD_FW "bad block ref number in cfgs\n");
3727 return -EINVAL;
3728 }
3729 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3730 tmp++;
3731 }
3732 if (!tmp) {
3733 printk(BAD_FW "nothing appropriate\n");
3734 return -EINVAL;
3735 }
3736
3737 for (b = bs; b < bs + h->n_blocks; b++)
3738 if (b->file_offset + b->size > len) {
3739 printk(BAD_FW "bad block data offset\n");
3740 return -EINVAL;
3741 }
3742
3743 /* everything is OK, let's seek'n'load it */
3744 for (c = cs; c < cs + h->n_config; c++)
3745 if (c->mailbox == mailbox && c->function == 0)
3746 break;
3747
3748 for (a = 0; a < c->n_blocks; a++) {
3749 b = &bs[c->block_list[a]];
3750 if (b->type == ZBLOCK_FPGA) {
3751 if (fpga != NULL)
3752 cyz_fpga_copy(fpga, ptr + b->file_offset,
3753 b->size);
3754 } else {
3755 if (base != NULL)
3756 memcpy_toio(base + b->ram_offset,
3757 ptr + b->file_offset, b->size);
3758 }
3759 }
3760#undef BAD_FW
3761 return 0;
3762}
3763
3764static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3765 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3766{
3767 const struct firmware *fw;
3768 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3769 struct CUSTOM_REG __iomem *cust = base_addr;
3770 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003771 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003772 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003773 unsigned int i;
3774 int retval;
3775
3776 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3777 if (retval) {
3778 dev_err(&pdev->dev, "can't get firmware\n");
3779 goto err;
3780 }
3781
3782 /* Check whether the firmware is already loaded and running. If
3783 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003784 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003785 u32 cntval = readl(base_addr + 0x190);
3786
3787 udelay(100);
3788 if (cntval != readl(base_addr + 0x190)) {
3789 /* FW counter is working, FW is running */
3790 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3791 "Skipping board.\n");
3792 retval = 0;
3793 goto err_rel;
3794 }
3795 }
3796
3797 /* start boot */
3798 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3799 ~0x00030800UL);
3800
3801 mailbox = readl(&ctl_addr->mail_box_0);
3802
Jiri Slaby2693f482009-06-11 12:31:06 +01003803 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003804 /* stops CPU and set window to beginning of RAM */
3805 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3806 cy_writel(&cust->cpu_stop, 0);
3807 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3808 udelay(100);
3809 }
3810
3811 plx_init(pdev, irq, ctl_addr);
3812
3813 if (mailbox != 0) {
3814 /* load FPGA */
3815 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3816 base_addr);
3817 if (retval)
3818 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003819 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003820 dev_err(&pdev->dev, "fw upload successful, but fw is "
3821 "not loaded\n");
3822 goto err_rel;
3823 }
3824 }
3825
3826 /* stops CPU and set window to beginning of RAM */
3827 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3828 cy_writel(&cust->cpu_stop, 0);
3829 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3830 udelay(100);
3831
3832 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003833 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003834 cy_writeb(tmp, 255);
3835 if (mailbox != 0) {
3836 /* set window to last 512K of RAM */
3837 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003838 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003839 cy_writeb(tmp, 255);
3840 /* set window to beginning of RAM */
3841 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003842 }
3843
3844 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3845 release_firmware(fw);
3846 if (retval)
3847 goto err;
3848
3849 /* finish boot and start boards */
3850 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3851 cy_writel(&cust->cpu_start, 0);
3852 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3853 i = 0;
3854 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3855 msleep(100);
3856 if (status != ZFIRM_ID) {
3857 if (status == ZFIRM_HLT) {
3858 dev_err(&pdev->dev, "you need an external power supply "
3859 "for this number of ports. Firmware halted and "
3860 "board reset.\n");
3861 retval = -EIO;
3862 goto err;
3863 }
3864 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3865 "some more time\n", status);
3866 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3867 i++ < 200)
3868 msleep(100);
3869 if (status != ZFIRM_ID) {
3870 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3871 "Giving up. (fid->signature = 0x%x)\n",
3872 status);
3873 dev_info(&pdev->dev, "*** Warning ***: if you are "
3874 "upgrading the FW, please power cycle the "
3875 "system before loading the new FW to the "
3876 "Cyclades-Z.\n");
3877
Jiri Slaby2693f482009-06-11 12:31:06 +01003878 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003879 plx_init(pdev, irq, ctl_addr);
3880
3881 retval = -EIO;
3882 goto err;
3883 }
3884 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3885 i / 10);
3886 }
3887 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3888
3889 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3890 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3891 base_addr + readl(&fid->zfwctrl_addr));
3892
Jiri Slaby963118e2009-06-11 12:34:27 +01003893 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003894 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003895 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003896
Jiri Slaby963118e2009-06-11 12:34:27 +01003897 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003898 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3899 "check the connection between the Z host card and the "
3900 "serial expanders.\n");
3901
Jiri Slaby2693f482009-06-11 12:31:06 +01003902 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003903 plx_init(pdev, irq, ctl_addr);
3904
3905 dev_info(&pdev->dev, "Null number of ports detected. Board "
3906 "reset.\n");
3907 retval = 0;
3908 goto err;
3909 }
3910
3911 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3912 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3913
3914 /*
3915 Early firmware failed to start looking for commands.
3916 This enables firmware interrupts for those commands.
3917 */
3918 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3919 (1 << 17));
3920 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3921 0x00030800UL);
3922
Jiri Slaby963118e2009-06-11 12:34:27 +01003923 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003924err_rel:
3925 release_firmware(fw);
3926err:
3927 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928}
3929
Jiri Slaby58936d82007-05-08 00:36:13 -07003930static int __devinit cy_pci_probe(struct pci_dev *pdev,
3931 const struct pci_device_id *ent)
3932{
Jiri Slaby31375532007-05-08 00:37:04 -07003933 void __iomem *addr0 = NULL, *addr2 = NULL;
3934 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003935 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003936 unsigned int device_id, nchan = 0, card_no, i;
3937 unsigned char plx_ver;
3938 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003939
3940 retval = pci_enable_device(pdev);
3941 if (retval) {
3942 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003943 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003944 }
3945
3946 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003947 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003948 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3949
Jiri Slaby31375532007-05-08 00:37:04 -07003950#if defined(__alpha__)
3951 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3952 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3953 "addresses on Alpha systems.\n");
3954 retval = -EIO;
3955 goto err_dis;
3956 }
3957#endif
3958 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3959 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3960 "addresses\n");
3961 retval = -EIO;
3962 goto err_dis;
3963 }
3964
3965 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3966 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3967 "it...\n");
3968 pdev->resource[2].flags &= ~IORESOURCE_IO;
3969 }
3970
3971 retval = pci_request_regions(pdev, "cyclades");
3972 if (retval) {
3973 dev_err(&pdev->dev, "failed to reserve resources\n");
3974 goto err_dis;
3975 }
3976
3977 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003978 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3979 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003980 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003981
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003982 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3983 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003984 if (addr0 == NULL) {
3985 dev_err(&pdev->dev, "can't remap ctl region\n");
3986 goto err_reg;
3987 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003988 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3989 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003990 if (addr2 == NULL) {
3991 dev_err(&pdev->dev, "can't remap base region\n");
3992 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003993 }
3994
Jiri Slaby31375532007-05-08 00:37:04 -07003995 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3996 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003997 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3998 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003999 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004000 }
Jiri Slaby31375532007-05-08 00:37:04 -07004001 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
4002 struct RUNTIME_9060 __iomem *ctl_addr;
4003
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004004 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
4005 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07004006 if (addr0 == NULL) {
4007 dev_err(&pdev->dev, "can't remap ctl region\n");
4008 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07004009 }
4010
Jiri Slaby31375532007-05-08 00:37:04 -07004011 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004012 cy_writew(&ctl_addr->intr_ctrl_stat,
4013 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07004014
Jiri Slaby054f5b02007-07-17 04:05:16 -07004015 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004016
Jiri Slaby101b8152009-06-11 12:30:10 +01004017 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07004018
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004019 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
4020 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07004021 if (addr2 == NULL) {
4022 dev_err(&pdev->dev, "can't remap base region\n");
4023 goto err_unmap;
4024 }
4025
4026 if (mailbox == ZE_V1) {
4027 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07004028 } else {
4029 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07004030#ifdef CY_PCI_DEBUG
4031 if (mailbox == ZO_V1) {
4032 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
4033 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
4034 "id %lx, ver %lx\n", (ulong)(0xff &
4035 readl(&((struct CUSTOM_REG *)addr2)->
4036 fpga_id)), (ulong)(0xff &
4037 readl(&((struct CUSTOM_REG *)addr2)->
4038 fpga_version)));
4039 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4040 } else {
4041 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
4042 "Cyclades-Z board. FPGA not loaded\n");
4043 }
4044#endif
4045 /* The following clears the firmware id word. This
4046 ensures that the driver will not attempt to talk to
4047 the board until it has been properly initialized.
4048 */
4049 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
4050 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07004051 }
Jiri Slabyace08c32009-06-11 12:20:38 +01004052
4053 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01004054 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01004055 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01004056 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07004057 }
4058
4059 if ((cy_next_channel + nchan) > NR_PORTS) {
4060 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4061 "channels are available. Change NR_PORTS in "
4062 "cyclades.c and recompile kernel.\n");
4063 goto err_unmap;
4064 }
4065 /* fill the next cy_card structure available */
4066 for (card_no = 0; card_no < NR_CARDS; card_no++) {
4067 if (cy_card[card_no].base_addr == NULL)
4068 break;
4069 }
4070 if (card_no == NR_CARDS) { /* no more cy_cards available */
4071 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4072 "more cards can be used. Change NR_CARDS in "
4073 "cyclades.c and recompile kernel.\n");
4074 goto err_unmap;
4075 }
4076
4077 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4078 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004079 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07004080 retval = request_irq(irq, cyy_interrupt,
4081 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07004082 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07004083 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004084 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004085 }
Jiri Slaby963118e2009-06-11 12:34:27 +01004086 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07004087 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004088 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
4089 struct ZFW_CTRL __iomem *zfw_ctrl;
4090
4091 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4092
Jiri Slaby101b8152009-06-11 12:30:10 +01004093 cy_card[card_no].hw_ver = mailbox;
4094 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004095 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07004096#ifdef CONFIG_CYZ_INTR
4097 /* allocate IRQ only if board has an IRQ */
4098 if (irq != 0 && irq != 255) {
4099 retval = request_irq(irq, cyz_interrupt,
4100 IRQF_SHARED, "Cyclades-Z",
4101 &cy_card[card_no]);
4102 if (retval) {
4103 dev_err(&pdev->dev, "could not allocate IRQ\n");
4104 goto err_unmap;
4105 }
4106 }
4107#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07004108 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004109
Jiri Slaby31375532007-05-08 00:37:04 -07004110 /* set cy_card */
4111 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01004112 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07004113 cy_card[card_no].irq = irq;
4114 cy_card[card_no].bus_index = 1;
4115 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01004116 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07004117 retval = cy_init_card(&cy_card[card_no]);
4118 if (retval)
4119 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07004120
Jiri Slaby31375532007-05-08 00:37:04 -07004121 pci_set_drvdata(pdev, &cy_card[card_no]);
4122
4123 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4124 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004125 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07004126 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07004127 switch (plx_ver) {
4128 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07004129 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07004130 break;
4131
4132 case PLX_9060:
4133 case PLX_9080:
4134 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004135 {
4136 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
4137 plx_init(pdev, irq, ctl_addr);
4138 cy_writew(&ctl_addr->intr_ctrl_stat,
4139 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07004140 break;
4141 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01004142 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004143 }
4144
Jiri Slaby31375532007-05-08 00:37:04 -07004145 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
4146 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
4147 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
4148 tty_register_device(cy_serial_driver, i, &pdev->dev);
4149 cy_next_channel += nchan;
4150
Jiri Slaby58936d82007-05-08 00:36:13 -07004151 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07004152err_null:
4153 cy_card[card_no].base_addr = NULL;
4154 free_irq(irq, &cy_card[card_no]);
4155err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004156 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004157 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004158 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07004159err_reg:
4160 pci_release_regions(pdev);
4161err_dis:
4162 pci_disable_device(pdev);
4163err:
4164 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07004165}
Jiri Slaby58936d82007-05-08 00:36:13 -07004166
Jiri Slaby6747cd92007-05-08 00:36:34 -07004167static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168{
Jiri Slaby38d09092007-05-08 00:36:10 -07004169 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07004170 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07004171
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004172 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01004173 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07004174 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01004175 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004176 else
4177#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004178 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004179#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01004180 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
4181 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
4182 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004183
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004184 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004185 if (cinfo->ctl_addr.p9050)
4186 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07004187 if (cinfo->irq
4188#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004189 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07004190#endif /* CONFIG_CYZ_INTR */
4191 )
4192 free_irq(cinfo->irq, cinfo);
4193 pci_release_regions(pdev);
4194
4195 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004196 for (i = cinfo->first_line; i < cinfo->first_line +
4197 cinfo->nports; i++)
4198 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07004199 cinfo->nports = 0;
4200 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07004201}
4202
Jiri Slaby6747cd92007-05-08 00:36:34 -07004203static struct pci_driver cy_pci_driver = {
4204 .name = "cyclades",
4205 .id_table = cy_pci_dev_id,
4206 .probe = cy_pci_probe,
4207 .remove = __devexit_p(cy_pci_remove)
4208};
4209#endif
4210
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004211static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212{
Jiri Slaby02f11752006-12-08 02:39:28 -08004213 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07004214 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08004215 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004217 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08004218 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
Jiri Slaby02f11752006-12-08 02:39:28 -08004220 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07004221 for (i = 0; i < NR_CARDS; i++)
4222 for (j = 0; j < cy_card[i].nports; j++) {
4223 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08004224
Jiri Slabyd13549f2009-09-19 13:13:12 -07004225 if (info->port.count) {
4226 /* XXX is the ldisc num worth this? */
4227 struct tty_struct *tty;
4228 struct tty_ldisc *ld;
4229 int num = 0;
4230 tty = tty_port_tty_get(&info->port);
4231 if (tty) {
4232 ld = tty_ldisc_ref(tty);
4233 if (ld) {
4234 num = ld->ops->num;
4235 tty_ldisc_deref(ld);
4236 }
4237 tty_kref_put(tty);
4238 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004239 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004240 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004241 (cur_jifs - info->idle_stats.in_use) /
4242 HZ, info->idle_stats.xmit_bytes,
4243 (cur_jifs - info->idle_stats.xmit_idle)/
4244 HZ, info->idle_stats.recv_bytes,
4245 (cur_jifs - info->idle_stats.recv_idle)/
4246 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004247 num);
4248 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004249 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004250 "%10lu %8lu %9lu %6ld\n",
4251 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004252 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004253 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254}
4255
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004256static int cyclades_proc_open(struct inode *inode, struct file *file)
4257{
4258 return single_open(file, cyclades_proc_show, NULL);
4259}
4260
4261static const struct file_operations cyclades_proc_fops = {
4262 .owner = THIS_MODULE,
4263 .open = cyclades_proc_open,
4264 .read = seq_read,
4265 .llseek = seq_lseek,
4266 .release = single_release,
4267};
4268
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269/* The serial driver boot-time initialization code!
4270 Hardware I/O ports are mapped to character special devices on a
4271 first found, first allocated manner. That is, this code searches
4272 for Cyclom cards in the system. As each is found, it is probed
4273 to discover how many chips (and thus how many ports) are present.
4274 These ports are mapped to the tty ports 32 and upward in monotonic
4275 fashion. If an 8-port card is replaced with a 16-port card, the
4276 port mapping on a following card will shift.
4277
4278 This approach is different from what is used in the other serial
4279 device driver because the Cyclom is more properly a multiplexer,
4280 not just an aggregation of serial ports on one card.
4281
4282 If there are more cards with more ports than have been
4283 statically allocated above, a warning is printed and the
4284 extra ports are ignored.
4285 */
4286
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004287static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004288 .open = cy_open,
4289 .close = cy_close,
4290 .write = cy_write,
4291 .put_char = cy_put_char,
4292 .flush_chars = cy_flush_chars,
4293 .write_room = cy_write_room,
4294 .chars_in_buffer = cy_chars_in_buffer,
4295 .flush_buffer = cy_flush_buffer,
4296 .ioctl = cy_ioctl,
4297 .throttle = cy_throttle,
4298 .unthrottle = cy_unthrottle,
4299 .set_termios = cy_set_termios,
4300 .stop = cy_stop,
4301 .start = cy_start,
4302 .hangup = cy_hangup,
4303 .break_ctl = cy_break,
4304 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004305 .tiocmget = cy_tiocmget,
4306 .tiocmset = cy_tiocmset,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004307 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308};
4309
Jiri Slaby02f11752006-12-08 02:39:28 -08004310static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311{
Jiri Slabydd025c02007-05-08 00:37:02 -07004312 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004313 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Jiri Slaby02f11752006-12-08 02:39:28 -08004315 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4316 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004317 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004318
4319 printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
4320 __DATE__, __TIME__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321
Jiri Slaby02f11752006-12-08 02:39:28 -08004322 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
Jiri Slaby02f11752006-12-08 02:39:28 -08004324 cy_serial_driver->owner = THIS_MODULE;
4325 cy_serial_driver->driver_name = "cyclades";
4326 cy_serial_driver->name = "ttyC";
4327 cy_serial_driver->major = CYCLADES_MAJOR;
4328 cy_serial_driver->minor_start = 0;
4329 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4330 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4331 cy_serial_driver->init_termios = tty_std_termios;
4332 cy_serial_driver->init_termios.c_cflag =
4333 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004334 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004335 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004337 retval = tty_register_driver(cy_serial_driver);
4338 if (retval) {
4339 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4340 goto err_frtty;
4341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
Jiri Slaby02f11752006-12-08 02:39:28 -08004343 /* the code below is responsible to find the boards. Each different
4344 type of board has its own detection routine. If a board is found,
4345 the next cy_card structure available is set by the detection
4346 routine. These functions are responsible for checking the
4347 availability of cy_card and cy_port data structures and updating
4348 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
Jiri Slaby02f11752006-12-08 02:39:28 -08004350 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004351 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Jiri Slaby6747cd92007-05-08 00:36:34 -07004353#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004354 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004355 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004356 if (retval && !nboards) {
4357 tty_unregister_driver(cy_serial_driver);
4358 goto err_frtty;
4359 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004360#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004361
4362 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004363err_frtty:
4364 put_tty_driver(cy_serial_driver);
4365err:
4366 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004367} /* cy_init */
4368
4369static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370{
Jiri Slabydd025c02007-05-08 00:37:02 -07004371 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004372 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373
4374#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004375 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376#endif /* CONFIG_CYZ_INTR */
4377
Alan Cox15ed6cc2008-04-30 00:53:55 -07004378 e1 = tty_unregister_driver(cy_serial_driver);
4379 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004380 printk(KERN_ERR "failed to unregister Cyclades serial "
4381 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382
Jiri Slaby6747cd92007-05-08 00:36:34 -07004383#ifdef CONFIG_PCI
4384 pci_unregister_driver(&cy_pci_driver);
4385#endif
4386
Jiri Slaby02f11752006-12-08 02:39:28 -08004387 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004388 card = &cy_card[i];
4389 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004390 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004391 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4392 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004393 if (card->ctl_addr.p9050)
4394 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004395 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004397 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004399 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004400 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004401 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004402 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004403 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004404 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004405 }
4406 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004407
4408 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409} /* cy_cleanup_module */
4410
4411module_init(cy_init);
4412module_exit(cy_cleanup_module);
4413
4414MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004415MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad72009-04-06 17:33:04 +01004416MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);