blob: 74627950f90199774bf51b3c684bfc31c566dcee [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#undef BLOCKMOVE
2#define Z_WAKE
3#undef Z_EXT_CHARS_IN_BUFFER
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5/*
6 * linux/drivers/char/cyclades.c
7 *
8 * This file contains the driver for the Cyclades async multiport
9 * serial boards.
10 *
11 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
12 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Jiri Slabyebdb5132009-09-19 13:13:14 -070014 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
16 * Much of the design and some of the code came from serial.c
17 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
18 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
19 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070020 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 */
23
Jiri Slabyebdb5132009-09-19 13:13:14 -070024#define CY_VERSION "2.6"
Jiri Slaby096dcfc2006-12-08 02:39:30 -080025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026/* If you need to install more boards than NR_CARDS, change the constant
27 in the definition below. No other change is necessary to support up to
28 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
29
Jiri Slaby02f11752006-12-08 02:39:28 -080030#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32/*
33 If the total number of ports is larger than NR_PORTS, change this
34 constant in the definition below. No other change is necessary to
35 support more boards/ports. */
36
Jiri Slaby02f11752006-12-08 02:39:28 -080037#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define ZO_V1 0
40#define ZO_V2 1
41#define ZE_V1 2
42
43#define SERIAL_PARANOIA_CHECK
44#undef CY_DEBUG_OPEN
45#undef CY_DEBUG_THROTTLE
46#undef CY_DEBUG_OTHER
47#undef CY_DEBUG_IO
48#undef CY_DEBUG_COUNT
49#undef CY_DEBUG_DTR
50#undef CY_DEBUG_WAIT_UNTIL_SENT
51#undef CY_DEBUG_INTERRUPTS
52#undef CY_16Y_HACK
53#undef CY_ENABLE_MONITORING
54#undef CY_PCI_DEBUG
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/*
Alan Cox15ed6cc2008-04-30 00:53:55 -070057 * Include section
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <linux/module.h>
60#include <linux/errno.h>
61#include <linux/signal.h>
62#include <linux/sched.h>
63#include <linux/timer.h>
64#include <linux/interrupt.h>
65#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -080066#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/serial.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040068#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include <linux/major.h>
70#include <linux/string.h>
71#include <linux/fcntl.h>
72#include <linux/ptrace.h>
73#include <linux/cyclades.h>
74#include <linux/mm.h>
75#include <linux/ioport.h>
76#include <linux/init.h>
77#include <linux/delay.h>
78#include <linux/spinlock.h>
79#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -070080#include <linux/firmware.h>
Scott James Remnant9f56fad2009-04-06 17:33:04 +010081#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Alan Cox15ed6cc2008-04-30 00:53:55 -070083#include <linux/io.h>
Alan Cox15ed6cc2008-04-30 00:53:55 -070084#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#include <linux/kernel.h>
87#include <linux/pci.h>
88
89#include <linux/stat.h>
90#include <linux/proc_fs.h>
Alexey Dobriyan444697d2009-03-31 15:19:15 -070091#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Jiri Slaby02f11752006-12-08 02:39:28 -080093static void cy_throttle(struct tty_struct *tty);
94static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifndef SERIAL_XMIT_SIZE
97#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
98#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100#define STD_COM_FLAGS (0)
101
Jiri Slaby054f5b02007-07-17 04:05:16 -0700102/* firmware stuff */
103#define ZL_MAX_BLOCKS 16
104#define DRIVER_VERSION 0x02010203
105#define RAM_SIZE 0x80000
106
Jiri Slaby054f5b02007-07-17 04:05:16 -0700107enum zblock_type {
108 ZBLOCK_PRG = 0,
109 ZBLOCK_FPGA = 1
110};
111
112struct zfile_header {
113 char name[64];
114 char date[32];
115 char aux[32];
116 u32 n_config;
117 u32 config_offset;
118 u32 n_blocks;
119 u32 block_offset;
120 u32 reserved[9];
121} __attribute__ ((packed));
122
123struct zfile_config {
124 char name[64];
125 u32 mailbox;
126 u32 function;
127 u32 n_blocks;
128 u32 block_list[ZL_MAX_BLOCKS];
129} __attribute__ ((packed));
130
131struct zfile_block {
132 u32 type;
133 u32 file_offset;
134 u32 ram_offset;
135 u32 size;
136} __attribute__ ((packed));
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static struct tty_driver *cy_serial_driver;
139
140#ifdef CONFIG_ISA
141/* This is the address lookup table. The driver will probe for
142 Cyclom-Y/ISA boards at all addresses in here. If you want the
143 driver to probe addresses at a different address, add it to
144 this table. If the driver is probing some other board and
145 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146*/
147
148static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800149 0xD0000,
150 0xD2000,
151 0xD4000,
152 0xD6000,
153 0xD8000,
154 0xDA000,
155 0xDC000,
156 0xDE000,
157 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158};
Jiri Slaby02f11752006-12-08 02:39:28 -0800159
Tobias Klauserfe971072006-01-09 20:54:02 -0800160#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162#ifdef MODULE
Jiri Slaby3046d502007-05-08 00:36:46 -0700163static long maddr[NR_CARDS];
164static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166module_param_array(maddr, long, NULL, 0);
167module_param_array(irq, int, NULL, 0);
168#endif
169
Jiri Slaby02f11752006-12-08 02:39:28 -0800170#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172/* This is the per-card data structure containing address, irq, number of
173 channels, etc. This driver supports a maximum of NR_CARDS cards.
174*/
175static struct cyclades_card cy_card[NR_CARDS];
176
Jiri Slaby02f11752006-12-08 02:39:28 -0800177static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 * This is used to look up the divisor speeds and the timeouts
181 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100182 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
184 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
185 * HI VHI
186 * 20
187 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700188static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800189 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
190 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
191 230400, 0
192};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Jiri Slabyebdb5132009-09-19 13:13:14 -0700194static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800195 /* value => 00 01 02 03 04 */
196 /* divide by 8 32 128 512 2048 */
197 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
198 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
199};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Jiri Slabyebdb5132009-09-19 13:13:14 -0700201static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800202 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
203 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
204};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Jiri Slabyebdb5132009-09-19 13:13:14 -0700206static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800207 /* value => 00 01 02 03 04 */
208 /* divide by 8 32 128 512 2048 */
209 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
210 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00
212};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Jiri Slabyebdb5132009-09-19 13:13:14 -0700214static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800215 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
216 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
217 0x21
218};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Jiri Slabyebdb5132009-09-19 13:13:14 -0700220static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800221 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
222 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
223 0x07
224};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226/*
227 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700228 * The cyclades_port structure member rflow and the vector rflow_thr
229 * allows us to take advantage of a special feature in the CD1400 to avoid
230 * data loss even when the system interrupt latency is too high. These flags
231 * are to be used only with very special applications. Setting these flags
232 * requires the use of a special cable (DTR and RTS reversed). In the new
233 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 * cables.
235 */
236
Jiri Slabyebdb5132009-09-19 13:13:14 -0700237static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
240 0x0a
241};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243/* The Cyclom-Ye has placed the sequential chips in non-sequential
244 * address order. This look-up table overcomes that problem.
245 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700246static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800247 0x0400,
248 0x0800,
249 0x0C00,
250 0x0200,
251 0x0600,
252 0x0A00,
253 0x0E00
254};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256/* PCI related definitions */
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700259static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700260 /* PCI < 1Mb */
261 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
262 /* PCI > 1Mb */
263 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
264 /* 4Y PCI < 1Mb */
265 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
266 /* 4Y PCI > 1Mb */
267 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
268 /* 8Y PCI < 1Mb */
269 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
270 /* 8Y PCI > 1Mb */
271 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
272 /* Z PCI < 1Mb */
273 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
274 /* Z PCI > 1Mb */
275 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800276 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800277};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800278MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#endif
280
281static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700282static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700283static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284#ifdef CONFIG_ISA
285static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800286#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288#ifndef CONFIG_CYZ_INTR
289static void cyz_poll(unsigned long);
290
291/* The Cyclades-Z polling cycle is defined by this variable */
292static long cyz_polling_cycle = CZ_DEF_POLL;
293
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700294static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Jiri Slaby02f11752006-12-08 02:39:28 -0800296#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297static void cyz_rx_restart(unsigned long);
298static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800299#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Jiri Slaby2693f482009-06-11 12:31:06 +0100301static inline bool cy_is_Z(struct cyclades_card *card)
302{
303 return card->num_chips == (unsigned int)-1;
304}
305
306static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
307{
308 return readl(&ctl_addr->init_ctrl) & (1 << 17);
309}
310
311static inline bool cyz_fpga_loaded(struct cyclades_card *card)
312{
313 return __cyz_fpga_loaded(card->ctl_addr.p9060);
314}
315
316static inline bool cyz_is_loaded(struct cyclades_card *card)
317{
318 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
319
320 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
321 readl(&fw_id->signature) == ZFIRM_ID;
322}
323
Jiri Slaby02f11752006-12-08 02:39:28 -0800324static inline int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700325 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800328 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700329 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
330 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800331 return 1;
332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jiri Slaby02f11752006-12-08 02:39:28 -0800334 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700335 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
336 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800337 return 1;
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800340 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700341}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343/***********************************************************/
344/********* Start of block of Cyclom-Y specific code ********/
345
346/* This routine waits up to 1000 micro-seconds for the previous
347 command to the Cirrus chip to complete and then issues the
348 new command. An error is returned if the previous command
349 didn't finish within the time limit.
350
351 This function is only called from inside spinlock-protected code.
352 */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700353static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Jiri Slabyad39c302007-05-08 00:35:49 -0700355 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Jiri Slaby02f11752006-12-08 02:39:28 -0800357 /* Check to see that the previous command has completed */
358 for (i = 0; i < 100; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700359 if (readb(base_addr + (CyCCR << index)) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800360 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800361 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800363 /* if the CCR never cleared, the previous command
364 didn't finish within the "reasonable time" */
365 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800366 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Jiri Slaby02f11752006-12-08 02:39:28 -0800368 /* Issue the new command */
369 cy_writeb(base_addr + (CyCCR << index), cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800371 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800372} /* cyy_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374#ifdef CONFIG_ISA
375/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700376static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
Jiri Slaby02f11752006-12-08 02:39:28 -0800378 int irq;
379 unsigned long irqs, flags;
380 int save_xir, save_car;
381 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Jiri Slaby02f11752006-12-08 02:39:28 -0800383 /* forget possible initially masked and pending IRQ */
384 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Jiri Slaby02f11752006-12-08 02:39:28 -0800386 /* Clear interrupts on the board first */
387 cy_writeb(address + (Cy_ClrIntr << index), 0);
388 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Jiri Slaby02f11752006-12-08 02:39:28 -0800390 irqs = probe_irq_on();
391 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700392 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Jiri Slaby02f11752006-12-08 02:39:28 -0800394 /* Enable the Tx interrupts on the CD1400 */
395 local_irq_save(flags);
396 cy_writeb(address + (CyCAR << index), 0);
397 cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Jiri Slaby02f11752006-12-08 02:39:28 -0800399 cy_writeb(address + (CyCAR << index), 0);
400 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700401 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800402 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Jiri Slaby02f11752006-12-08 02:39:28 -0800404 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700405 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Jiri Slaby02f11752006-12-08 02:39:28 -0800407 /* Check which interrupt is in use */
408 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Jiri Slaby02f11752006-12-08 02:39:28 -0800410 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700411 save_xir = (u_char) readb(address + (CyTIR << index));
412 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800413 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
414 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700415 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800416 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
417 cy_writeb(address + (CyCAR << index), (save_car));
418 cy_writeb(address + (Cy_ClrIntr << index), 0);
419 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Jiri Slaby02f11752006-12-08 02:39:28 -0800421 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
Jiri Slaby02f11752006-12-08 02:39:28 -0800423#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Jiri Slabyce97a092007-10-18 03:06:21 -0700425static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
426 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800427{
428 struct cyclades_port *info;
429 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700430 int len, index = cinfo->bus_index;
431 u8 save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800432
Jiri Slabye9410272006-12-08 02:39:28 -0800433#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700434 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800435#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700436 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700437 save_xir = readb(base_addr + (CyRIR << index));
438 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700439 info = &cinfo->ports[channel + chip * 4];
440 save_car = readb(base_addr + (CyCAR << index));
441 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800442
Jiri Slabyd13549f2009-09-19 13:13:12 -0700443 tty = tty_port_tty_get(&info->port);
Jiri Slabyce97a092007-10-18 03:06:21 -0700444 /* if there is nowhere to put the data, discard it */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700445 if (tty == NULL) {
Jiri Slaby65f76a82007-10-18 03:06:22 -0700446 if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
447 CyIVRRxEx) { /* exception */
Jiri Slabyce97a092007-10-18 03:06:21 -0700448 data = readb(base_addr + (CyRDSR << index));
449 } else { /* normal character reception */
450 char_count = readb(base_addr + (CyRDCR << index));
451 while (char_count--)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700452 data = readb(base_addr + (CyRDSR << index));
Jiri Slabyce97a092007-10-18 03:06:21 -0700453 }
454 goto end;
455 }
456 /* there is an open port for this data */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700457 if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
458 CyIVRRxEx) { /* exception */
Jiri Slabyce97a092007-10-18 03:06:21 -0700459 data = readb(base_addr + (CyRDSR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800460
Jiri Slabyce97a092007-10-18 03:06:21 -0700461 /* For statistics only */
462 if (data & CyBREAK)
463 info->icount.brk++;
464 else if (data & CyFRAME)
465 info->icount.frame++;
466 else if (data & CyPARITY)
467 info->icount.parity++;
468 else if (data & CyOVERRUN)
469 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800470
Jiri Slabyce97a092007-10-18 03:06:21 -0700471 if (data & info->ignore_status_mask) {
472 info->icount.rx++;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700473 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700474 return;
475 }
476 if (tty_buffer_request_room(tty, 1)) {
477 if (data & info->read_status_mask) {
478 if (data & CyBREAK) {
479 tty_insert_flip_char(tty,
480 readb(base_addr + (CyRDSR <<
481 index)), TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800482 info->icount.rx++;
Alan Cox77451e52008-07-16 21:57:02 +0100483 if (info->port.flags & ASYNC_SAK)
Jiri Slabyce97a092007-10-18 03:06:21 -0700484 do_SAK(tty);
485 } else if (data & CyFRAME) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700486 tty_insert_flip_char(tty,
Jiri Slabyce97a092007-10-18 03:06:21 -0700487 readb(base_addr + (CyRDSR <<
488 index)), TTY_FRAME);
489 info->icount.rx++;
490 info->idle_stats.frame_errs++;
491 } else if (data & CyPARITY) {
492 /* Pieces of seven... */
493 tty_insert_flip_char(tty,
494 readb(base_addr + (CyRDSR <<
495 index)), TTY_PARITY);
496 info->icount.rx++;
497 info->idle_stats.parity_errs++;
498 } else if (data & CyOVERRUN) {
499 tty_insert_flip_char(tty, 0,
500 TTY_OVERRUN);
501 info->icount.rx++;
502 /* If the flip buffer itself is
503 overflowing, we still lose
504 the next incoming character.
505 */
506 tty_insert_flip_char(tty,
507 readb(base_addr + (CyRDSR <<
508 index)), TTY_FRAME);
509 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800510 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700511 /* These two conditions may imply */
512 /* a normal read should be done. */
513 /* } else if(data & CyTIMEOUT) { */
514 /* } else if(data & CySPECHAR) { */
515 } else {
516 tty_insert_flip_char(tty, 0,
517 TTY_NORMAL);
518 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800519 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700520 } else {
521 tty_insert_flip_char(tty, 0, TTY_NORMAL);
522 info->icount.rx++;
523 }
524 } else {
525 /* there was a software buffer overrun and nothing
526 * could be done about it!!! */
527 info->icount.buf_overrun++;
528 info->idle_stats.overruns++;
529 }
530 } else { /* normal character reception */
531 /* load # chars available from the chip */
532 char_count = readb(base_addr + (CyRDCR << index));
Jiri Slabye9410272006-12-08 02:39:28 -0800533
534#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700535 ++info->mon.int_count;
536 info->mon.char_count += char_count;
537 if (char_count > info->mon.char_max)
538 info->mon.char_max = char_count;
539 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800540#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700541 len = tty_buffer_request_room(tty, char_count);
542 while (len--) {
543 data = readb(base_addr + (CyRDSR << index));
544 tty_insert_flip_char(tty, data, TTY_NORMAL);
545 info->idle_stats.recv_bytes++;
546 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800547#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700548 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800549#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800550 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700551 info->idle_stats.recv_idle = jiffies;
552 }
553 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700554 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700555end:
556 /* end of service */
557 cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
558 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700559}
560
Jiri Slaby65f76a82007-10-18 03:06:22 -0700561static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700562 void __iomem *base_addr)
563{
564 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700565 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700566 int char_count, index = cinfo->bus_index;
567 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700568
569 /* Since we only get here when the transmit buffer
570 is empty, we know we can always stuff a dozen
571 characters. */
572#ifdef CY_DEBUG_INTERRUPTS
573 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
574#endif
575
576 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700577 save_xir = readb(base_addr + (CyTIR << index));
578 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700579 save_car = readb(base_addr + (CyCAR << index));
580 cy_writeb(base_addr + (CyCAR << index), save_xir);
581
582 /* validate the port# (as configured and open) */
583 if (channel + chip * 4 >= cinfo->nports) {
584 cy_writeb(base_addr + (CySRER << index),
585 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
586 goto end;
587 }
588 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700589 tty = tty_port_tty_get(&info->port);
590 if (tty == NULL) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700591 cy_writeb(base_addr + (CySRER << index),
592 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
593 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800594 }
595
Jiri Slabyce97a092007-10-18 03:06:21 -0700596 /* load the on-chip space for outbound data */
597 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800598
Jiri Slabyce97a092007-10-18 03:06:21 -0700599 if (info->x_char) { /* send special char */
600 outch = info->x_char;
601 cy_writeb(base_addr + (CyTDR << index), outch);
602 char_count--;
603 info->icount.tx++;
604 info->x_char = 0;
605 }
Jiri Slabye9410272006-12-08 02:39:28 -0800606
Jiri Slabyce97a092007-10-18 03:06:21 -0700607 if (info->breakon || info->breakoff) {
608 if (info->breakon) {
609 cy_writeb(base_addr + (CyTDR << index), 0);
610 cy_writeb(base_addr + (CyTDR << index), 0x81);
611 info->breakon = 0;
612 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800613 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700614 if (info->breakoff) {
615 cy_writeb(base_addr + (CyTDR << index), 0);
616 cy_writeb(base_addr + (CyTDR << index), 0x83);
617 info->breakoff = 0;
618 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800619 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700620 }
Jiri Slabye9410272006-12-08 02:39:28 -0800621
Jiri Slabyce97a092007-10-18 03:06:21 -0700622 while (char_count-- > 0) {
623 if (!info->xmit_cnt) {
624 if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
625 cy_writeb(base_addr + (CySRER << index),
626 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800627 ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700628 } else {
629 cy_writeb(base_addr + (CySRER << index),
630 (readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800631 ~CyTxRdy) | CyTxMpty);
Jiri Slaby02f11752006-12-08 02:39:28 -0800632 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700633 goto done;
634 }
Alan Cox77451e52008-07-16 21:57:02 +0100635 if (info->port.xmit_buf == NULL) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700636 cy_writeb(base_addr + (CySRER << index),
637 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800638 ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700639 goto done;
640 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700641 if (tty->stopped || tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700642 cy_writeb(base_addr + (CySRER << index),
643 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800644 ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700645 goto done;
646 }
647 /* Because the Embedded Transmit Commands have been enabled,
648 * we must check to see if the escape character, NULL, is being
649 * sent. If it is, we must ensure that there is room for it to
650 * be doubled in the output stream. Therefore we no longer
651 * advance the pointer when the character is fetched, but
652 * rather wait until after the check for a NULL output
653 * character. This is necessary because there may not be room
654 * for the two chars needed to send a NULL.)
655 */
Alan Cox77451e52008-07-16 21:57:02 +0100656 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700657 if (outch) {
658 info->xmit_cnt--;
659 info->xmit_tail = (info->xmit_tail + 1) &
660 (SERIAL_XMIT_SIZE - 1);
661 cy_writeb(base_addr + (CyTDR << index), outch);
662 info->icount.tx++;
663 } else {
664 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800665 info->xmit_cnt--;
666 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700667 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800668 cy_writeb(base_addr + (CyTDR << index), outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700669 cy_writeb(base_addr + (CyTDR << index), 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800670 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700671 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800672 }
673 }
Jiri Slabye9410272006-12-08 02:39:28 -0800674 }
675
Jiri Slabyce97a092007-10-18 03:06:21 -0700676done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700677 tty_wakeup(tty);
678 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700679end:
680 /* end of service */
681 cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
682 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700683}
Jiri Slabye9410272006-12-08 02:39:28 -0800684
Jiri Slabyce97a092007-10-18 03:06:21 -0700685static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
686 void __iomem *base_addr)
687{
688 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700689 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700690 int index = cinfo->bus_index;
691 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800692
Jiri Slabyce97a092007-10-18 03:06:21 -0700693 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700694 save_xir = readb(base_addr + (CyMIR << index));
695 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700696 info = &cinfo->ports[channel + chip * 4];
697 save_car = readb(base_addr + (CyCAR << index));
698 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800699
Jiri Slabyce97a092007-10-18 03:06:21 -0700700 mdm_change = readb(base_addr + (CyMISR << index));
701 mdm_status = readb(base_addr + (CyMSVR1 << index));
Jiri Slabye9410272006-12-08 02:39:28 -0800702
Jiri Slabyd13549f2009-09-19 13:13:12 -0700703 tty = tty_port_tty_get(&info->port);
704 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700705 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800706
Jiri Slabyce97a092007-10-18 03:06:21 -0700707 if (mdm_change & CyANY_DELTA) {
708 /* For statistics only */
709 if (mdm_change & CyDCD)
710 info->icount.dcd++;
711 if (mdm_change & CyCTS)
712 info->icount.cts++;
713 if (mdm_change & CyDSR)
714 info->icount.dsr++;
715 if (mdm_change & CyRI)
716 info->icount.rng++;
717
718 wake_up_interruptible(&info->delta_msr_wait);
719 }
720
Alan Cox77451e52008-07-16 21:57:02 +0100721 if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700722 if (mdm_status & CyDCD)
723 wake_up_interruptible(&info->port.open_wait);
724 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700725 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800726 }
Alan Cox77451e52008-07-16 21:57:02 +0100727 if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700728 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700729 if (mdm_status & CyCTS) {
730 /* cy_start isn't used
731 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700732 tty->hw_stopped = 0;
Jiri Slabyce97a092007-10-18 03:06:21 -0700733 cy_writeb(base_addr + (CySRER << index),
734 readb(base_addr + (CySRER << index)) |
735 CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700736 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700737 }
738 } else {
739 if (!(mdm_status & CyCTS)) {
740 /* cy_stop isn't used
741 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700742 tty->hw_stopped = 1;
Jiri Slabyce97a092007-10-18 03:06:21 -0700743 cy_writeb(base_addr + (CySRER << index),
744 readb(base_addr + (CySRER << index)) &
745 ~CyTxRdy);
746 }
747 }
748 }
749/* if (mdm_change & CyDSR) {
750 }
751 if (mdm_change & CyRI) {
752 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700753 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700754end:
755 /* end of service */
756 cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
757 cy_writeb(base_addr + (CyCAR << index), save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760/* The real interrupt service routine is called
761 whenever the card wants its hand held--chars
762 received, out buffer empty, modem change, etc.
763 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800764static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Jiri Slaby02f11752006-12-08 02:39:28 -0800766 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700767 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800768 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700769 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800770 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800771
Jiri Slabyf7429032007-05-08 00:36:59 -0700772 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700774 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
775 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800777 return IRQ_NONE; /* spurious interrupt */
778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Jiri Slaby02f11752006-12-08 02:39:28 -0800780 card_base_addr = cinfo->base_addr;
781 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700783 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
784 if (unlikely(card_base_addr == NULL))
785 return IRQ_HANDLED;
786
Jiri Slaby02f11752006-12-08 02:39:28 -0800787 /* This loop checks all chips in the card. Make a note whenever
788 _any_ chip had some work to do, as this is considered an
789 indication that there will be more to do. Only when no chip
790 has any work does this outermost loop exit.
791 */
792 do {
793 had_work = 0;
794 for (chip = 0; chip < cinfo->num_chips; chip++) {
795 base_addr = cinfo->base_addr +
796 (cy_chip_offset[chip] << index);
797 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700798 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800799 (CySVRR << index))) != 0x00) {
800 had_work++;
801 /* The purpose of the following test is to ensure that
802 no chip can monopolize the driver. This forces the
803 chips to be checked in a round-robin fashion (after
804 draining each of a bunch (1000) of characters).
805 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700806 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800807 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700808 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700809 if (status & CySRReceive) /* rx intr */
810 cyy_chip_rx(cinfo, chip, base_addr);
811 if (status & CySRTransmit) /* tx intr */
812 cyy_chip_tx(cinfo, chip, base_addr);
813 if (status & CySRModem) /* modem intr */
814 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700815 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800816 }
817 }
818 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Jiri Slaby02f11752006-12-08 02:39:28 -0800820 /* clear interrupts */
821 spin_lock(&cinfo->card_lock);
822 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
823 /* Cy_ClrIntr is 0x1800 */
824 spin_unlock(&cinfo->card_lock);
825 return IRQ_HANDLED;
826} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Jiri Slaby4d768202009-09-19 13:13:15 -0700828static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
829 unsigned int clear)
830{
831 struct cyclades_card *card = info->card;
832 void __iomem *base_addr;
833 int chip, channel, index;
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 Slaby875b2062007-05-08 00:36:49 -07001299 int chip, channel, index;
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
Alan Cox77451e52008-07-16 21:57:02 +01001311 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001312 free_page(page);
1313 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001315
1316 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001317 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001318 free_page(page);
1319 goto errout;
1320 }
1321
Alan Cox77451e52008-07-16 21:57:02 +01001322 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001323 free_page(page);
1324 else
Alan Cox77451e52008-07-16 21:57:02 +01001325 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001327 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Jiri Slabyd13549f2009-09-19 13:13:12 -07001329 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Jiri Slaby2693f482009-06-11 12:31:06 +01001331 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001332 chip = channel >> 2;
1333 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001334 index = card->bus_index;
1335 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001338 printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
1339 "base_addr %p\n",
1340 card, chip, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001341#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001342 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001343
1344 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1345
1346 cy_writeb(base_addr + (CyRTPR << index),
1347 (info->default_timeout ? info->default_timeout : 0x02));
1348 /* 10ms rx timeout */
1349
1350 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
1351 index);
1352
Jiri Slaby4d768202009-09-19 13:13:15 -07001353 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Jiri Slaby02f11752006-12-08 02:39:28 -08001355 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001356 readb(base_addr + (CySRER << index)) | CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001357 info->port.flags |= ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Jiri Slabyd13549f2009-09-19 13:13:12 -07001359 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001360 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1361 info->breakon = info->breakoff = 0;
1362 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1363 info->idle_stats.in_use =
1364 info->idle_stats.recv_idle =
1365 info->idle_stats.xmit_idle = jiffies;
1366
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001367 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001368
1369 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001370 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001371
Jiri Slaby2693f482009-06-11 12:31:06 +01001372 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001373 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001374
Jiri Slaby02f11752006-12-08 02:39:28 -08001375#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001376 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001377 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001378#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001379 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001380
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001381 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382#ifdef Z_WAKE
1383#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001384 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001385 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1386 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001388 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001389 C_IN_IOCTLW | C_IN_MDCD);
1390#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391#else
1392#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001393 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001394 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1395 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001397 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001398#endif /* CONFIG_CYZ_INTR */
1399#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Jiri Slaby875b2062007-05-08 00:36:49 -07001401 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001402 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001403 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1404 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Jiri Slaby02f11752006-12-08 02:39:28 -08001407 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001408 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001409 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001410 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1411 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Jiri Slaby02f11752006-12-08 02:39:28 -08001414 /* set timeout !!! */
1415 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001416 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
Jiri Slaby02f11752006-12-08 02:39:28 -08001418 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Alan Cox77451e52008-07-16 21:57:02 +01001420 info->port.flags |= ASYNC_INITIALIZED;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001421 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001422 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1423 info->breakon = info->breakoff = 0;
1424 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1425 info->idle_stats.in_use =
1426 info->idle_stats.recv_idle =
1427 info->idle_stats.xmit_idle = jiffies;
1428
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001429 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001433 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434#endif
1435 return 0;
1436
1437errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001438 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001440} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Jiri Slaby02f11752006-12-08 02:39:28 -08001442static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
Jiri Slaby875b2062007-05-08 00:36:49 -07001444 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001445 unsigned long flags;
1446 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001447 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Jiri Slaby02f11752006-12-08 02:39:28 -08001449 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001450 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001451 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001452 chip = channel >> 2;
1453 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001454 index = card->bus_index;
1455 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001457 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001458 cy_writeb(base_addr + (CyCAR << index), channel);
1459 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001460 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001461 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001462 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001464 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001466 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001467 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001468 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001469 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1470 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001471 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001472 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001473#else /* CONFIG_CYZ_INTR */
1474 /* Don't have to do anything at this time */
1475#endif /* CONFIG_CYZ_INTR */
1476 }
1477} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
1479/*
1480 * This routine shuts down a serial port; interrupts are disabled,
1481 * and DTR is dropped if the hangup on close termio flag is on.
1482 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001483static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
Jiri Slaby875b2062007-05-08 00:36:49 -07001485 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001486 unsigned long flags;
1487 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001488 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Alan Cox77451e52008-07-16 21:57:02 +01001490 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001491 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
Jiri Slaby02f11752006-12-08 02:39:28 -08001493 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001494 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01001495 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001496 chip = channel >> 2;
1497 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001498 index = card->bus_index;
1499 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001502 printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
1503 "channel %d, base_addr %p\n",
1504 card, chip, channel, base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001507 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001508
1509 /* Clear delta_msr_wait queue to avoid mem leaks. */
1510 wake_up_interruptible(&info->delta_msr_wait);
1511
Alan Cox77451e52008-07-16 21:57:02 +01001512 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001513 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001514 temp = info->port.xmit_buf;
1515 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001516 free_page((unsigned long)temp);
1517 }
Jiri Slaby4d768202009-09-19 13:13:15 -07001518 if (tty->termios->c_cflag & HUPCL)
1519 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1520
Jiri Slaby02f11752006-12-08 02:39:28 -08001521 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
1522 /* it may be appropriate to clear _XMIT at
1523 some later date (after testing)!!! */
1524
Jiri Slabyd13549f2009-09-19 13:13:12 -07001525 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001526 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001527 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001528 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001529#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001530 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001531 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001532#endif
1533
Jiri Slaby2693f482009-06-11 12:31:06 +01001534 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001535 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001536
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001537 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001538
Alan Cox77451e52008-07-16 21:57:02 +01001539 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001540 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001541 temp = info->port.xmit_buf;
1542 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001543 free_page((unsigned long)temp);
1544 }
1545
Jiri Slaby4d768202009-09-19 13:13:15 -07001546 if (tty->termios->c_cflag & HUPCL)
1547 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001548
Jiri Slabyd13549f2009-09-19 13:13:12 -07001549 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001550 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001551
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001552 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001553 }
1554
1555#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001556 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001557#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001558} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560/*
1561 * ------------------------------------------------------------
1562 * cy_open() and friends
1563 * ------------------------------------------------------------
1564 */
1565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566/*
1567 * This routine is called whenever a serial port is opened. It
1568 * performs the serial-specific initialization for the tty structure.
1569 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001570static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
Jiri Slaby02f11752006-12-08 02:39:28 -08001572 struct cyclades_port *info;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001573 unsigned int i, line;
1574 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Jiri Slaby02f11752006-12-08 02:39:28 -08001576 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001577 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001579
Jiri Slabydd025c02007-05-08 00:37:02 -07001580 for (i = 0; i < NR_CARDS; i++)
1581 if (line < cy_card[i].first_line + cy_card[i].nports &&
1582 line >= cy_card[i].first_line)
1583 break;
1584 if (i >= NR_CARDS)
1585 return -ENODEV;
1586 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001587 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001588 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001589
1590 /* If the card's firmware hasn't been loaded,
1591 treat it as absent from the system. This
1592 will make the user pay attention.
1593 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001594 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001595 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001596 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1597
Jiri Slaby2693f482009-06-11 12:31:06 +01001598 if (!cyz_is_loaded(cinfo)) {
1599 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001600 readl(&firm_id->signature) ==
1601 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001602 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1603 "need an external power supply for "
1604 "this number of ports.\nFirmware "
1605 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001606 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001607 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1608 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001609 }
1610 return -ENODEV;
1611 }
1612#ifdef CONFIG_CYZ_INTR
1613 else {
1614 /* In case this Z board is operating in interrupt mode, its
1615 interrupts should be enabled as soon as the first open
1616 happens to one of its ports. */
1617 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001618 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001619
Jiri Slaby02f11752006-12-08 02:39:28 -08001620 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001621 intr = readw(&cinfo->ctl_addr.p9060->
1622 intr_ctrl_stat) | 0x0900;
1623 cy_writew(&cinfo->ctl_addr.p9060->
1624 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001625 /* Enable interrupts on the FW */
1626 retval = cyz_issue_cmd(cinfo, 0,
1627 C_CM_IRQ_ENBL, 0L);
1628 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001629 printk(KERN_ERR "cyc:IRQ enable retval "
1630 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001631 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001632 cinfo->intr_enabled = 1;
1633 }
1634 }
1635#endif /* CONFIG_CYZ_INTR */
1636 /* Make sure this Z port really exists in hardware */
1637 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1638 return -ENODEV;
1639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001641 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001643 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001644 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001645 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001648 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001649 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650#endif
Alan Cox77451e52008-07-16 21:57:02 +01001651 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001653 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001654 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Jiri Slaby02f11752006-12-08 02:39:28 -08001657 /*
1658 * If the port is the middle of closing, bail out now
1659 */
Alan Cox77451e52008-07-16 21:57:02 +01001660 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1661 wait_event_interruptible(info->port.close_wait,
1662 !(info->port.flags & ASYNC_CLOSING));
1663 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
Jiri Slaby02f11752006-12-08 02:39:28 -08001666 /*
1667 * Start up serial port
1668 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001669 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001670 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001671 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
Jiri Slabyf0737572009-09-19 13:13:12 -07001673 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001674 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001676 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1677 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001679 return retval;
1680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
Jiri Slaby02f11752006-12-08 02:39:28 -08001682 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001683 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
1685#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001686 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001688 return 0;
1689} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691/*
1692 * cy_wait_until_sent() --- wait until the transmitter is empty
1693 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001694static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695{
Jiri Slaby875b2062007-05-08 00:36:49 -07001696 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001697 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001698 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001699 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001700 unsigned long orig_jiffies;
1701 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Jiri Slaby02f11752006-12-08 02:39:28 -08001703 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1704 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
Jiri Slaby02f11752006-12-08 02:39:28 -08001706 if (info->xmit_fifo_size == 0)
1707 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Jiri Slaby02f11752006-12-08 02:39:28 -08001709 orig_jiffies = jiffies;
Alan Cox978e5952008-04-30 00:53:59 -07001710 lock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08001711 /*
1712 * Set the check interval to be 1/5 of the estimated time to
1713 * send a single character, and make it at least 1. The check
1714 * interval should also be less than the timeout.
1715 *
1716 * Note: we have to use pretty tight timings here to satisfy
1717 * the NIST-PCTS.
1718 */
1719 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1720 char_time = char_time / 5;
1721 if (char_time <= 0)
1722 char_time = 1;
1723 if (timeout < 0)
1724 timeout = 0;
1725 if (timeout)
1726 char_time = min(char_time, timeout);
1727 /*
1728 * If the transmitter hasn't cleared in twice the approximate
1729 * amount of time to send the entire FIFO, it probably won't
1730 * ever clear. This assumes the UART isn't doing flow
1731 * control, which is currently the case. Hence, if it ever
1732 * takes longer than info->timeout, this is probably due to a
1733 * UART bug of some kind. So, we clamp the timeout parameter at
1734 * 2*info->timeout.
1735 */
1736 if (!timeout || timeout > 2 * info->timeout)
1737 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001739 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1740 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001742 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001743 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01001744 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001745 chip = channel >> 2;
1746 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001747 index = card->bus_index;
1748 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001749 while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
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 "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001753 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1754 break;
1755 if (timeout && time_after(jiffies, orig_jiffies +
1756 timeout))
1757 break;
1758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001760 /* Run one more char cycle */
1761 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Alan Cox978e5952008-04-30 00:53:59 -07001762 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001764 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765#endif
1766}
1767
Alan Cox978e5952008-04-30 00:53:59 -07001768static void cy_flush_buffer(struct tty_struct *tty)
1769{
1770 struct cyclades_port *info = tty->driver_data;
1771 struct cyclades_card *card;
1772 int channel, retval;
1773 unsigned long flags;
1774
1775#ifdef CY_DEBUG_IO
1776 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1777#endif
1778
1779 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1780 return;
1781
1782 card = info->card;
1783 channel = info->line - card->first_line;
1784
1785 spin_lock_irqsave(&card->card_lock, flags);
1786 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1787 spin_unlock_irqrestore(&card->card_lock, flags);
1788
Jiri Slaby2693f482009-06-11 12:31:06 +01001789 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001790 buffers as well */
1791 spin_lock_irqsave(&card->card_lock, flags);
1792 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1793 if (retval != 0) {
1794 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1795 "was %x\n", info->line, retval);
1796 }
1797 spin_unlock_irqrestore(&card->card_lock, flags);
1798 }
1799 tty_wakeup(tty);
1800} /* cy_flush_buffer */
1801
1802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803/*
1804 * This routine is called when a particular tty device is closed.
1805 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001806static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001808 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001809 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001810 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Alan Cox15ed6cc2008-04-30 00:53:55 -07001812 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001815 card = info->card;
1816
Jiri Slaby23342262009-09-19 13:13:13 -07001817 if (!tty_port_close_start(&info->port, tty, filp))
Jiri Slaby02f11752006-12-08 02:39:28 -08001818 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001819
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001820 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001821
Jiri Slaby2693f482009-06-11 12:31:06 +01001822 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001823 int channel = info->line - card->first_line;
1824 int index = card->bus_index;
1825 void __iomem *base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001826 (cy_chip_offset[channel >> 2] << index);
1827 /* Stop accepting input */
1828 channel &= 0x03;
1829 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1830 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001831 readb(base_addr + (CySRER << index)) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001832 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001833 /* Waiting for on-board buffers to be empty before
1834 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001835 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001836 cy_wait_until_sent(tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001837 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001838 }
1839 } else {
1840#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001841 /* Waiting for on-board buffers to be empty before closing
1842 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001843 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001844 int channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001845 int retval;
1846
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001847 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001848 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001849 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001850 printk(KERN_DEBUG "cyc:cy_close retval on "
1851 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001852 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001853 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001854 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001855 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001856 }
1857#endif
1858 }
1859
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001860 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001861 cy_shutdown(info, tty);
Alan Cox978e5952008-04-30 00:53:59 -07001862 cy_flush_buffer(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001863
Jiri Slabyd13549f2009-09-19 13:13:12 -07001864 tty_port_tty_set(&info->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
Jiri Slaby23342262009-09-19 13:13:13 -07001866 tty_port_close_end(&info->port, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001867} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
1869/* This routine gets called when tty_write has put something into
1870 * the write_queue. The characters may come from user space or
1871 * kernel space.
1872 *
1873 * This routine will return the number of characters actually
1874 * accepted for writing.
1875 *
1876 * If the port is not already transmitting stuff, start it off by
1877 * enabling interrupts. The interrupt service routine will then
1878 * ensure that the characters are sent.
1879 * If the port is already active, there is no need to kick it.
1880 *
1881 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001882static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001884 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001885 unsigned long flags;
1886 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001889 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890#endif
1891
Alan Cox15ed6cc2008-04-30 00:53:55 -07001892 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001893 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Alan Cox77451e52008-07-16 21:57:02 +01001895 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001896 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001898 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001899 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001900 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1901 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
Jiri Slaby02f11752006-12-08 02:39:28 -08001903 if (c <= 0)
1904 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Alan Cox77451e52008-07-16 21:57:02 +01001906 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 info->xmit_head = (info->xmit_head + c) &
1908 (SERIAL_XMIT_SIZE - 1);
1909 info->xmit_cnt += c;
1910 buf += c;
1911 count -= c;
1912 ret += c;
1913 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001914 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
Jiri Slaby02f11752006-12-08 02:39:28 -08001916 info->idle_stats.xmit_bytes += ret;
1917 info->idle_stats.xmit_idle = jiffies;
1918
Alan Cox15ed6cc2008-04-30 00:53:55 -07001919 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001920 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001921
Jiri Slaby02f11752006-12-08 02:39:28 -08001922 return ret;
1923} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925/*
1926 * This routine is called by the kernel to write a single
1927 * character to the tty device. If the kernel uses this routine,
1928 * it must call the flush_chars() routine (if defined) when it is
1929 * done stuffing characters into the driver. If there is no room
1930 * in the queue, the character is ignored.
1931 */
Alan Cox76b25a52008-04-30 00:54:03 -07001932static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001934 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001935 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
1937#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001938 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939#endif
1940
Jiri Slaby02f11752006-12-08 02:39:28 -08001941 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001942 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
Alan Cox77451e52008-07-16 21:57:02 +01001944 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001945 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001947 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001948 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001949 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001950 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Alan Cox77451e52008-07-16 21:57:02 +01001953 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001954 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1955 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 info->idle_stats.xmit_bytes++;
1957 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001958 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001959 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001960} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
1962/*
1963 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001964 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001966static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001968 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001969
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001971 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972#endif
1973
Jiri Slaby02f11752006-12-08 02:39:28 -08001974 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1975 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Jiri Slaby02f11752006-12-08 02:39:28 -08001977 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001978 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001979 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Jiri Slaby02f11752006-12-08 02:39:28 -08001981 start_xmit(info);
1982} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984/*
1985 * This routine returns the numbers of characters the tty driver
1986 * will accept for queuing to be written. This number is subject
1987 * to change as output buffers get emptied, or if the output flow
1988 * control is activated.
1989 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001990static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001992 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001993 int ret;
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001996 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997#endif
1998
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
2000 return 0;
2001 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
2002 if (ret < 0)
2003 ret = 0;
2004 return ret;
2005} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Jiri Slaby02f11752006-12-08 02:39:28 -08002007static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002009 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Jiri Slaby02f11752006-12-08 02:39:28 -08002011 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
2012 return 0;
2013
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002015 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002016#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002018 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2019 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002021 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002023 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002024 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002025 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07002026 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
Alan Cox978e5952008-04-30 00:53:59 -07002028 lock_kernel();
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002029 tx_get = readl(&buf_ctrl->tx_get);
2030 tx_put = readl(&buf_ctrl->tx_put);
2031 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08002032 if (tx_put >= tx_get)
2033 char_count = tx_put - tx_get;
2034 else
2035 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002037 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2038 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039#endif
Alan Cox978e5952008-04-30 00:53:59 -07002040 unlock_kernel();
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002041 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08002042 }
2043#endif /* Z_EXT_CHARS_IN_BUFFER */
2044} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045
2046/*
2047 * ------------------------------------------------------------
2048 * cy_ioctl() and friends
2049 * ------------------------------------------------------------
2050 */
2051
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002052static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053{
Jiri Slaby02f11752006-12-08 02:39:28 -08002054 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002055 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08002056 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
Jiri Slaby02f11752006-12-08 02:39:28 -08002058 if (baud == 0) {
2059 info->tbpr = info->tco = info->rbpr = info->rco = 0;
2060 return;
2061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Jiri Slaby02f11752006-12-08 02:39:28 -08002063 /* determine which prescaler to use */
2064 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
2065 if (cy_clock / co_val / baud > 63)
2066 break;
2067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Jiri Slaby02f11752006-12-08 02:39:28 -08002069 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
2070 if (bpr > 255)
2071 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Jiri Slaby02f11752006-12-08 02:39:28 -08002073 info->tbpr = info->rbpr = bpr;
2074 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075}
2076
2077/*
2078 * This routine finds or computes the various line characteristics.
2079 * It used to be called config_setup
2080 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002081static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082{
Jiri Slaby875b2062007-05-08 00:36:49 -07002083 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002084 unsigned long flags;
2085 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002086 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002087 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002088 int baud, baud_rate = 0;
2089 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Jiri Slabyd13549f2009-09-19 13:13:12 -07002091 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002092 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002093
2094 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002095 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002096
Jiri Slabyd13549f2009-09-19 13:13:12 -07002097 cflag = tty->termios->c_cflag;
2098 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Jiri Slaby02f11752006-12-08 02:39:28 -08002100 /*
2101 * Set up the tty->alt_speed kludge
2102 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002103 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2104 tty->alt_speed = 57600;
2105 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2106 tty->alt_speed = 115200;
2107 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2108 tty->alt_speed = 230400;
2109 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2110 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
Jiri Slaby02f11752006-12-08 02:39:28 -08002112 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002113 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002114
Jiri Slaby2693f482009-06-11 12:31:06 +01002115 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002116
Jiri Slaby875b2062007-05-08 00:36:49 -07002117 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002118
2119 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002120 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002121 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002122 ASYNC_SPD_CUST) {
2123 if (info->custom_divisor)
2124 baud_rate = info->baud / info->custom_divisor;
2125 else
2126 baud_rate = info->baud;
2127 } else if (baud > CD1400_MAX_SPEED) {
2128 baud = CD1400_MAX_SPEED;
2129 }
2130 /* find the baud index */
2131 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002132 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002133 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002134 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002135 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002136 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002137
Alan Cox77451e52008-07-16 21:57:02 +01002138 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002139 ASYNC_SPD_CUST) {
2140 cyy_baud_calc(info, baud_rate);
2141 } else {
2142 if (info->chip_rev >= CD1400_REV_J) {
2143 /* It is a CD1400 rev. J or later */
2144 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2145 info->tco = baud_co_60[i]; /* Tx CO */
2146 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2147 info->rco = baud_co_60[i]; /* Rx CO */
2148 } else {
2149 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2150 info->tco = baud_co_25[i]; /* Tx CO */
2151 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2152 info->rco = baud_co_25[i]; /* Rx CO */
2153 }
2154 }
2155 if (baud_table[i] == 134) {
2156 /* get it right for 134.5 baud */
2157 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2158 2;
Alan Cox77451e52008-07-16 21:57:02 +01002159 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002160 ASYNC_SPD_CUST) {
2161 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2162 baud_rate) + 2;
2163 } else if (baud_table[i]) {
2164 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2165 baud_table[i]) + 2;
2166 /* this needs to be propagated into the card info */
2167 } else {
2168 info->timeout = 0;
2169 }
2170 /* By tradition (is it a standard?) a baud rate of zero
2171 implies the line should be/has been closed. A bit
2172 later in this routine such a test is performed. */
2173
2174 /* byte size and parity */
2175 info->cor5 = 0;
2176 info->cor4 = 0;
2177 /* receive threshold */
2178 info->cor3 = (info->default_threshold ?
2179 info->default_threshold : baud_cor3[i]);
2180 info->cor2 = CyETC;
2181 switch (cflag & CSIZE) {
2182 case CS5:
2183 info->cor1 = Cy_5_BITS;
2184 break;
2185 case CS6:
2186 info->cor1 = Cy_6_BITS;
2187 break;
2188 case CS7:
2189 info->cor1 = Cy_7_BITS;
2190 break;
2191 case CS8:
2192 info->cor1 = Cy_8_BITS;
2193 break;
2194 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002195 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002196 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002197
Jiri Slaby02f11752006-12-08 02:39:28 -08002198 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002199 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002200 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002201 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002202 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002203 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002204 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002205
2206 /* CTS flow control flag */
2207 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002208 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002209 info->cor2 |= CyCtsAE;
2210 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002211 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002212 info->cor2 &= ~CyCtsAE;
2213 }
2214 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002215 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 else
Alan Cox77451e52008-07-16 21:57:02 +01002217 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
2219 /***********************************************
2220 The hardware option, CyRtsAO, presents RTS when
2221 the chip has characters to send. Since most modems
2222 use RTS as reverse (inbound) flow control, this
2223 option is not used. If inbound flow control is
2224 necessary, DTR can be programmed to provide the
2225 appropriate signals for use with a non-standard
2226 cable. Contact Marcio Saito for details.
2227 ***********************************************/
2228
Jiri Slaby02f11752006-12-08 02:39:28 -08002229 chip = channel >> 2;
2230 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002231 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002233 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002234 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Jiri Slaby02f11752006-12-08 02:39:28 -08002236 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Jiri Slaby02f11752006-12-08 02:39:28 -08002238 cy_writeb(base_addr + (CyTCOR << index), info->tco);
2239 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
2240 cy_writeb(base_addr + (CyRCOR << index), info->rco);
2241 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Jiri Slaby02f11752006-12-08 02:39:28 -08002243 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
Jiri Slabyd13549f2009-09-19 13:13:12 -07002245 cy_writeb(base_addr + (CySCHR1 << index), START_CHAR(tty));
2246 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(tty));
Jiri Slaby02f11752006-12-08 02:39:28 -08002247 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
2248 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
2249 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2250 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
2251 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Jiri Slaby02f11752006-12-08 02:39:28 -08002253 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2254 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
Alan Cox15ed6cc2008-04-30 00:53:55 -07002256 /* !!! Is this needed? */
2257 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08002258 cy_writeb(base_addr + (CyRTPR << index),
2259 (info->default_timeout ? info->default_timeout : 0x02));
2260 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
Jiri Slabyd13549f2009-09-19 13:13:12 -07002262 if (C_CLOCAL(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002263 /* without modem intr */
2264 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002265 readb(base_addr + (CySRER << index)) | CyMdmCh);
Jiri Slaby02f11752006-12-08 02:39:28 -08002266 /* act on 1->0 modem transitions */
2267 if ((cflag & CRTSCTS) && info->rflow) {
2268 cy_writeb(base_addr + (CyMCOR1 << index),
2269 (CyCTS | rflow_thr[i]));
2270 } else {
2271 cy_writeb(base_addr + (CyMCOR1 << index),
2272 CyCTS);
2273 }
2274 /* act on 0->1 modem transitions */
2275 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002277 /* without modem intr */
2278 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002279 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002280 (CySRER << index)) | CyMdmCh);
2281 /* act on 1->0 modem transitions */
2282 if ((cflag & CRTSCTS) && info->rflow) {
2283 cy_writeb(base_addr + (CyMCOR1 << index),
2284 (CyDSR | CyCTS | CyRI | CyDCD |
2285 rflow_thr[i]));
2286 } else {
2287 cy_writeb(base_addr + (CyMCOR1 << index),
2288 CyDSR | CyCTS | CyRI | CyDCD);
2289 }
2290 /* act on 0->1 modem transitions */
2291 cy_writeb(base_addr + (CyMCOR2 << index),
2292 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002294
Jiri Slaby4d768202009-09-19 13:13:15 -07002295 if (i == 0) /* baud rate is zero, turn off line */
2296 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2297 else
2298 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Jiri Slabyd13549f2009-09-19 13:13:12 -07002300 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002301 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002304 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002305 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002306 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Jiri Slaby2693f482009-06-11 12:31:06 +01002308 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002309 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Jiri Slaby02f11752006-12-08 02:39:28 -08002311 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002312 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002313 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002314 ASYNC_SPD_CUST) {
2315 if (info->custom_divisor)
2316 baud_rate = info->baud / info->custom_divisor;
2317 else
2318 baud_rate = info->baud;
2319 } else if (baud > CYZ_MAX_SPEED) {
2320 baud = CYZ_MAX_SPEED;
2321 }
2322 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Jiri Slaby02f11752006-12-08 02:39:28 -08002324 if (baud == 134) {
2325 /* get it right for 134.5 baud */
2326 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2327 2;
Alan Cox77451e52008-07-16 21:57:02 +01002328 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002329 ASYNC_SPD_CUST) {
2330 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2331 baud_rate) + 2;
2332 } else if (baud) {
2333 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2334 baud) + 2;
2335 /* this needs to be propagated into the card info */
2336 } else {
2337 info->timeout = 0;
2338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
Jiri Slaby02f11752006-12-08 02:39:28 -08002340 /* byte size and parity */
2341 switch (cflag & CSIZE) {
2342 case CS5:
2343 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2344 break;
2345 case CS6:
2346 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2347 break;
2348 case CS7:
2349 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2350 break;
2351 case CS8:
2352 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2353 break;
2354 }
2355 if (cflag & CSTOPB) {
2356 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002357 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002358 } else {
2359 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002360 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002361 }
2362 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002363 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002364 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002365 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002366 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002367 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002368 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Jiri Slaby02f11752006-12-08 02:39:28 -08002370 /* CTS flow control flag */
2371 if (cflag & CRTSCTS) {
2372 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002373 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002374 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002375 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2376 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002377 }
2378 /* As the HW flow control is done in firmware, the driver
2379 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002380 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002381
2382 /* XON/XOFF/XANY flow control flags */
2383 sw_flow = 0;
2384 if (iflag & IXON) {
2385 sw_flow |= C_FL_OXX;
2386 if (iflag & IXANY)
2387 sw_flow |= C_FL_OIXANY;
2388 }
2389 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2390
Jiri Slaby875b2062007-05-08 00:36:49 -07002391 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002392 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002393 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2394 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002395 }
2396
2397 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002398 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002399 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002400 else
Alan Cox77451e52008-07-16 21:57:02 +01002401 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002402
2403 if (baud == 0) { /* baud rate is zero, turn off line */
2404 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002405 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002407 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002409 } else {
2410 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002411 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002413 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Alan Cox15ed6cc2008-04-30 00:53:55 -07002417 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002418 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002419 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2420 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
Jiri Slabyd13549f2009-09-19 13:13:12 -07002423 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002425} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
2427static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002428get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002429 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
Jiri Slaby02f11752006-12-08 02:39:28 -08002431 struct serial_struct tmp;
Jiri Slaby875b2062007-05-08 00:36:49 -07002432 struct cyclades_card *cinfo = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Jiri Slaby02f11752006-12-08 02:39:28 -08002434 if (!retinfo)
2435 return -EFAULT;
2436 memset(&tmp, 0, sizeof(tmp));
2437 tmp.type = info->type;
2438 tmp.line = info->line;
Jiri Slaby875b2062007-05-08 00:36:49 -07002439 tmp.port = (info->card - cy_card) * 0x100 + info->line -
2440 cinfo->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002441 tmp.irq = cinfo->irq;
Alan Cox77451e52008-07-16 21:57:02 +01002442 tmp.flags = info->port.flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01002443 tmp.close_delay = info->port.close_delay;
2444 tmp.closing_wait = info->port.closing_wait;
Jiri Slaby02f11752006-12-08 02:39:28 -08002445 tmp.baud_base = info->baud;
2446 tmp.custom_divisor = info->custom_divisor;
2447 tmp.hub6 = 0; /*!!! */
2448 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
2449} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002452cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002453 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454{
Jiri Slaby02f11752006-12-08 02:39:28 -08002455 struct serial_struct new_serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Jiri Slaby02f11752006-12-08 02:39:28 -08002457 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2458 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459
Jiri Slaby02f11752006-12-08 02:39:28 -08002460 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002461 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002462 new_serial.baud_base != info->baud ||
2463 (new_serial.flags & ASYNC_FLAGS &
2464 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002465 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Jiri Slaby02f11752006-12-08 02:39:28 -08002466 return -EPERM;
Alan Cox77451e52008-07-16 21:57:02 +01002467 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002468 (new_serial.flags & ASYNC_USR_MASK);
2469 info->baud = new_serial.baud_base;
2470 info->custom_divisor = new_serial.custom_divisor;
2471 goto check_and_exit;
2472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
Jiri Slaby02f11752006-12-08 02:39:28 -08002474 /*
2475 * OK, past this point, all the error checking has been done.
2476 * At this point, we start making changes.....
2477 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
Jiri Slaby02f11752006-12-08 02:39:28 -08002479 info->baud = new_serial.baud_base;
2480 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002481 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002482 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002483 info->port.close_delay = new_serial.close_delay * HZ / 100;
2484 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
2486check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002487 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002488 cy_set_line_char(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002489 return 0;
2490 } else {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002491 return cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002492 }
2493} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
2495/*
2496 * get_lsr_info - get line status register info
2497 *
2498 * Purpose: Let user call ioctl() to get info when the UART physically
2499 * is emptied. On bus types like RS485, the transmitter must
2500 * release the bus after transmitting. This must be done when
2501 * the transmit shift register is empty, not be done when the
2502 * transmit holding register is empty. This functionality
2503 * allows an RS485 driver to be written in user space.
2504 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002505static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506{
Jiri Slaby875b2062007-05-08 00:36:49 -07002507 struct cyclades_card *card;
2508 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002509 unsigned char status;
2510 unsigned int result;
2511 unsigned long flags;
2512 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
Jiri Slaby02f11752006-12-08 02:39:28 -08002514 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002515 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002516 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002517 chip = channel >> 2;
2518 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002519 index = card->bus_index;
2520 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002522 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002523 status = readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002524 (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002525 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002526 result = (status ? 0 : TIOCSER_TEMT);
2527 } else {
2528 /* Not supported yet */
2529 return -EINVAL;
2530 }
2531 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532}
2533
Jiri Slaby02f11752006-12-08 02:39:28 -08002534static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002536 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002537 struct cyclades_card *card;
2538 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002539 void __iomem *base_addr;
2540 unsigned long flags;
2541 unsigned char status;
2542 unsigned long lstatus;
2543 unsigned int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002545 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002546 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
Alan Cox7b130c02008-04-30 00:53:16 -07002548 lock_kernel();
2549
Jiri Slaby02f11752006-12-08 02:39:28 -08002550 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002551 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002552 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002553 chip = channel >> 2;
2554 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002555 index = card->bus_index;
2556 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002558 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002559 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002560 status = readb(base_addr + (CyMSVR1 << index));
2561 status |= readb(base_addr + (CyMSVR2 << index));
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002562 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
Jiri Slaby02f11752006-12-08 02:39:28 -08002564 if (info->rtsdtr_inv) {
2565 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2566 ((status & CyDTR) ? TIOCM_RTS : 0);
2567 } else {
2568 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2569 ((status & CyDTR) ? TIOCM_DTR : 0);
2570 }
2571 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2572 ((status & CyRI) ? TIOCM_RNG : 0) |
2573 ((status & CyDSR) ? TIOCM_DSR : 0) |
2574 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002576 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002577 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby02f11752006-12-08 02:39:28 -08002578 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2579 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2580 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2581 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2582 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2583 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
2584 } else {
2585 result = 0;
Alan Cox7b130c02008-04-30 00:53:16 -07002586 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002587 return -ENODEV;
2588 }
2589
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 }
Alan Cox7b130c02008-04-30 00:53:16 -07002591 unlock_kernel();
Jiri Slaby02f11752006-12-08 02:39:28 -08002592 return result;
2593} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595static int
2596cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08002597 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002599 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002600 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002601 unsigned long flags;
Jiri Slaby4d768202009-09-19 13:13:15 -07002602 int channel, retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002604 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002605 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Jiri Slaby02f11752006-12-08 02:39:28 -08002607 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002608 channel = (info->line) - (card->first_line);
Jiri Slaby2693f482009-06-11 12:31:06 +01002609 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002610 spin_lock_irqsave(&card->card_lock, flags);
2611 cyy_change_rts_dtr(info, set, clear);
2612 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002613 } else {
Jiri Slaby2693f482009-06-11 12:31:06 +01002614 if (cyz_is_loaded(card)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002615 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002616
2617 if (set & TIOCM_RTS) {
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_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002621 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002622 }
2623 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002624 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002625 cy_writel(&ch_ctrl->rs_control,
2626 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002627 ~C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002628 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002629 }
2630 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002631 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002632 cy_writel(&ch_ctrl->rs_control,
2633 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002634#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002635 printk(KERN_DEBUG "cyc:set_modem_info raising "
2636 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002637#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002638 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002639 }
2640 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002641 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002642 cy_writel(&ch_ctrl->rs_control,
2643 readl(&ch_ctrl->rs_control) &
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002644 ~C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002645#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002646 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2647 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002648#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002649 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002650 }
2651 } else {
2652 return -ENODEV;
2653 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002654 spin_lock_irqsave(&card->card_lock, flags);
2655 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002656 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002657 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2658 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002659 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002660 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002662 return 0;
2663} /* cy_tiocmset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
2665/*
2666 * cy_break() --- routine which turns the break handling on or off
2667 */
Alan Cox9e989662008-07-22 11:18:03 +01002668static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002670 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002671 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002672 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002673 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
Jiri Slaby02f11752006-12-08 02:39:28 -08002675 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002676 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002678 card = info->card;
2679
2680 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002681 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002682 /* Let the transmit ISR take care of this (since it
2683 requires stuffing characters into the output stream).
2684 */
2685 if (break_state == -1) {
2686 if (!info->breakon) {
2687 info->breakon = 1;
2688 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002689 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002690 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002691 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002692 }
2693 }
2694 } else {
2695 if (!info->breakoff) {
2696 info->breakoff = 1;
2697 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002698 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002699 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002700 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002701 }
2702 }
2703 }
2704 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002705 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002706 retval = cyz_issue_cmd(card,
2707 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002708 C_CM_SET_BREAK, 0L);
2709 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002710 printk(KERN_ERR "cyc:cy_break (set) retval on "
2711 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002712 }
2713 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002714 retval = cyz_issue_cmd(card,
2715 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002716 C_CM_CLR_BREAK, 0L);
2717 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002718 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2719 "on ttyC%d was %x\n", info->line,
2720 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002721 }
2722 }
2723 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002724 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002725 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002726} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
Alan Cox15ed6cc2008-04-30 00:53:55 -07002728static int get_mon_info(struct cyclades_port *info,
2729 struct cyclades_monitor __user *mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730{
Jiri Slaby02f11752006-12-08 02:39:28 -08002731 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
2732 return -EFAULT;
2733 info->mon.int_count = 0;
2734 info->mon.char_count = 0;
2735 info->mon.char_max = 0;
2736 info->mon.char_last = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002738} /* get_mon_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
Jiri Slaby02f11752006-12-08 02:39:28 -08002740static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741{
Jiri Slaby875b2062007-05-08 00:36:49 -07002742 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002743 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002744 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002745 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Jiri Slaby02f11752006-12-08 02:39:28 -08002747 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002748 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002749 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002750 chip = channel >> 2;
2751 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002752 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002753 base_addr =
Jiri Slaby875b2062007-05-08 00:36:49 -07002754 card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Jiri Slaby02f11752006-12-08 02:39:28 -08002756 info->cor3 &= ~CyREC_FIFO;
2757 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002759 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002760 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
2761 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002762 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002765} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Alan Cox15ed6cc2008-04-30 00:53:55 -07002767static int get_threshold(struct cyclades_port *info,
2768 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769{
Jiri Slaby875b2062007-05-08 00:36:49 -07002770 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002771 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002772 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002773 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
Jiri Slaby02f11752006-12-08 02:39:28 -08002775 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002776 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002777 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002778 chip = channel >> 2;
2779 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002780 index = card->bus_index;
2781 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002782
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002783 tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002784 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002785 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002786 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002787} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Alan Cox15ed6cc2008-04-30 00:53:55 -07002789static int set_default_threshold(struct cyclades_port *info,
2790 unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791{
Jiri Slaby02f11752006-12-08 02:39:28 -08002792 info->default_threshold = value & 0x0f;
2793 return 0;
2794} /* set_default_threshold */
2795
Alan Cox15ed6cc2008-04-30 00:53:55 -07002796static int get_default_threshold(struct cyclades_port *info,
2797 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002798{
2799 return put_user(info->default_threshold, value);
2800} /* get_default_threshold */
2801
2802static int set_timeout(struct cyclades_port *info, unsigned long value)
2803{
Jiri Slaby875b2062007-05-08 00:36:49 -07002804 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002805 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002806 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002807 unsigned long flags;
2808
2809 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002810 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002811 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002812 chip = channel >> 2;
2813 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002814 index = card->bus_index;
2815 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002816
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002817 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002818 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002819 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002820 }
2821 return 0;
2822} /* set_timeout */
2823
Alan Cox15ed6cc2008-04-30 00:53:55 -07002824static int get_timeout(struct cyclades_port *info,
2825 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002826{
Jiri Slaby875b2062007-05-08 00:36:49 -07002827 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002828 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002829 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002830 unsigned long tmp;
2831
2832 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002833 channel = info->line - card->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002834 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002835 chip = channel >> 2;
2836 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002837 index = card->bus_index;
2838 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08002839
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002840 tmp = readb(base_addr + (CyRTPR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08002841 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002842 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002843 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002844} /* get_timeout */
2845
2846static int set_default_timeout(struct cyclades_port *info, unsigned long value)
2847{
2848 info->default_timeout = value & 0xff;
2849 return 0;
2850} /* set_default_timeout */
2851
Alan Cox15ed6cc2008-04-30 00:53:55 -07002852static int get_default_timeout(struct cyclades_port *info,
2853 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002854{
2855 return put_user(info->default_timeout, value);
2856} /* get_default_timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
2858/*
2859 * This routine allows the tty driver to implement device-
2860 * specific ioctl's. If the ioctl number passed in cmd is
2861 * not recognized by the driver, it should return ENOIOCTLCMD.
2862 */
2863static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002864cy_ioctl(struct tty_struct *tty, struct file *file,
2865 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002867 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002868 struct cyclades_icount cprev, cnow; /* kernel counter temps */
2869 struct serial_icounter_struct __user *p_cuser; /* user space */
2870 int ret_val = 0;
2871 unsigned long flags;
2872 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
Jiri Slaby02f11752006-12-08 02:39:28 -08002874 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2875 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
2877#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002878 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2879 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880#endif
Alan Cox7b130c02008-04-30 00:53:16 -07002881 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
Jiri Slaby02f11752006-12-08 02:39:28 -08002883 switch (cmd) {
2884 case CYGETMON:
2885 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002887 case CYGETTHRESH:
2888 ret_val = get_threshold(info, argp);
2889 break;
2890 case CYSETTHRESH:
2891 ret_val = set_threshold(info, arg);
2892 break;
2893 case CYGETDEFTHRESH:
2894 ret_val = get_default_threshold(info, argp);
2895 break;
2896 case CYSETDEFTHRESH:
2897 ret_val = set_default_threshold(info, arg);
2898 break;
2899 case CYGETTIMEOUT:
2900 ret_val = get_timeout(info, argp);
2901 break;
2902 case CYSETTIMEOUT:
2903 ret_val = set_timeout(info, arg);
2904 break;
2905 case CYGETDEFTIMEOUT:
2906 ret_val = get_default_timeout(info, argp);
2907 break;
2908 case CYSETDEFTIMEOUT:
2909 ret_val = set_default_timeout(info, arg);
2910 break;
2911 case CYSETRFLOW:
2912 info->rflow = (int)arg;
2913 ret_val = 0;
2914 break;
2915 case CYGETRFLOW:
2916 ret_val = info->rflow;
2917 break;
2918 case CYSETRTSDTR_INV:
2919 info->rtsdtr_inv = (int)arg;
2920 ret_val = 0;
2921 break;
2922 case CYGETRTSDTR_INV:
2923 ret_val = info->rtsdtr_inv;
2924 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002926 ret_val = info->chip_rev;
2927 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928#ifndef CONFIG_CYZ_INTR
2929 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002930 cyz_polling_cycle = (arg * HZ) / 1000;
2931 ret_val = 0;
2932 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002934 ret_val = (cyz_polling_cycle * 1000) / HZ;
2935 break;
2936#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002938 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002939 ret_val = 0;
2940 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002942 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002943 break;
2944 case TIOCGSERIAL:
2945 ret_val = get_serial_info(info, argp);
2946 break;
2947 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002948 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002949 break;
2950 case TIOCSERGETLSR: /* Get line status register */
2951 ret_val = get_lsr_info(info, argp);
2952 break;
2953 /*
2954 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2955 * - mask passed in arg for lines of interest
2956 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2957 * Caller should use TIOCGICOUNT to see which one it was
2958 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002960 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002961 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002962 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002963 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002964 ret_val = wait_event_interruptible(info->delta_msr_wait, ({
2965 cprev = cnow;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002966 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002967 cnow = info->icount; /* atomic copy */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002968 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002970 ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2971 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2972 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2973 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
2974 }));
2975 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002976
2977 /*
2978 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2979 * Return: write counters to the user passed counter struct
2980 * NB: both 1->0 and 0->1 transitions are counted except for
2981 * RI where only 0->1 is counted.
2982 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 case TIOCGICOUNT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002984 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002985 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002986 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002987 p_cuser = argp;
2988 ret_val = put_user(cnow.cts, &p_cuser->cts);
2989 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002990 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002991 ret_val = put_user(cnow.dsr, &p_cuser->dsr);
2992 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002993 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002994 ret_val = put_user(cnow.rng, &p_cuser->rng);
2995 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002996 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002997 ret_val = put_user(cnow.dcd, &p_cuser->dcd);
2998 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07002999 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003000 ret_val = put_user(cnow.rx, &p_cuser->rx);
3001 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003002 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003003 ret_val = put_user(cnow.tx, &p_cuser->tx);
3004 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003005 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003006 ret_val = put_user(cnow.frame, &p_cuser->frame);
3007 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003008 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003009 ret_val = put_user(cnow.overrun, &p_cuser->overrun);
3010 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003011 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003012 ret_val = put_user(cnow.parity, &p_cuser->parity);
3013 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003014 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003015 ret_val = put_user(cnow.brk, &p_cuser->brk);
3016 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003017 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003018 ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
3019 if (ret_val)
Alan Cox7b130c02008-04-30 00:53:16 -07003020 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003021 ret_val = 0;
3022 break;
3023 default:
3024 ret_val = -ENOIOCTLCMD;
3025 }
Alan Cox7b130c02008-04-30 00:53:16 -07003026 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027
3028#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003029 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003031 return ret_val;
3032} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034/*
3035 * This routine allows the tty driver to be notified when
3036 * device's termios settings have changed. Note that a
3037 * well-designed tty driver should be prepared to accept the case
3038 * where old == NULL, and try to do something rational.
3039 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003040static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003042 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
3044#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003045 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046#endif
3047
Jiri Slabyd13549f2009-09-19 13:13:12 -07003048 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
Jiri Slaby02f11752006-12-08 02:39:28 -08003050 if ((old_termios->c_cflag & CRTSCTS) &&
3051 !(tty->termios->c_cflag & CRTSCTS)) {
3052 tty->hw_stopped = 0;
3053 cy_start(tty);
3054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08003056 /*
3057 * No need to wake up processes in open wait, since they
3058 * sample the CLOCAL flag once, and don't recheck it.
3059 * XXX It's not clear whether the current behavior is correct
3060 * or not. Hence, this may change.....
3061 */
3062 if (!(old_termios->c_cflag & CLOCAL) &&
3063 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01003064 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003066} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
3068/* This function is used to send a high-priority XON/XOFF character to
3069 the device.
3070*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003071static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003073 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003074 struct cyclades_card *card;
3075 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076
Jiri Slaby02f11752006-12-08 02:39:28 -08003077 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 return;
3079
Jiri Slaby02f11752006-12-08 02:39:28 -08003080 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081
3082 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08003083 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084
3085 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003086 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
Jiri Slaby2693f482009-06-11 12:31:06 +01003088 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003089 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003090 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003091 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07003092 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 }
3094}
3095
3096/* This routine is called by the upper-layer tty layer to signal
3097 that incoming characters should be throttled because the input
3098 buffers are close to full.
3099 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003100static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003102 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003103 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003104 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
3106#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003107 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108
Jiri Slaby21719192007-05-08 00:36:42 -07003109 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08003110 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111#endif
3112
Alan Cox15ed6cc2008-04-30 00:53:55 -07003113 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003114 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
Jiri Slaby02f11752006-12-08 02:39:28 -08003116 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
Jiri Slaby02f11752006-12-08 02:39:28 -08003118 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003119 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08003120 cy_send_xchar(tty, STOP_CHAR(tty));
3121 else
3122 info->throttle = 1;
3123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
Jiri Slaby02f11752006-12-08 02:39:28 -08003125 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01003126 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003127 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003128 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003129 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003130 } else {
3131 info->throttle = 1;
3132 }
3133 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003134} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
3136/*
3137 * This routine notifies the tty driver that it should signal
3138 * that characters can now be sent to the tty without fear of
3139 * overrunning the input buffers of the line disciplines.
3140 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003141static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003143 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003144 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003145 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
3147#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08003148 char buf[64];
3149
Jiri Slaby21719192007-05-08 00:36:42 -07003150 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07003151 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152#endif
3153
Alan Cox15ed6cc2008-04-30 00:53:55 -07003154 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08003155 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
Jiri Slaby02f11752006-12-08 02:39:28 -08003157 if (I_IXOFF(tty)) {
3158 if (info->x_char)
3159 info->x_char = 0;
3160 else
3161 cy_send_xchar(tty, START_CHAR(tty));
3162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
Jiri Slaby02f11752006-12-08 02:39:28 -08003164 if (tty->termios->c_cflag & CRTSCTS) {
3165 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01003166 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003167 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003168 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003169 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003170 } else {
3171 info->throttle = 0;
3172 }
3173 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003174} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176/* cy_start and cy_stop provide software output flow control as a
3177 function of XON/XOFF, software CTS, and other such stuff.
3178*/
Jiri Slaby02f11752006-12-08 02:39:28 -08003179static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180{
Jiri Slaby02f11752006-12-08 02:39:28 -08003181 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003182 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003183 void __iomem *base_addr;
3184 int chip, channel, index;
3185 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
3187#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003188 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189#endif
3190
Jiri Slaby02f11752006-12-08 02:39:28 -08003191 if (serial_paranoia_check(info, tty->name, "cy_stop"))
3192 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
Jiri Slaby875b2062007-05-08 00:36:49 -07003194 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003195 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003196 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003197 index = cinfo->bus_index;
3198 chip = channel >> 2;
3199 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003200 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003202 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003203 cy_writeb(base_addr + (CyCAR << index),
3204 (u_char)(channel & 0x0003)); /* index channel */
3205 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003206 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003207 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003209} /* cy_stop */
3210
3211static void cy_start(struct tty_struct *tty)
3212{
3213 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003214 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003215 void __iomem *base_addr;
3216 int chip, channel, index;
3217 unsigned long flags;
3218
3219#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003220 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08003221#endif
3222
3223 if (serial_paranoia_check(info, tty->name, "cy_start"))
3224 return;
3225
Jiri Slaby875b2062007-05-08 00:36:49 -07003226 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003227 channel = info->line - cinfo->first_line;
3228 index = cinfo->bus_index;
Jiri Slaby2693f482009-06-11 12:31:06 +01003229 if (!cy_is_Z(cinfo)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003230 chip = channel >> 2;
3231 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003232 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003233
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003234 spin_lock_irqsave(&cinfo->card_lock, flags);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003235 cy_writeb(base_addr + (CyCAR << index),
3236 (u_char) (channel & 0x0003)); /* index channel */
Jiri Slaby02f11752006-12-08 02:39:28 -08003237 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003238 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003239 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003240 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003241} /* cy_start */
3242
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243/*
3244 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3245 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003246static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003248 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003249
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003251 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252#endif
3253
Jiri Slaby02f11752006-12-08 02:39:28 -08003254 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3255 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256
Jiri Slaby02f11752006-12-08 02:39:28 -08003257 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003258 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003259 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003260} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
Jiri Slabyf0737572009-09-19 13:13:12 -07003262static int cyy_carrier_raised(struct tty_port *port)
3263{
3264 struct cyclades_port *info = container_of(port, struct cyclades_port,
3265 port);
3266 struct cyclades_card *cinfo = info->card;
3267 void __iomem *base = cinfo->base_addr;
3268 unsigned long flags;
3269 int channel = info->line - cinfo->first_line;
3270 int chip = channel >> 2, index = cinfo->bus_index;
3271 u32 cd;
3272
3273 channel &= 0x03;
3274 base += cy_chip_offset[chip] << index;
3275
3276 spin_lock_irqsave(&cinfo->card_lock, flags);
3277 cy_writeb(base + (CyCAR << index), (u8)channel);
3278 cd = readb(base + (CyMSVR1 << index)) & CyDCD;
3279 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3280
3281 return cd;
3282}
3283
3284static void cyy_dtr_rts(struct tty_port *port, int raise)
3285{
3286 struct cyclades_port *info = container_of(port, struct cyclades_port,
3287 port);
3288 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003289 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003290
3291 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003292 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3293 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003294 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3295}
3296
3297static int cyz_carrier_raised(struct tty_port *port)
3298{
3299 struct cyclades_port *info = container_of(port, struct cyclades_port,
3300 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003301
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003302 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003303}
3304
3305static void cyz_dtr_rts(struct tty_port *port, int raise)
3306{
3307 struct cyclades_port *info = container_of(port, struct cyclades_port,
3308 port);
3309 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003310 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003311 int ret, channel = info->line - cinfo->first_line;
3312 u32 rs;
3313
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003314 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003315 if (raise)
3316 rs |= C_RS_RTS | C_RS_DTR;
3317 else
3318 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003319 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003320 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3321 if (ret != 0)
3322 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3323 __func__, info->line, ret);
3324#ifdef CY_DEBUG_DTR
3325 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3326#endif
3327}
3328
3329static const struct tty_port_operations cyy_port_ops = {
3330 .carrier_raised = cyy_carrier_raised,
3331 .dtr_rts = cyy_dtr_rts,
3332};
3333
3334static const struct tty_port_operations cyz_port_ops = {
3335 .carrier_raised = cyz_carrier_raised,
3336 .dtr_rts = cyz_dtr_rts,
3337};
3338
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339/*
3340 * ---------------------------------------------------------------------
3341 * cy_init() and friends
3342 *
3343 * cy_init() is called at boot-time to initialize the serial driver.
3344 * ---------------------------------------------------------------------
3345 */
3346
Jiri Slabydd025c02007-05-08 00:37:02 -07003347static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003348{
3349 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003350 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003351
Jiri Slaby3046d502007-05-08 00:36:46 -07003352 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003353 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003354
Jiri Slaby963118e2009-06-11 12:34:27 +01003355 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3356 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003357 if (cinfo->ports == NULL) {
3358 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3359 return -ENOMEM;
3360 }
3361
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003362 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3363 channel++, port++) {
3364 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003365 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003366 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003367 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003368 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003369
Alan Cox44b7d1b2008-07-16 21:57:18 +01003370 info->port.closing_wait = CLOSING_WAIT_DELAY;
3371 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003372 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003373 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003374 init_waitqueue_head(&info->delta_msr_wait);
3375
Jiri Slaby2693f482009-06-11 12:31:06 +01003376 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003377 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3378 struct ZFW_CTRL *zfw_ctrl;
3379
Jiri Slabyf0737572009-09-19 13:13:12 -07003380 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003381 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003382
3383 zfw_ctrl = cinfo->base_addr +
3384 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3385 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3386 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3387
Jiri Slaby101b8152009-06-11 12:30:10 +01003388 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003389 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3390 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003391 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003392#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003393 setup_timer(&cyz_rx_full_timer[port],
3394 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003395#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003396 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003397 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003398 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003399
Jiri Slabyf0737572009-09-19 13:13:12 -07003400 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003401 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003402 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003403 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003404 info->cor2 = CyETC;
3405 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003406
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003407 chip_number = channel / CyPORTS_PER_CHIP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07003408 info->chip_rev = readb(cinfo->base_addr +
3409 (cy_chip_offset[chip_number] << index) +
3410 (CyGFRCR << index));
3411
3412 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003413 /* It is a CD1400 rev. J or later */
3414 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3415 info->tco = baud_co_60[13]; /* Tx CO */
3416 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3417 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003418 info->rtsdtr_inv = 1;
3419 } else {
3420 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3421 info->tco = baud_co_25[13]; /* Tx CO */
3422 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3423 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003424 info->rtsdtr_inv = 0;
3425 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003426 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3427 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003428 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003429
Jiri Slaby0809e262007-05-08 00:36:14 -07003430 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003431
3432#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003433 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003434 mod_timer(&cyz_timerlist, jiffies + 1);
3435#ifdef CY_PCI_DEBUG
3436 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3437#endif
3438 }
3439#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003440 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003441}
3442
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443/* initialize chips on Cyclom-Y card -- return number of valid
3444 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003445static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3446 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447{
Jiri Slaby02f11752006-12-08 02:39:28 -08003448 unsigned int chip_number;
3449 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
Jiri Slaby02f11752006-12-08 02:39:28 -08003451 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3452 /* Cy_HwReset is 0x1400 */
3453 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3454 /* Cy_ClrIntr is 0x1800 */
3455 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
Alan Cox15ed6cc2008-04-30 00:53:55 -07003457 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3458 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003459 base_addr =
3460 true_base_addr + (cy_chip_offset[chip_number] << index);
3461 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003462 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003463 /*************
3464 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3465 chip_number, (unsigned long)base_addr);
3466 *************/
3467 return chip_number;
3468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
Jiri Slaby02f11752006-12-08 02:39:28 -08003470 cy_writeb(base_addr + (CyGFRCR << index), 0);
3471 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
Jiri Slaby02f11752006-12-08 02:39:28 -08003473 /* The Cyclom-16Y does not decode address bit 9 and therefore
3474 cannot distinguish between references to chip 0 and a non-
3475 existent chip 4. If the preceding clearing of the supposed
3476 chip 4 GFRCR register appears at chip 0, there is no chip 4
3477 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3478 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003479 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003480 (cy_chip_offset[0] << index) +
3481 (CyGFRCR << index)) == 0) {
3482 return chip_number;
3483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
Jiri Slaby02f11752006-12-08 02:39:28 -08003485 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3486 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003488 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003489 /*
3490 printk(" chip #%d at %#6lx is not responding ",
3491 chip_number, (unsigned long)base_addr);
3492 printk("(GFRCR stayed 0)\n",
3493 */
3494 return chip_number;
3495 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003496 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003497 0x40) {
3498 /*
3499 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3500 "%#2x)\n",
3501 chip_number, (unsigned long)base_addr,
3502 base_addr[CyGFRCR<<index]);
3503 */
3504 return chip_number;
3505 }
3506 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003507 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003508 /* It is a CD1400 rev. J or later */
3509 /* Impossible to reach 5ms with this chip.
3510 Changed to 2ms instead (f = 500 Hz). */
3511 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3512 } else {
3513 /* f = 200 Hz */
3514 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3515 }
3516
3517 /*
3518 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3519 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003520 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003521 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003523 return chip_number;
3524} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
3526/*
3527 * ---------------------------------------------------------------------
3528 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3529 * sets global variables and return the number of ISA boards found.
3530 * ---------------------------------------------------------------------
3531 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003532static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533{
3534#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003535 unsigned short cy_isa_irq, nboard;
3536 void __iomem *cy_isa_address;
3537 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08003539 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540#endif
3541
Jiri Slaby02f11752006-12-08 02:39:28 -08003542 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
3544#ifdef MODULE
3545 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003546 for (i = 0; i < NR_CARDS; i++) {
3547 if (maddr[i] || i) {
3548 isparam = 1;
3549 cy_isa_addresses[i] = maddr[i];
3550 }
3551 if (!maddr[i])
3552 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 }
3554#endif
3555
Jiri Slaby02f11752006-12-08 02:39:28 -08003556 /* scan the address table probing for Cyclom-Y/ISA boards */
3557 for (i = 0; i < NR_ISA_ADDRS; i++) {
3558 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003559 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003560 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
Jiri Slaby02f11752006-12-08 02:39:28 -08003562 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003563 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003564 if (cy_isa_address == NULL) {
3565 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3566 "address\n");
3567 continue;
3568 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003569 cy_isa_nchan = CyPORTS_PER_CHIP *
3570 cyy_init_card(cy_isa_address, 0);
3571 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003572 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003573 continue;
3574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575#ifdef MODULE
3576 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003577 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 else
3579#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003580 /* find out the board's irq by probing */
3581 cy_isa_irq = detect_isa_irq(cy_isa_address);
3582 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003583 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3584 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003585 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003586 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003587 continue;
3588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
Jiri Slaby02f11752006-12-08 02:39:28 -08003590 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003591 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3592 "more channels are available. Change NR_PORTS "
3593 "in 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 }
3598 /* fill the next cy_card structure available */
3599 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003600 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003601 break;
3602 }
3603 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003604 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3605 "more cards can be used. Change NR_CARDS in "
3606 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003607 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003608 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003609 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
Jiri Slaby02f11752006-12-08 02:39:28 -08003612 /* allocate IRQ */
3613 if (request_irq(cy_isa_irq, cyy_interrupt,
3614 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003615 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3616 "could not allocate IRQ#%d.\n",
3617 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003618 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003619 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Jiri Slaby02f11752006-12-08 02:39:28 -08003622 /* set cy_card */
3623 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003624 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003625 cy_card[j].irq = (int)cy_isa_irq;
3626 cy_card[j].bus_index = 0;
3627 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003628 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3629 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003630 if (cy_init_card(&cy_card[j])) {
3631 cy_card[j].base_addr = NULL;
3632 free_irq(cy_isa_irq, &cy_card[j]);
3633 iounmap(cy_isa_address);
3634 continue;
3635 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003636 nboard++;
3637
Jiri Slaby21719192007-05-08 00:36:42 -07003638 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3639 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003640 j + 1, (unsigned long)cy_isa_address,
3641 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003642 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3643
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003644 for (j = cy_next_channel;
3645 j < cy_next_channel + cy_isa_nchan; j++)
3646 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003647 cy_next_channel += cy_isa_nchan;
3648 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003649 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003651 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003652#endif /* CONFIG_ISA */
3653} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654
Jiri Slaby58936d82007-05-08 00:36:13 -07003655#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003656static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3657{
3658 unsigned int a;
3659
3660 for (a = 0; a < size && *str; a++, str++)
3661 if (*str & 0x80)
3662 return -EINVAL;
3663
3664 for (; a < size; a++, str++)
3665 if (*str)
3666 return -EINVAL;
3667
3668 return 0;
3669}
3670
David Woodhousef61e7612008-05-23 23:57:19 +01003671static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003672 unsigned int size)
3673{
3674 for (; size > 0; size--) {
3675 cy_writel(fpga, *data++);
3676 udelay(10);
3677 }
3678}
3679
3680static void __devinit plx_init(struct pci_dev *pdev, int irq,
3681 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682{
Jiri Slaby02f11752006-12-08 02:39:28 -08003683 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003684 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003685 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003686 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687
Jiri Slaby02f11752006-12-08 02:39:28 -08003688 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003689 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003690 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003691 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3692
3693 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3694 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3695 * registers. This will remain here until we find a permanent fix.
3696 */
3697 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3698}
3699
3700static int __devinit __cyz_load_fw(const struct firmware *fw,
3701 const char *name, const u32 mailbox, void __iomem *base,
3702 void __iomem *fpga)
3703{
David Woodhousef61e7612008-05-23 23:57:19 +01003704 const void *ptr = fw->data;
3705 const struct zfile_header *h = ptr;
3706 const struct zfile_config *c, *cs;
3707 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003708 unsigned int a, tmp, len = fw->size;
3709#define BAD_FW KERN_ERR "Bad firmware: "
3710 if (len < sizeof(*h)) {
3711 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3712 return -EINVAL;
3713 }
3714
3715 cs = ptr + h->config_offset;
3716 bs = ptr + h->block_offset;
3717
3718 if ((void *)(cs + h->n_config) > ptr + len ||
3719 (void *)(bs + h->n_blocks) > ptr + len) {
3720 printk(BAD_FW "too short");
3721 return -EINVAL;
3722 }
3723
3724 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3725 cyc_isfwstr(h->date, sizeof(h->date))) {
3726 printk(BAD_FW "bad formatted header string\n");
3727 return -EINVAL;
3728 }
3729
3730 if (strncmp(name, h->name, sizeof(h->name))) {
3731 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3732 return -EINVAL;
3733 }
3734
3735 tmp = 0;
3736 for (c = cs; c < cs + h->n_config; c++) {
3737 for (a = 0; a < c->n_blocks; a++)
3738 if (c->block_list[a] > h->n_blocks) {
3739 printk(BAD_FW "bad block ref number in cfgs\n");
3740 return -EINVAL;
3741 }
3742 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3743 tmp++;
3744 }
3745 if (!tmp) {
3746 printk(BAD_FW "nothing appropriate\n");
3747 return -EINVAL;
3748 }
3749
3750 for (b = bs; b < bs + h->n_blocks; b++)
3751 if (b->file_offset + b->size > len) {
3752 printk(BAD_FW "bad block data offset\n");
3753 return -EINVAL;
3754 }
3755
3756 /* everything is OK, let's seek'n'load it */
3757 for (c = cs; c < cs + h->n_config; c++)
3758 if (c->mailbox == mailbox && c->function == 0)
3759 break;
3760
3761 for (a = 0; a < c->n_blocks; a++) {
3762 b = &bs[c->block_list[a]];
3763 if (b->type == ZBLOCK_FPGA) {
3764 if (fpga != NULL)
3765 cyz_fpga_copy(fpga, ptr + b->file_offset,
3766 b->size);
3767 } else {
3768 if (base != NULL)
3769 memcpy_toio(base + b->ram_offset,
3770 ptr + b->file_offset, b->size);
3771 }
3772 }
3773#undef BAD_FW
3774 return 0;
3775}
3776
3777static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3778 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3779{
3780 const struct firmware *fw;
3781 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3782 struct CUSTOM_REG __iomem *cust = base_addr;
3783 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003784 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003785 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003786 unsigned int i;
3787 int retval;
3788
3789 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3790 if (retval) {
3791 dev_err(&pdev->dev, "can't get firmware\n");
3792 goto err;
3793 }
3794
3795 /* Check whether the firmware is already loaded and running. If
3796 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003797 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003798 u32 cntval = readl(base_addr + 0x190);
3799
3800 udelay(100);
3801 if (cntval != readl(base_addr + 0x190)) {
3802 /* FW counter is working, FW is running */
3803 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3804 "Skipping board.\n");
3805 retval = 0;
3806 goto err_rel;
3807 }
3808 }
3809
3810 /* start boot */
3811 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3812 ~0x00030800UL);
3813
3814 mailbox = readl(&ctl_addr->mail_box_0);
3815
Jiri Slaby2693f482009-06-11 12:31:06 +01003816 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003817 /* stops CPU and set window to beginning of RAM */
3818 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3819 cy_writel(&cust->cpu_stop, 0);
3820 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3821 udelay(100);
3822 }
3823
3824 plx_init(pdev, irq, ctl_addr);
3825
3826 if (mailbox != 0) {
3827 /* load FPGA */
3828 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3829 base_addr);
3830 if (retval)
3831 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003832 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003833 dev_err(&pdev->dev, "fw upload successful, but fw is "
3834 "not loaded\n");
3835 goto err_rel;
3836 }
3837 }
3838
3839 /* stops CPU and set window to beginning of RAM */
3840 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3841 cy_writel(&cust->cpu_stop, 0);
3842 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3843 udelay(100);
3844
3845 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003846 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003847 cy_writeb(tmp, 255);
3848 if (mailbox != 0) {
3849 /* set window to last 512K of RAM */
3850 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003851 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003852 cy_writeb(tmp, 255);
3853 /* set window to beginning of RAM */
3854 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003855 }
3856
3857 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3858 release_firmware(fw);
3859 if (retval)
3860 goto err;
3861
3862 /* finish boot and start boards */
3863 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3864 cy_writel(&cust->cpu_start, 0);
3865 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3866 i = 0;
3867 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3868 msleep(100);
3869 if (status != ZFIRM_ID) {
3870 if (status == ZFIRM_HLT) {
3871 dev_err(&pdev->dev, "you need an external power supply "
3872 "for this number of ports. Firmware halted and "
3873 "board reset.\n");
3874 retval = -EIO;
3875 goto err;
3876 }
3877 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3878 "some more time\n", status);
3879 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3880 i++ < 200)
3881 msleep(100);
3882 if (status != ZFIRM_ID) {
3883 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3884 "Giving up. (fid->signature = 0x%x)\n",
3885 status);
3886 dev_info(&pdev->dev, "*** Warning ***: if you are "
3887 "upgrading the FW, please power cycle the "
3888 "system before loading the new FW to the "
3889 "Cyclades-Z.\n");
3890
Jiri Slaby2693f482009-06-11 12:31:06 +01003891 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003892 plx_init(pdev, irq, ctl_addr);
3893
3894 retval = -EIO;
3895 goto err;
3896 }
3897 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3898 i / 10);
3899 }
3900 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3901
3902 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3903 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3904 base_addr + readl(&fid->zfwctrl_addr));
3905
Jiri Slaby963118e2009-06-11 12:34:27 +01003906 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003907 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003908 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003909
Jiri Slaby963118e2009-06-11 12:34:27 +01003910 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003911 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3912 "check the connection between the Z host card and the "
3913 "serial expanders.\n");
3914
Jiri Slaby2693f482009-06-11 12:31:06 +01003915 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003916 plx_init(pdev, irq, ctl_addr);
3917
3918 dev_info(&pdev->dev, "Null number of ports detected. Board "
3919 "reset.\n");
3920 retval = 0;
3921 goto err;
3922 }
3923
3924 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3925 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3926
3927 /*
3928 Early firmware failed to start looking for commands.
3929 This enables firmware interrupts for those commands.
3930 */
3931 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3932 (1 << 17));
3933 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3934 0x00030800UL);
3935
Jiri Slaby963118e2009-06-11 12:34:27 +01003936 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003937err_rel:
3938 release_firmware(fw);
3939err:
3940 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941}
3942
Jiri Slaby58936d82007-05-08 00:36:13 -07003943static int __devinit cy_pci_probe(struct pci_dev *pdev,
3944 const struct pci_device_id *ent)
3945{
Jiri Slaby31375532007-05-08 00:37:04 -07003946 void __iomem *addr0 = NULL, *addr2 = NULL;
3947 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003948 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003949 unsigned int device_id, nchan = 0, card_no, i;
3950 unsigned char plx_ver;
3951 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003952
3953 retval = pci_enable_device(pdev);
3954 if (retval) {
3955 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003956 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003957 }
3958
3959 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003960 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003961 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3962
Jiri Slaby31375532007-05-08 00:37:04 -07003963#if defined(__alpha__)
3964 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3965 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3966 "addresses on Alpha systems.\n");
3967 retval = -EIO;
3968 goto err_dis;
3969 }
3970#endif
3971 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3972 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3973 "addresses\n");
3974 retval = -EIO;
3975 goto err_dis;
3976 }
3977
3978 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3979 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3980 "it...\n");
3981 pdev->resource[2].flags &= ~IORESOURCE_IO;
3982 }
3983
3984 retval = pci_request_regions(pdev, "cyclades");
3985 if (retval) {
3986 dev_err(&pdev->dev, "failed to reserve resources\n");
3987 goto err_dis;
3988 }
3989
3990 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003991 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3992 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003993 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003994
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003995 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3996 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003997 if (addr0 == NULL) {
3998 dev_err(&pdev->dev, "can't remap ctl region\n");
3999 goto err_reg;
4000 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004001 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
4002 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07004003 if (addr2 == NULL) {
4004 dev_err(&pdev->dev, "can't remap base region\n");
4005 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004006 }
4007
Jiri Slaby31375532007-05-08 00:37:04 -07004008 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
4009 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07004010 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
4011 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00004012 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004013 }
Jiri Slaby31375532007-05-08 00:37:04 -07004014 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
4015 struct RUNTIME_9060 __iomem *ctl_addr;
4016
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004017 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
4018 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07004019 if (addr0 == NULL) {
4020 dev_err(&pdev->dev, "can't remap ctl region\n");
4021 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07004022 }
4023
Jiri Slaby31375532007-05-08 00:37:04 -07004024 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004025 cy_writew(&ctl_addr->intr_ctrl_stat,
4026 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07004027
Jiri Slaby054f5b02007-07-17 04:05:16 -07004028 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004029
Jiri Slaby101b8152009-06-11 12:30:10 +01004030 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07004031
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004032 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
4033 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07004034 if (addr2 == NULL) {
4035 dev_err(&pdev->dev, "can't remap base region\n");
4036 goto err_unmap;
4037 }
4038
4039 if (mailbox == ZE_V1) {
4040 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07004041 } else {
4042 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07004043#ifdef CY_PCI_DEBUG
4044 if (mailbox == ZO_V1) {
4045 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
4046 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
4047 "id %lx, ver %lx\n", (ulong)(0xff &
4048 readl(&((struct CUSTOM_REG *)addr2)->
4049 fpga_id)), (ulong)(0xff &
4050 readl(&((struct CUSTOM_REG *)addr2)->
4051 fpga_version)));
4052 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4053 } else {
4054 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
4055 "Cyclades-Z board. FPGA not loaded\n");
4056 }
4057#endif
4058 /* The following clears the firmware id word. This
4059 ensures that the driver will not attempt to talk to
4060 the board until it has been properly initialized.
4061 */
4062 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
4063 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07004064 }
Jiri Slabyace08c32009-06-11 12:20:38 +01004065
4066 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01004067 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01004068 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01004069 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07004070 }
4071
4072 if ((cy_next_channel + nchan) > NR_PORTS) {
4073 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4074 "channels are available. Change NR_PORTS in "
4075 "cyclades.c and recompile kernel.\n");
4076 goto err_unmap;
4077 }
4078 /* fill the next cy_card structure available */
4079 for (card_no = 0; card_no < NR_CARDS; card_no++) {
4080 if (cy_card[card_no].base_addr == NULL)
4081 break;
4082 }
4083 if (card_no == NR_CARDS) { /* no more cy_cards available */
4084 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
4085 "more cards can be used. Change NR_CARDS in "
4086 "cyclades.c and recompile kernel.\n");
4087 goto err_unmap;
4088 }
4089
4090 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4091 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004092 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07004093 retval = request_irq(irq, cyy_interrupt,
4094 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07004095 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07004096 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004097 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07004098 }
Jiri Slaby963118e2009-06-11 12:34:27 +01004099 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07004100 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004101 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
4102 struct ZFW_CTRL __iomem *zfw_ctrl;
4103
4104 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4105
Jiri Slaby101b8152009-06-11 12:30:10 +01004106 cy_card[card_no].hw_ver = mailbox;
4107 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07004108 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07004109#ifdef CONFIG_CYZ_INTR
4110 /* allocate IRQ only if board has an IRQ */
4111 if (irq != 0 && irq != 255) {
4112 retval = request_irq(irq, cyz_interrupt,
4113 IRQF_SHARED, "Cyclades-Z",
4114 &cy_card[card_no]);
4115 if (retval) {
4116 dev_err(&pdev->dev, "could not allocate IRQ\n");
4117 goto err_unmap;
4118 }
4119 }
4120#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07004121 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004122
Jiri Slaby31375532007-05-08 00:37:04 -07004123 /* set cy_card */
4124 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01004125 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07004126 cy_card[card_no].irq = irq;
4127 cy_card[card_no].bus_index = 1;
4128 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01004129 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07004130 retval = cy_init_card(&cy_card[card_no]);
4131 if (retval)
4132 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07004133
Jiri Slaby31375532007-05-08 00:37:04 -07004134 pci_set_drvdata(pdev, &cy_card[card_no]);
4135
4136 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4137 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07004138 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07004139 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07004140 switch (plx_ver) {
4141 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07004142 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07004143 break;
4144
4145 case PLX_9060:
4146 case PLX_9080:
4147 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01004148 {
4149 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
4150 plx_init(pdev, irq, ctl_addr);
4151 cy_writew(&ctl_addr->intr_ctrl_stat,
4152 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07004153 break;
4154 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01004155 }
Jiri Slaby58936d82007-05-08 00:36:13 -07004156 }
4157
Jiri Slaby31375532007-05-08 00:37:04 -07004158 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
4159 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
4160 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
4161 tty_register_device(cy_serial_driver, i, &pdev->dev);
4162 cy_next_channel += nchan;
4163
Jiri Slaby58936d82007-05-08 00:36:13 -07004164 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07004165err_null:
4166 cy_card[card_no].base_addr = NULL;
4167 free_irq(irq, &cy_card[card_no]);
4168err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004169 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07004170 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004171 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07004172err_reg:
4173 pci_release_regions(pdev);
4174err_dis:
4175 pci_disable_device(pdev);
4176err:
4177 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07004178}
Jiri Slaby58936d82007-05-08 00:36:13 -07004179
Jiri Slaby6747cd92007-05-08 00:36:34 -07004180static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181{
Jiri Slaby38d09092007-05-08 00:36:10 -07004182 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07004183 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07004184
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004185 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01004186 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07004187 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01004188 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004189 else
4190#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004191 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004192#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01004193 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
4194 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
4195 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004196
Jiri Slaby24e6fd42008-10-13 10:34:09 +01004197 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004198 if (cinfo->ctl_addr.p9050)
4199 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07004200 if (cinfo->irq
4201#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004202 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07004203#endif /* CONFIG_CYZ_INTR */
4204 )
4205 free_irq(cinfo->irq, cinfo);
4206 pci_release_regions(pdev);
4207
4208 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004209 for (i = cinfo->first_line; i < cinfo->first_line +
4210 cinfo->nports; i++)
4211 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07004212 cinfo->nports = 0;
4213 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07004214}
4215
Jiri Slaby6747cd92007-05-08 00:36:34 -07004216static struct pci_driver cy_pci_driver = {
4217 .name = "cyclades",
4218 .id_table = cy_pci_dev_id,
4219 .probe = cy_pci_probe,
4220 .remove = __devexit_p(cy_pci_remove)
4221};
4222#endif
4223
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004224static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225{
Jiri Slaby02f11752006-12-08 02:39:28 -08004226 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07004227 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08004228 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004230 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08004231 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
Jiri Slaby02f11752006-12-08 02:39:28 -08004233 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07004234 for (i = 0; i < NR_CARDS; i++)
4235 for (j = 0; j < cy_card[i].nports; j++) {
4236 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08004237
Jiri Slabyd13549f2009-09-19 13:13:12 -07004238 if (info->port.count) {
4239 /* XXX is the ldisc num worth this? */
4240 struct tty_struct *tty;
4241 struct tty_ldisc *ld;
4242 int num = 0;
4243 tty = tty_port_tty_get(&info->port);
4244 if (tty) {
4245 ld = tty_ldisc_ref(tty);
4246 if (ld) {
4247 num = ld->ops->num;
4248 tty_ldisc_deref(ld);
4249 }
4250 tty_kref_put(tty);
4251 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004252 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004253 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004254 (cur_jifs - info->idle_stats.in_use) /
4255 HZ, info->idle_stats.xmit_bytes,
4256 (cur_jifs - info->idle_stats.xmit_idle)/
4257 HZ, info->idle_stats.recv_bytes,
4258 (cur_jifs - info->idle_stats.recv_idle)/
4259 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004260 num);
4261 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004262 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004263 "%10lu %8lu %9lu %6ld\n",
4264 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004265 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004266 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267}
4268
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004269static int cyclades_proc_open(struct inode *inode, struct file *file)
4270{
4271 return single_open(file, cyclades_proc_show, NULL);
4272}
4273
4274static const struct file_operations cyclades_proc_fops = {
4275 .owner = THIS_MODULE,
4276 .open = cyclades_proc_open,
4277 .read = seq_read,
4278 .llseek = seq_lseek,
4279 .release = single_release,
4280};
4281
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282/* The serial driver boot-time initialization code!
4283 Hardware I/O ports are mapped to character special devices on a
4284 first found, first allocated manner. That is, this code searches
4285 for Cyclom cards in the system. As each is found, it is probed
4286 to discover how many chips (and thus how many ports) are present.
4287 These ports are mapped to the tty ports 32 and upward in monotonic
4288 fashion. If an 8-port card is replaced with a 16-port card, the
4289 port mapping on a following card will shift.
4290
4291 This approach is different from what is used in the other serial
4292 device driver because the Cyclom is more properly a multiplexer,
4293 not just an aggregation of serial ports on one card.
4294
4295 If there are more cards with more ports than have been
4296 statically allocated above, a warning is printed and the
4297 extra ports are ignored.
4298 */
4299
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004300static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004301 .open = cy_open,
4302 .close = cy_close,
4303 .write = cy_write,
4304 .put_char = cy_put_char,
4305 .flush_chars = cy_flush_chars,
4306 .write_room = cy_write_room,
4307 .chars_in_buffer = cy_chars_in_buffer,
4308 .flush_buffer = cy_flush_buffer,
4309 .ioctl = cy_ioctl,
4310 .throttle = cy_throttle,
4311 .unthrottle = cy_unthrottle,
4312 .set_termios = cy_set_termios,
4313 .stop = cy_stop,
4314 .start = cy_start,
4315 .hangup = cy_hangup,
4316 .break_ctl = cy_break,
4317 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004318 .tiocmget = cy_tiocmget,
4319 .tiocmset = cy_tiocmset,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004320 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321};
4322
Jiri Slaby02f11752006-12-08 02:39:28 -08004323static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324{
Jiri Slabydd025c02007-05-08 00:37:02 -07004325 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004326 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Jiri Slaby02f11752006-12-08 02:39:28 -08004328 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4329 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004330 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004331
4332 printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
4333 __DATE__, __TIME__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Jiri Slaby02f11752006-12-08 02:39:28 -08004335 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Jiri Slaby02f11752006-12-08 02:39:28 -08004337 cy_serial_driver->owner = THIS_MODULE;
4338 cy_serial_driver->driver_name = "cyclades";
4339 cy_serial_driver->name = "ttyC";
4340 cy_serial_driver->major = CYCLADES_MAJOR;
4341 cy_serial_driver->minor_start = 0;
4342 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4343 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4344 cy_serial_driver->init_termios = tty_std_termios;
4345 cy_serial_driver->init_termios.c_cflag =
4346 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004347 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004348 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004350 retval = tty_register_driver(cy_serial_driver);
4351 if (retval) {
4352 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4353 goto err_frtty;
4354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Jiri Slaby02f11752006-12-08 02:39:28 -08004356 /* the code below is responsible to find the boards. Each different
4357 type of board has its own detection routine. If a board is found,
4358 the next cy_card structure available is set by the detection
4359 routine. These functions are responsible for checking the
4360 availability of cy_card and cy_port data structures and updating
4361 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
Jiri Slaby02f11752006-12-08 02:39:28 -08004363 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004364 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365
Jiri Slaby6747cd92007-05-08 00:36:34 -07004366#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004367 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004368 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004369 if (retval && !nboards) {
4370 tty_unregister_driver(cy_serial_driver);
4371 goto err_frtty;
4372 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004373#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004374
4375 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004376err_frtty:
4377 put_tty_driver(cy_serial_driver);
4378err:
4379 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004380} /* cy_init */
4381
4382static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
Jiri Slabydd025c02007-05-08 00:37:02 -07004384 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004385 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
4387#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004388 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389#endif /* CONFIG_CYZ_INTR */
4390
Alan Cox15ed6cc2008-04-30 00:53:55 -07004391 e1 = tty_unregister_driver(cy_serial_driver);
4392 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004393 printk(KERN_ERR "failed to unregister Cyclades serial "
4394 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395
Jiri Slaby6747cd92007-05-08 00:36:34 -07004396#ifdef CONFIG_PCI
4397 pci_unregister_driver(&cy_pci_driver);
4398#endif
4399
Jiri Slaby02f11752006-12-08 02:39:28 -08004400 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004401 card = &cy_card[i];
4402 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004403 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004404 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4405 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004406 if (card->ctl_addr.p9050)
4407 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004408 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004410 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004412 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004413 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004414 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004415 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004416 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004417 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004418 }
4419 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004420
4421 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422} /* cy_cleanup_module */
4423
4424module_init(cy_init);
4425module_exit(cy_cleanup_module);
4426
4427MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004428MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad2009-04-06 17:33:04 +01004429MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);