blob: c0e8f2eeb88697b390787d1f210411ae6521c1cd [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/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * This file contains the driver for the Cyclades async multiport
7 * serial boards.
8 *
9 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
10 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Jiri Slabyebdb5132009-09-19 13:13:14 -070012 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 * Much of the design and some of the code came from serial.c
15 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
16 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
17 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070018 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21
Jiri Slabyebdb5132009-09-19 13:13:14 -070022#define CY_VERSION "2.6"
Jiri Slaby096dcfc2006-12-08 02:39:30 -080023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024/* If you need to install more boards than NR_CARDS, change the constant
25 in the definition below. No other change is necessary to support up to
26 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
27
Jiri Slaby02f11752006-12-08 02:39:28 -080028#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30/*
31 If the total number of ports is larger than NR_PORTS, change this
32 constant in the definition below. No other change is necessary to
33 support more boards/ports. */
34
Jiri Slaby02f11752006-12-08 02:39:28 -080035#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define ZO_V1 0
38#define ZO_V2 1
39#define ZE_V1 2
40
41#define SERIAL_PARANOIA_CHECK
42#undef CY_DEBUG_OPEN
43#undef CY_DEBUG_THROTTLE
44#undef CY_DEBUG_OTHER
45#undef CY_DEBUG_IO
46#undef CY_DEBUG_COUNT
47#undef CY_DEBUG_DTR
48#undef CY_DEBUG_WAIT_UNTIL_SENT
49#undef CY_DEBUG_INTERRUPTS
50#undef CY_16Y_HACK
51#undef CY_ENABLE_MONITORING
52#undef CY_PCI_DEBUG
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054/*
Alan Cox15ed6cc2008-04-30 00:53:55 -070055 * Include section
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/module.h>
58#include <linux/errno.h>
59#include <linux/signal.h>
60#include <linux/sched.h>
61#include <linux/timer.h>
62#include <linux/interrupt.h>
63#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -080064#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <linux/serial.h>
66#include <linux/major.h>
67#include <linux/string.h>
68#include <linux/fcntl.h>
69#include <linux/ptrace.h>
70#include <linux/cyclades.h>
71#include <linux/mm.h>
72#include <linux/ioport.h>
73#include <linux/init.h>
74#include <linux/delay.h>
75#include <linux/spinlock.h>
76#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -070077#include <linux/firmware.h>
Scott James Remnant9f56fad2009-04-06 17:33:04 +010078#include <linux/device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090079#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Alan Cox15ed6cc2008-04-30 00:53:55 -070081#include <linux/io.h>
Alan Cox15ed6cc2008-04-30 00:53:55 -070082#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#include <linux/kernel.h>
85#include <linux/pci.h>
86
87#include <linux/stat.h>
88#include <linux/proc_fs.h>
Alexey Dobriyan444697d2009-03-31 15:19:15 -070089#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Jiri Slaby02f11752006-12-08 02:39:28 -080091static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#ifndef SERIAL_XMIT_SIZE
94#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
95#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97#define STD_COM_FLAGS (0)
98
Jiri Slaby054f5b02007-07-17 04:05:16 -070099/* firmware stuff */
100#define ZL_MAX_BLOCKS 16
101#define DRIVER_VERSION 0x02010203
102#define RAM_SIZE 0x80000
103
Jiri Slaby054f5b02007-07-17 04:05:16 -0700104enum zblock_type {
105 ZBLOCK_PRG = 0,
106 ZBLOCK_FPGA = 1
107};
108
109struct zfile_header {
110 char name[64];
111 char date[32];
112 char aux[32];
113 u32 n_config;
114 u32 config_offset;
115 u32 n_blocks;
116 u32 block_offset;
117 u32 reserved[9];
118} __attribute__ ((packed));
119
120struct zfile_config {
121 char name[64];
122 u32 mailbox;
123 u32 function;
124 u32 n_blocks;
125 u32 block_list[ZL_MAX_BLOCKS];
126} __attribute__ ((packed));
127
128struct zfile_block {
129 u32 type;
130 u32 file_offset;
131 u32 ram_offset;
132 u32 size;
133} __attribute__ ((packed));
134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135static struct tty_driver *cy_serial_driver;
136
137#ifdef CONFIG_ISA
138/* This is the address lookup table. The driver will probe for
139 Cyclom-Y/ISA boards at all addresses in here. If you want the
140 driver to probe addresses at a different address, add it to
141 this table. If the driver is probing some other board and
142 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143*/
144
145static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800146 0xD0000,
147 0xD2000,
148 0xD4000,
149 0xD6000,
150 0xD8000,
151 0xDA000,
152 0xDC000,
153 0xDE000,
154 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155};
Jiri Slaby02f11752006-12-08 02:39:28 -0800156
Tobias Klauserfe971072006-01-09 20:54:02 -0800157#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Jiri Slaby3046d502007-05-08 00:36:46 -0700159static long maddr[NR_CARDS];
160static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162module_param_array(maddr, long, NULL, 0);
163module_param_array(irq, int, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Jiri Slaby02f11752006-12-08 02:39:28 -0800165#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167/* This is the per-card data structure containing address, irq, number of
168 channels, etc. This driver supports a maximum of NR_CARDS cards.
169*/
170static struct cyclades_card cy_card[NR_CARDS];
171
Jiri Slaby02f11752006-12-08 02:39:28 -0800172static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 * This is used to look up the divisor speeds and the timeouts
176 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100177 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
179 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
180 * HI VHI
181 * 20
182 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700183static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800184 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
185 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
186 230400, 0
187};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Jiri Slabyebdb5132009-09-19 13:13:14 -0700189static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800190 /* value => 00 01 02 03 04 */
191 /* divide by 8 32 128 512 2048 */
192 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
193 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
194};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Jiri Slabyebdb5132009-09-19 13:13:14 -0700196static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800197 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
198 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
199};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Jiri Slabyebdb5132009-09-19 13:13:14 -0700201static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800202 /* value => 00 01 02 03 04 */
203 /* divide by 8 32 128 512 2048 */
204 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
205 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00
207};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Jiri Slabyebdb5132009-09-19 13:13:14 -0700209static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800210 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
211 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
212 0x21
213};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Jiri Slabyebdb5132009-09-19 13:13:14 -0700215static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800216 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
217 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
218 0x07
219};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221/*
222 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700223 * The cyclades_port structure member rflow and the vector rflow_thr
224 * allows us to take advantage of a special feature in the CD1400 to avoid
225 * data loss even when the system interrupt latency is too high. These flags
226 * are to be used only with very special applications. Setting these flags
227 * requires the use of a special cable (DTR and RTS reversed). In the new
228 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 * cables.
230 */
231
Jiri Slabyebdb5132009-09-19 13:13:14 -0700232static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
235 0x0a
236};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238/* The Cyclom-Ye has placed the sequential chips in non-sequential
239 * address order. This look-up table overcomes that problem.
240 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700241static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800242 0x0400,
243 0x0800,
244 0x0C00,
245 0x0200,
246 0x0600,
247 0x0A00,
248 0x0E00
249};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251/* PCI related definitions */
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700254static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700255 /* PCI < 1Mb */
256 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
257 /* PCI > 1Mb */
258 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
259 /* 4Y PCI < 1Mb */
260 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
261 /* 4Y PCI > 1Mb */
262 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
263 /* 8Y PCI < 1Mb */
264 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
265 /* 8Y PCI > 1Mb */
266 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
267 /* Z PCI < 1Mb */
268 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
269 /* Z PCI > 1Mb */
270 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800271 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800272};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800273MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274#endif
275
276static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700277static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700278static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#ifdef CONFIG_ISA
280static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800281#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283#ifndef CONFIG_CYZ_INTR
284static void cyz_poll(unsigned long);
285
286/* The Cyclades-Z polling cycle is defined by this variable */
287static long cyz_polling_cycle = CZ_DEF_POLL;
288
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700289static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Jiri Slaby02f11752006-12-08 02:39:28 -0800291#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292static void cyz_rx_restart(unsigned long);
293static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800294#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700296static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
297{
298 struct cyclades_card *card = port->card;
299
300 cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
301}
302
303static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
304{
305 struct cyclades_card *card = port->card;
306
307 return readb(port->u.cyy.base_addr + (reg << card->bus_index));
308}
309
Jiri Slaby2693f482009-06-11 12:31:06 +0100310static inline bool cy_is_Z(struct cyclades_card *card)
311{
312 return card->num_chips == (unsigned int)-1;
313}
314
315static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
316{
317 return readl(&ctl_addr->init_ctrl) & (1 << 17);
318}
319
320static inline bool cyz_fpga_loaded(struct cyclades_card *card)
321{
322 return __cyz_fpga_loaded(card->ctl_addr.p9060);
323}
324
325static inline bool cyz_is_loaded(struct cyclades_card *card)
326{
327 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
328
329 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
330 readl(&fw_id->signature) == ZFIRM_ID;
331}
332
Jiri Slaby02f11752006-12-08 02:39:28 -0800333static inline int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700334 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800337 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700338 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
339 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800340 return 1;
341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Jiri Slaby02f11752006-12-08 02:39:28 -0800343 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700344 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
345 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800346 return 1;
347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800349 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700350}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/***********************************************************/
353/********* Start of block of Cyclom-Y specific code ********/
354
355/* This routine waits up to 1000 micro-seconds for the previous
356 command to the Cirrus chip to complete and then issues the
357 new command. An error is returned if the previous command
358 didn't finish within the time limit.
359
360 This function is only called from inside spinlock-protected code.
361 */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700362static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700364 void __iomem *ccr = base_addr + (CyCCR << index);
Jiri Slabyad39c302007-05-08 00:35:49 -0700365 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Jiri Slaby02f11752006-12-08 02:39:28 -0800367 /* Check to see that the previous command has completed */
368 for (i = 0; i < 100; i++) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700369 if (readb(ccr) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800370 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800371 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800373 /* if the CCR never cleared, the previous command
374 didn't finish within the "reasonable time" */
375 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800376 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Jiri Slaby02f11752006-12-08 02:39:28 -0800378 /* Issue the new command */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700379 cy_writeb(ccr, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800381 return 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700382}
383
384static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
385{
386 return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
387 port->card->bus_index);
388}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390#ifdef CONFIG_ISA
391/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700392static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
Jiri Slaby02f11752006-12-08 02:39:28 -0800394 int irq;
395 unsigned long irqs, flags;
396 int save_xir, save_car;
397 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Jiri Slaby02f11752006-12-08 02:39:28 -0800399 /* forget possible initially masked and pending IRQ */
400 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Jiri Slaby02f11752006-12-08 02:39:28 -0800402 /* Clear interrupts on the board first */
403 cy_writeb(address + (Cy_ClrIntr << index), 0);
404 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Jiri Slaby02f11752006-12-08 02:39:28 -0800406 irqs = probe_irq_on();
407 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700408 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Jiri Slaby02f11752006-12-08 02:39:28 -0800410 /* Enable the Tx interrupts on the CD1400 */
411 local_irq_save(flags);
412 cy_writeb(address + (CyCAR << index), 0);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700413 __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Jiri Slaby02f11752006-12-08 02:39:28 -0800415 cy_writeb(address + (CyCAR << index), 0);
416 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700417 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800418 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Jiri Slaby02f11752006-12-08 02:39:28 -0800420 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700421 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Jiri Slaby02f11752006-12-08 02:39:28 -0800423 /* Check which interrupt is in use */
424 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Jiri Slaby02f11752006-12-08 02:39:28 -0800426 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700427 save_xir = (u_char) readb(address + (CyTIR << index));
428 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800429 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
430 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700431 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800432 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
433 cy_writeb(address + (CyCAR << index), (save_car));
434 cy_writeb(address + (Cy_ClrIntr << index), 0);
435 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Jiri Slaby02f11752006-12-08 02:39:28 -0800437 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
Jiri Slaby02f11752006-12-08 02:39:28 -0800439#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Jiri Slabyce97a092007-10-18 03:06:21 -0700441static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
442 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800443{
444 struct cyclades_port *info;
445 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700446 int len, index = cinfo->bus_index;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700447 u8 ivr, save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800448
Jiri Slabye9410272006-12-08 02:39:28 -0800449#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700450 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800451#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700452 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700453 save_xir = readb(base_addr + (CyRIR << index));
454 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700455 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700456 save_car = cyy_readb(info, CyCAR);
457 cyy_writeb(info, CyCAR, save_xir);
458 ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
Jiri Slabye9410272006-12-08 02:39:28 -0800459
Jiri Slabyd13549f2009-09-19 13:13:12 -0700460 tty = tty_port_tty_get(&info->port);
Jiri Slabyce97a092007-10-18 03:06:21 -0700461 /* if there is nowhere to put the data, discard it */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700462 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700463 if (ivr == CyIVRRxEx) { /* exception */
464 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700465 } else { /* normal character reception */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700466 char_count = cyy_readb(info, CyRDCR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700467 while (char_count--)
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700468 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700469 }
470 goto end;
471 }
472 /* there is an open port for this data */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700473 if (ivr == CyIVRRxEx) { /* exception */
474 data = cyy_readb(info, CyRDSR);
Jiri Slaby02f11752006-12-08 02:39:28 -0800475
Jiri Slabyce97a092007-10-18 03:06:21 -0700476 /* For statistics only */
477 if (data & CyBREAK)
478 info->icount.brk++;
479 else if (data & CyFRAME)
480 info->icount.frame++;
481 else if (data & CyPARITY)
482 info->icount.parity++;
483 else if (data & CyOVERRUN)
484 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800485
Jiri Slabyce97a092007-10-18 03:06:21 -0700486 if (data & info->ignore_status_mask) {
487 info->icount.rx++;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700488 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700489 return;
490 }
491 if (tty_buffer_request_room(tty, 1)) {
492 if (data & info->read_status_mask) {
493 if (data & CyBREAK) {
494 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700495 cyy_readb(info, CyRDSR),
496 TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800497 info->icount.rx++;
Alan Cox77451e52008-07-16 21:57:02 +0100498 if (info->port.flags & ASYNC_SAK)
Jiri Slabyce97a092007-10-18 03:06:21 -0700499 do_SAK(tty);
500 } else if (data & CyFRAME) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700501 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700502 cyy_readb(info, CyRDSR),
503 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700504 info->icount.rx++;
505 info->idle_stats.frame_errs++;
506 } else if (data & CyPARITY) {
507 /* Pieces of seven... */
508 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700509 cyy_readb(info, CyRDSR),
510 TTY_PARITY);
Jiri Slabyce97a092007-10-18 03:06:21 -0700511 info->icount.rx++;
512 info->idle_stats.parity_errs++;
513 } else if (data & CyOVERRUN) {
514 tty_insert_flip_char(tty, 0,
515 TTY_OVERRUN);
516 info->icount.rx++;
517 /* If the flip buffer itself is
518 overflowing, we still lose
519 the next incoming character.
520 */
521 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700522 cyy_readb(info, CyRDSR),
523 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700524 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800525 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700526 /* These two conditions may imply */
527 /* a normal read should be done. */
528 /* } else if(data & CyTIMEOUT) { */
529 /* } else if(data & CySPECHAR) { */
530 } else {
531 tty_insert_flip_char(tty, 0,
532 TTY_NORMAL);
533 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800534 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700535 } else {
536 tty_insert_flip_char(tty, 0, TTY_NORMAL);
537 info->icount.rx++;
538 }
539 } else {
540 /* there was a software buffer overrun and nothing
541 * could be done about it!!! */
542 info->icount.buf_overrun++;
543 info->idle_stats.overruns++;
544 }
545 } else { /* normal character reception */
546 /* load # chars available from the chip */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700547 char_count = cyy_readb(info, CyRDCR);
Jiri Slabye9410272006-12-08 02:39:28 -0800548
549#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700550 ++info->mon.int_count;
551 info->mon.char_count += char_count;
552 if (char_count > info->mon.char_max)
553 info->mon.char_max = char_count;
554 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800555#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700556 len = tty_buffer_request_room(tty, char_count);
557 while (len--) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700558 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700559 tty_insert_flip_char(tty, data, TTY_NORMAL);
560 info->idle_stats.recv_bytes++;
561 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800562#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700563 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800564#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800565 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700566 info->idle_stats.recv_idle = jiffies;
567 }
568 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700569 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700570end:
571 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700572 cyy_writeb(info, CyRIR, save_xir & 0x3f);
573 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700574}
575
Jiri Slaby65f76a82007-10-18 03:06:22 -0700576static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700577 void __iomem *base_addr)
578{
579 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700580 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700581 int char_count, index = cinfo->bus_index;
582 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700583
584 /* Since we only get here when the transmit buffer
585 is empty, we know we can always stuff a dozen
586 characters. */
587#ifdef CY_DEBUG_INTERRUPTS
588 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
589#endif
590
591 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700592 save_xir = readb(base_addr + (CyTIR << index));
593 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700594 save_car = readb(base_addr + (CyCAR << index));
595 cy_writeb(base_addr + (CyCAR << index), save_xir);
596
Jiri Slabyce97a092007-10-18 03:06:21 -0700597 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700598 tty = tty_port_tty_get(&info->port);
599 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700600 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700601 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800602 }
603
Jiri Slabyce97a092007-10-18 03:06:21 -0700604 /* load the on-chip space for outbound data */
605 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800606
Jiri Slabyce97a092007-10-18 03:06:21 -0700607 if (info->x_char) { /* send special char */
608 outch = info->x_char;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700609 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700610 char_count--;
611 info->icount.tx++;
612 info->x_char = 0;
613 }
Jiri Slabye9410272006-12-08 02:39:28 -0800614
Jiri Slabyce97a092007-10-18 03:06:21 -0700615 if (info->breakon || info->breakoff) {
616 if (info->breakon) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700617 cyy_writeb(info, CyTDR, 0);
618 cyy_writeb(info, CyTDR, 0x81);
Jiri Slabyce97a092007-10-18 03:06:21 -0700619 info->breakon = 0;
620 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800621 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700622 if (info->breakoff) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700623 cyy_writeb(info, CyTDR, 0);
624 cyy_writeb(info, CyTDR, 0x83);
Jiri Slabyce97a092007-10-18 03:06:21 -0700625 info->breakoff = 0;
626 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800627 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700628 }
Jiri Slabye9410272006-12-08 02:39:28 -0800629
Jiri Slabyce97a092007-10-18 03:06:21 -0700630 while (char_count-- > 0) {
631 if (!info->xmit_cnt) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700632 if (cyy_readb(info, CySRER) & CyTxMpty) {
633 cyy_writeb(info, CySRER,
634 cyy_readb(info, CySRER) & ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700635 } else {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700636 cyy_writeb(info, CySRER, CyTxMpty |
637 (cyy_readb(info, CySRER) & ~CyTxRdy));
Jiri Slaby02f11752006-12-08 02:39:28 -0800638 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700639 goto done;
640 }
Alan Cox77451e52008-07-16 21:57:02 +0100641 if (info->port.xmit_buf == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700642 cyy_writeb(info, CySRER,
643 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700644 goto done;
645 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700646 if (tty->stopped || tty->hw_stopped) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700647 cyy_writeb(info, CySRER,
648 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700649 goto done;
650 }
651 /* Because the Embedded Transmit Commands have been enabled,
652 * we must check to see if the escape character, NULL, is being
653 * sent. If it is, we must ensure that there is room for it to
654 * be doubled in the output stream. Therefore we no longer
655 * advance the pointer when the character is fetched, but
656 * rather wait until after the check for a NULL output
657 * character. This is necessary because there may not be room
658 * for the two chars needed to send a NULL.)
659 */
Alan Cox77451e52008-07-16 21:57:02 +0100660 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700661 if (outch) {
662 info->xmit_cnt--;
663 info->xmit_tail = (info->xmit_tail + 1) &
664 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700665 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700666 info->icount.tx++;
667 } else {
668 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800669 info->xmit_cnt--;
670 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700671 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700672 cyy_writeb(info, CyTDR, outch);
673 cyy_writeb(info, CyTDR, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800674 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700675 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800676 }
677 }
Jiri Slabye9410272006-12-08 02:39:28 -0800678 }
679
Jiri Slabyce97a092007-10-18 03:06:21 -0700680done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700681 tty_wakeup(tty);
682 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700683end:
684 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700685 cyy_writeb(info, CyTIR, save_xir & 0x3f);
686 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700687}
Jiri Slabye9410272006-12-08 02:39:28 -0800688
Jiri Slabyce97a092007-10-18 03:06:21 -0700689static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
690 void __iomem *base_addr)
691{
692 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700693 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700694 int index = cinfo->bus_index;
695 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800696
Jiri Slabyce97a092007-10-18 03:06:21 -0700697 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700698 save_xir = readb(base_addr + (CyMIR << index));
699 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700700 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700701 save_car = cyy_readb(info, CyCAR);
702 cyy_writeb(info, CyCAR, save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800703
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700704 mdm_change = cyy_readb(info, CyMISR);
705 mdm_status = cyy_readb(info, CyMSVR1);
Jiri Slabye9410272006-12-08 02:39:28 -0800706
Jiri Slabyd13549f2009-09-19 13:13:12 -0700707 tty = tty_port_tty_get(&info->port);
708 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700709 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800710
Jiri Slabyce97a092007-10-18 03:06:21 -0700711 if (mdm_change & CyANY_DELTA) {
712 /* For statistics only */
713 if (mdm_change & CyDCD)
714 info->icount.dcd++;
715 if (mdm_change & CyCTS)
716 info->icount.cts++;
717 if (mdm_change & CyDSR)
718 info->icount.dsr++;
719 if (mdm_change & CyRI)
720 info->icount.rng++;
721
Alan Coxbdc04e32009-09-19 13:13:31 -0700722 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slabyce97a092007-10-18 03:06:21 -0700723 }
724
Alan Cox77451e52008-07-16 21:57:02 +0100725 if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700726 if (mdm_status & CyDCD)
727 wake_up_interruptible(&info->port.open_wait);
728 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700729 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800730 }
Alan Cox77451e52008-07-16 21:57:02 +0100731 if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700732 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700733 if (mdm_status & CyCTS) {
734 /* cy_start isn't used
735 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700736 tty->hw_stopped = 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700737 cyy_writeb(info, CySRER,
738 cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700739 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700740 }
741 } else {
742 if (!(mdm_status & CyCTS)) {
743 /* cy_stop isn't used
744 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700745 tty->hw_stopped = 1;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700746 cyy_writeb(info, CySRER,
747 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700748 }
749 }
750 }
751/* if (mdm_change & CyDSR) {
752 }
753 if (mdm_change & CyRI) {
754 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700755 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700756end:
757 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700758 cyy_writeb(info, CyMIR, save_xir & 0x3f);
759 cyy_writeb(info, CyCAR, save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800760}
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762/* The real interrupt service routine is called
763 whenever the card wants its hand held--chars
764 received, out buffer empty, modem change, etc.
765 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800766static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
Jiri Slaby02f11752006-12-08 02:39:28 -0800768 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700769 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800770 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700771 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800772 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800773
Jiri Slabyf7429032007-05-08 00:36:59 -0700774 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700776 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
777 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800779 return IRQ_NONE; /* spurious interrupt */
780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Jiri Slaby02f11752006-12-08 02:39:28 -0800782 card_base_addr = cinfo->base_addr;
783 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700785 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
786 if (unlikely(card_base_addr == NULL))
787 return IRQ_HANDLED;
788
Jiri Slaby02f11752006-12-08 02:39:28 -0800789 /* This loop checks all chips in the card. Make a note whenever
790 _any_ chip had some work to do, as this is considered an
791 indication that there will be more to do. Only when no chip
792 has any work does this outermost loop exit.
793 */
794 do {
795 had_work = 0;
796 for (chip = 0; chip < cinfo->num_chips; chip++) {
797 base_addr = cinfo->base_addr +
798 (cy_chip_offset[chip] << index);
799 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700800 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800801 (CySVRR << index))) != 0x00) {
802 had_work++;
803 /* The purpose of the following test is to ensure that
804 no chip can monopolize the driver. This forces the
805 chips to be checked in a round-robin fashion (after
806 draining each of a bunch (1000) of characters).
807 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700808 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800809 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700810 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700811 if (status & CySRReceive) /* rx intr */
812 cyy_chip_rx(cinfo, chip, base_addr);
813 if (status & CySRTransmit) /* tx intr */
814 cyy_chip_tx(cinfo, chip, base_addr);
815 if (status & CySRModem) /* modem intr */
816 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700817 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800818 }
819 }
820 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
Jiri Slaby02f11752006-12-08 02:39:28 -0800822 /* clear interrupts */
823 spin_lock(&cinfo->card_lock);
824 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
825 /* Cy_ClrIntr is 0x1800 */
826 spin_unlock(&cinfo->card_lock);
827 return IRQ_HANDLED;
828} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Jiri Slaby4d768202009-09-19 13:13:15 -0700830static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
831 unsigned int clear)
832{
833 struct cyclades_card *card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700834 int channel = info->line - card->first_line;
Jiri Slaby0d348722009-09-19 13:13:16 -0700835 u32 rts, dtr, msvrr, msvrd;
Jiri Slaby4d768202009-09-19 13:13:15 -0700836
Jiri Slaby4d768202009-09-19 13:13:15 -0700837 channel &= 0x03;
Jiri Slaby4d768202009-09-19 13:13:15 -0700838
Jiri Slaby0d348722009-09-19 13:13:16 -0700839 if (info->rtsdtr_inv) {
840 msvrr = CyMSVR2;
841 msvrd = CyMSVR1;
842 rts = CyDTR;
843 dtr = CyRTS;
844 } else {
845 msvrr = CyMSVR1;
846 msvrd = CyMSVR2;
847 rts = CyRTS;
848 dtr = CyDTR;
849 }
Jiri Slaby4d768202009-09-19 13:13:15 -0700850 if (set & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700851 cyy_writeb(info, CyCAR, channel);
852 cyy_writeb(info, msvrr, rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700853 }
854 if (clear & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700855 cyy_writeb(info, CyCAR, channel);
856 cyy_writeb(info, msvrr, ~rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700857 }
858 if (set & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700859 cyy_writeb(info, CyCAR, channel);
860 cyy_writeb(info, msvrd, dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700861#ifdef CY_DEBUG_DTR
862 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
863 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700864 cyy_readb(info, CyMSVR1),
865 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700866#endif
867 }
868 if (clear & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700869 cyy_writeb(info, CyCAR, channel);
870 cyy_writeb(info, msvrd, ~dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700871#ifdef CY_DEBUG_DTR
872 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
873 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700874 cyy_readb(info, CyMSVR1),
875 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700876#endif
877 }
878}
879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880/***********************************************************/
881/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700882/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883/***********************************************************/
884
885static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800886cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700887 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700889 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800890 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Jiri Slaby97e87f82009-06-11 12:29:27 +0100892 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800893 if (loc_doorbell) {
894 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700895 *channel = readl(&board_ctrl->fwcmd_channel);
896 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100897 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800898 return 1;
899 }
900 return 0;
901} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800904cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700905 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700907 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700908 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700909 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Jiri Slaby2693f482009-06-11 12:31:06 +0100911 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800912 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700913
Jiri Slaby02f11752006-12-08 02:39:28 -0800914 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100915 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700916 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700917 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700918 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800919 udelay(50L);
920 }
921 cy_writel(&board_ctrl->hcmd_channel, channel);
922 cy_writel(&board_ctrl->hcmd_param, param);
923 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800925 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800926} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700928static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700930 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700931 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700932 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800933 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700935 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800937 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700939 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700941 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
942 rx_put = readl(&buf_ctrl->rx_put);
943 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
944 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800945 if (rx_put >= rx_get)
946 char_count = rx_put - rx_get;
947 else
948 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Jiri Slaby02f11752006-12-08 02:39:28 -0800950 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800952 info->mon.int_count++;
953 info->mon.char_count += char_count;
954 if (char_count > info->mon.char_max)
955 info->mon.char_max = char_count;
956 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700958 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800959 /* flush received characters */
960 new_rx_get = (new_rx_get + char_count) &
961 (rx_bufsize - 1);
962 info->rflush_count++;
963 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800965 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
966 for performance, but because of buffer boundaries, there
967 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700968 while (1) {
969 len = tty_prepare_flip_string(tty, &buf,
970 char_count);
971 if (!len)
972 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700974 len = min_t(unsigned int, min(len, char_count),
975 rx_bufsize - new_rx_get);
976
977 memcpy_fromio(buf, cinfo->base_addr +
978 rx_bufaddr + new_rx_get, len);
979
980 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800981 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700982 char_count -= len;
983 info->icount.rx += len;
984 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800987 len = tty_buffer_request_room(tty, char_count);
988 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700989 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800990 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700991 new_rx_get = (new_rx_get + 1) &
992 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800993 tty_insert_flip_char(tty, data, TTY_NORMAL);
994 info->idle_stats.recv_bytes++;
995 info->icount.rx++;
996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997#endif
998#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -0800999 /* Recalculate the number of chars in the RX buffer and issue
1000 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001001 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001002 if (rx_put >= rx_get)
1003 char_count = rx_put - rx_get;
1004 else
1005 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001006 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -07001007 !timer_pending(&cyz_rx_full_timer[
1008 info->line]))
1009 mod_timer(&cyz_rx_full_timer[info->line],
1010 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001012 info->idle_stats.recv_idle = jiffies;
1013 tty_schedule_flip(tty);
1014 }
1015 /* Update rx_get */
1016 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018}
1019
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001020static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001022 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001023 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001024 u8 data;
1025 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001027 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001029 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Jiri Slaby02f11752006-12-08 02:39:28 -08001031 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1032 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001034 tx_get = readl(&buf_ctrl->tx_get);
1035 tx_put = readl(&buf_ctrl->tx_put);
1036 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1037 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001038 if (tx_put >= tx_get)
1039 char_count = tx_get - tx_put - 1 + tx_bufsize;
1040 else
1041 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Jiri Slaby02f11752006-12-08 02:39:28 -08001043 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Jiri Slabyf7429032007-05-08 00:36:59 -07001045 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001046 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001047
1048 if (info->x_char) { /* send special char */
1049 data = info->x_char;
1050
1051 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1052 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1053 info->x_char = 0;
1054 char_count--;
1055 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001056 }
1057#ifdef BLOCKMOVE
1058 while (0 < (small_count = min_t(unsigned int,
1059 tx_bufsize - tx_put, min_t(unsigned int,
1060 (SERIAL_XMIT_SIZE - info->xmit_tail),
1061 min_t(unsigned int, info->xmit_cnt,
1062 char_count))))) {
1063
1064 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1065 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001066 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001067 small_count);
1068
1069 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1070 char_count -= small_count;
1071 info->icount.tx += small_count;
1072 info->xmit_cnt -= small_count;
1073 info->xmit_tail = (info->xmit_tail + small_count) &
1074 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001075 }
1076#else
1077 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001078 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001079 info->xmit_cnt--;
1080 info->xmit_tail = (info->xmit_tail + 1) &
1081 (SERIAL_XMIT_SIZE - 1);
1082
1083 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1084 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1085 char_count--;
1086 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001089 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001090ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001091 /* Update tx_put */
1092 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094}
1095
Jiri Slaby02f11752006-12-08 02:39:28 -08001096static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001098 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001099 struct tty_struct *tty;
1100 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001101 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001102 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001103 int special_count;
1104 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001106 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Jiri Slaby02f11752006-12-08 02:39:28 -08001108 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1109 special_count = 0;
1110 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001111 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001112 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001113 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001114 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001115
Jiri Slaby02f11752006-12-08 02:39:28 -08001116 switch (cmd) {
1117 case C_CM_PR_ERROR:
1118 tty_insert_flip_char(tty, 0, TTY_PARITY);
1119 info->icount.rx++;
1120 special_count++;
1121 break;
1122 case C_CM_FR_ERROR:
1123 tty_insert_flip_char(tty, 0, TTY_FRAME);
1124 info->icount.rx++;
1125 special_count++;
1126 break;
1127 case C_CM_RXBRK:
1128 tty_insert_flip_char(tty, 0, TTY_BREAK);
1129 info->icount.rx++;
1130 special_count++;
1131 break;
1132 case C_CM_MDCD:
1133 info->icount.dcd++;
1134 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001135 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001136 u32 dcd = fw_ver > 241 ? param :
1137 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001138 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001139 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001140 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001141 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001142 }
1143 break;
1144 case C_CM_MCTS:
1145 info->icount.cts++;
1146 delta_count++;
1147 break;
1148 case C_CM_MRI:
1149 info->icount.rng++;
1150 delta_count++;
1151 break;
1152 case C_CM_MDSR:
1153 info->icount.dsr++;
1154 delta_count++;
1155 break;
1156#ifdef Z_WAKE
1157 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001158 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001159 break;
1160#endif
1161#ifdef CONFIG_CYZ_INTR
1162 case C_CM_RXHIWM:
1163 case C_CM_RXNNDT:
1164 case C_CM_INTBACK2:
1165 /* Reception Interrupt */
1166#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001167 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1168 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001169#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001170 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001171 break;
1172 case C_CM_TXBEMPTY:
1173 case C_CM_TXLOWWM:
1174 case C_CM_INTBACK:
1175 /* Transmission Interrupt */
1176#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001177 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1178 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001179#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001180 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001181 break;
1182#endif /* CONFIG_CYZ_INTR */
1183 case C_CM_FATAL:
1184 /* should do something with this !!! */
1185 break;
1186 default:
1187 break;
1188 }
1189 if (delta_count)
Alan Coxbdc04e32009-09-19 13:13:31 -07001190 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001191 if (special_count)
1192 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001193 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001194 }
1195}
1196
1197#ifdef CONFIG_CYZ_INTR
1198static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1199{
Jiri Slabyf7429032007-05-08 00:36:59 -07001200 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001201
Jiri Slaby2693f482009-06-11 12:31:06 +01001202 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001203#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001204 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1205 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001206#endif
1207 return IRQ_NONE;
1208 }
1209
1210 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 cyz_handle_cmd(cinfo);
1212
Jiri Slaby02f11752006-12-08 02:39:28 -08001213 return IRQ_HANDLED;
1214} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Jiri Slaby02f11752006-12-08 02:39:28 -08001216static void cyz_rx_restart(unsigned long arg)
1217{
1218 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001219 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001220 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001221 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001222 unsigned long flags;
1223
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001224 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001225 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001226 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001227 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001228 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001230 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001231}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Jiri Slaby02f11752006-12-08 02:39:28 -08001233#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Jiri Slaby02f11752006-12-08 02:39:28 -08001235static void cyz_poll(unsigned long arg)
1236{
1237 struct cyclades_card *cinfo;
1238 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001239 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001240 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001241
Jiri Slaby02f11752006-12-08 02:39:28 -08001242 for (card = 0; card < NR_CARDS; card++) {
1243 cinfo = &cy_card[card];
1244
Jiri Slaby2693f482009-06-11 12:31:06 +01001245 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001246 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001247 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001248 continue;
1249
Jiri Slaby02f11752006-12-08 02:39:28 -08001250 /* Skip first polling cycle to avoid racing conditions with the FW */
1251 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001252 cinfo->intr_enabled = 1;
1253 continue;
1254 }
1255
1256 cyz_handle_cmd(cinfo);
1257
1258 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001259 struct tty_struct *tty;
1260
Jiri Slabydd025c02007-05-08 00:37:02 -07001261 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001262 tty = tty_port_tty_get(&info->port);
1263 /* OK to pass NULL to the handle functions below.
1264 They need to drop the data in that case. */
1265
Jiri Slaby02f11752006-12-08 02:39:28 -08001266 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001267 cyz_handle_rx(info, tty);
1268 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001269 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001270 }
1271 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001272 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001273 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001274 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001275} /* cyz_poll */
1276
1277#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279/********** End of block of Cyclades-Z specific code *********/
1280/***********************************************************/
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282/* This is called whenever a port becomes active;
1283 interrupts are enabled and DTR & RTS are turned on.
1284 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001285static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
Jiri Slaby875b2062007-05-08 00:36:49 -07001287 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001288 unsigned long flags;
1289 int retval = 0;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001290 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001291 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Jiri Slaby02f11752006-12-08 02:39:28 -08001293 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001294 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Jiri Slaby02f11752006-12-08 02:39:28 -08001296 page = get_zeroed_page(GFP_KERNEL);
1297 if (!page)
1298 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001300 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001302 if (info->port.flags & ASYNC_INITIALIZED)
Jiri Slaby02f11752006-12-08 02:39:28 -08001303 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001304
1305 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001306 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001307 goto errout;
1308 }
1309
Alan Cox77451e52008-07-16 21:57:02 +01001310 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001311 free_page(page);
1312 else
Alan Cox77451e52008-07-16 21:57:02 +01001313 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001315 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
Jiri Slabyd13549f2009-09-19 13:13:12 -07001317 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Jiri Slaby2693f482009-06-11 12:31:06 +01001319 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001320 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001322 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001323
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001324 cyy_writeb(info, CyCAR, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001325
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001326 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08001327 (info->default_timeout ? info->default_timeout : 0x02));
1328 /* 10ms rx timeout */
1329
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001330 cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001331
Jiri Slaby4d768202009-09-19 13:13:15 -07001332 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001334 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001335 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001336 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001337
Jiri Slaby2693f482009-06-11 12:31:06 +01001338 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001339 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001340
Jiri Slaby02f11752006-12-08 02:39:28 -08001341#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001342 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001343 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001344#endif
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001345 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001346
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001347 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348#ifdef Z_WAKE
1349#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001350 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001351 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1352 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001354 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001355 C_IN_IOCTLW | C_IN_MDCD);
1356#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357#else
1358#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001359 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001360 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1361 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001363 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001364#endif /* CONFIG_CYZ_INTR */
1365#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Jiri Slaby875b2062007-05-08 00:36:49 -07001367 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001368 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001369 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1370 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Jiri Slaby02f11752006-12-08 02:39:28 -08001373 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001374 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001375 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001376 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1377 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Jiri Slaby02f11752006-12-08 02:39:28 -08001380 /* set timeout !!! */
1381 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001382 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Jiri Slaby02f11752006-12-08 02:39:28 -08001384 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001387 info->port.flags |= ASYNC_INITIALIZED;
1388
1389 clear_bit(TTY_IO_ERROR, &tty->flags);
1390 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1391 info->breakon = info->breakoff = 0;
1392 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1393 info->idle_stats.in_use =
1394 info->idle_stats.recv_idle =
1395 info->idle_stats.xmit_idle = jiffies;
1396
1397 spin_unlock_irqrestore(&card->card_lock, flags);
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001400 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401#endif
1402 return 0;
1403
1404errout:
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001405 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001406 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001408} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Jiri Slaby02f11752006-12-08 02:39:28 -08001410static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001412 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001413 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001414 int channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Jiri Slaby2693f482009-06-11 12:31:06 +01001416 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001417 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001418 cyy_writeb(info, CyCAR, channel & 0x03);
1419 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001420 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001421 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001423 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001425 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001426 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001427 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001428 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1429 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001430 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001431 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001432#else /* CONFIG_CYZ_INTR */
1433 /* Don't have to do anything at this time */
1434#endif /* CONFIG_CYZ_INTR */
1435 }
1436} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438/*
1439 * This routine shuts down a serial port; interrupts are disabled,
1440 * and DTR is dropped if the hangup on close termio flag is on.
1441 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001442static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
Alan Cox77451e52008-07-16 21:57:02 +01001447 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001448 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
Jiri Slaby02f11752006-12-08 02:39:28 -08001450 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001451 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001452 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001453
1454 /* Clear delta_msr_wait queue to avoid mem leaks. */
Alan Coxbdc04e32009-09-19 13:13:31 -07001455 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001456
Alan Cox77451e52008-07-16 21:57:02 +01001457 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001458 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001459 temp = info->port.xmit_buf;
1460 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001461 free_page((unsigned long)temp);
1462 }
Jiri Slaby4d768202009-09-19 13:13:15 -07001463 if (tty->termios->c_cflag & HUPCL)
1464 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1465
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001466 cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001467 /* it may be appropriate to clear _XMIT at
1468 some later date (after testing)!!! */
1469
Jiri Slabyd13549f2009-09-19 13:13:12 -07001470 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001471 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001472 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001473 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001474#ifdef CY_DEBUG_OPEN
Jiri Slaby0e7f4192011-03-23 09:49:56 +01001475 int channel = info->line - card->first_line;
Jiri Slaby21719192007-05-08 00:36:42 -07001476 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001477 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001478#endif
1479
Jiri Slaby2693f482009-06-11 12:31:06 +01001480 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001481 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001482
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001483 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001484
Alan Cox77451e52008-07-16 21:57:02 +01001485 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001486 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001487 temp = info->port.xmit_buf;
1488 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001489 free_page((unsigned long)temp);
1490 }
1491
Jiri Slaby4d768202009-09-19 13:13:15 -07001492 if (tty->termios->c_cflag & HUPCL)
1493 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001494
Jiri Slabyd13549f2009-09-19 13:13:12 -07001495 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001496 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001497
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001498 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001499 }
1500
1501#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001502 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001503#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001504} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
1506/*
1507 * ------------------------------------------------------------
1508 * cy_open() and friends
1509 * ------------------------------------------------------------
1510 */
1511
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512/*
1513 * This routine is called whenever a serial port is opened. It
1514 * performs the serial-specific initialization for the tty structure.
1515 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001516static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517{
Jiri Slaby02f11752006-12-08 02:39:28 -08001518 struct cyclades_port *info;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001519 unsigned int i, line;
1520 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
Jiri Slaby02f11752006-12-08 02:39:28 -08001522 line = tty->index;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001523 if (tty->index < 0 || NR_PORTS <= line)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001525
Jiri Slabydd025c02007-05-08 00:37:02 -07001526 for (i = 0; i < NR_CARDS; i++)
1527 if (line < cy_card[i].first_line + cy_card[i].nports &&
1528 line >= cy_card[i].first_line)
1529 break;
1530 if (i >= NR_CARDS)
1531 return -ENODEV;
1532 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001533 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001534 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001535
1536 /* If the card's firmware hasn't been loaded,
1537 treat it as absent from the system. This
1538 will make the user pay attention.
1539 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001540 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001541 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001542 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1543
Jiri Slaby2693f482009-06-11 12:31:06 +01001544 if (!cyz_is_loaded(cinfo)) {
1545 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001546 readl(&firm_id->signature) ==
1547 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001548 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1549 "need an external power supply for "
1550 "this number of ports.\nFirmware "
1551 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001552 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001553 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1554 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001555 }
1556 return -ENODEV;
1557 }
1558#ifdef CONFIG_CYZ_INTR
1559 else {
1560 /* In case this Z board is operating in interrupt mode, its
1561 interrupts should be enabled as soon as the first open
1562 happens to one of its ports. */
1563 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001564 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001565
Jiri Slaby02f11752006-12-08 02:39:28 -08001566 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001567 intr = readw(&cinfo->ctl_addr.p9060->
1568 intr_ctrl_stat) | 0x0900;
1569 cy_writew(&cinfo->ctl_addr.p9060->
1570 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001571 /* Enable interrupts on the FW */
1572 retval = cyz_issue_cmd(cinfo, 0,
1573 C_CM_IRQ_ENBL, 0L);
1574 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001575 printk(KERN_ERR "cyc:IRQ enable retval "
1576 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001577 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001578 cinfo->intr_enabled = 1;
1579 }
1580 }
1581#endif /* CONFIG_CYZ_INTR */
1582 /* Make sure this Z port really exists in hardware */
1583 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1584 return -ENODEV;
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001587 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001589 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001590 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001591 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001592
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001594 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001595 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596#endif
Alan Cox77451e52008-07-16 21:57:02 +01001597 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001599 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001600 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
Jiri Slaby02f11752006-12-08 02:39:28 -08001603 /*
1604 * If the port is the middle of closing, bail out now
1605 */
Alan Cox77451e52008-07-16 21:57:02 +01001606 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
Arnd Bergmannbe1bc282010-06-01 22:53:05 +02001607 wait_event_interruptible_tty(info->port.close_wait,
Alan Cox77451e52008-07-16 21:57:02 +01001608 !(info->port.flags & ASYNC_CLOSING));
1609 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 /*
1613 * Start up serial port
1614 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001615 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001616 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001617 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Jiri Slabyf0737572009-09-19 13:13:12 -07001619 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001620 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001622 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1623 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001625 return retval;
1626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Jiri Slaby02f11752006-12-08 02:39:28 -08001628 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001629 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001632 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001634 return 0;
1635} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637/*
1638 * cy_wait_until_sent() --- wait until the transmitter is empty
1639 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001640static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641{
Jiri Slaby875b2062007-05-08 00:36:49 -07001642 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001643 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001644 unsigned long orig_jiffies;
1645 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Jiri Slaby02f11752006-12-08 02:39:28 -08001647 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1648 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
Jiri Slaby02f11752006-12-08 02:39:28 -08001650 if (info->xmit_fifo_size == 0)
1651 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Jiri Slaby02f11752006-12-08 02:39:28 -08001653 orig_jiffies = jiffies;
1654 /*
1655 * Set the check interval to be 1/5 of the estimated time to
1656 * send a single character, and make it at least 1. The check
1657 * interval should also be less than the timeout.
1658 *
1659 * Note: we have to use pretty tight timings here to satisfy
1660 * the NIST-PCTS.
1661 */
1662 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1663 char_time = char_time / 5;
1664 if (char_time <= 0)
1665 char_time = 1;
1666 if (timeout < 0)
1667 timeout = 0;
1668 if (timeout)
1669 char_time = min(char_time, timeout);
1670 /*
1671 * If the transmitter hasn't cleared in twice the approximate
1672 * amount of time to send the entire FIFO, it probably won't
1673 * ever clear. This assumes the UART isn't doing flow
1674 * control, which is currently the case. Hence, if it ever
1675 * takes longer than info->timeout, this is probably due to a
1676 * UART bug of some kind. So, we clamp the timeout parameter at
1677 * 2*info->timeout.
1678 */
1679 if (!timeout || timeout > 2 * info->timeout)
1680 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001682 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1683 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001685 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001686 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001687 while (cyy_readb(info, CySRER) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001689 printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001691 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1692 break;
1693 if (timeout && time_after(jiffies, orig_jiffies +
1694 timeout))
1695 break;
1696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001698 /* Run one more char cycle */
1699 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07001701 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702#endif
1703}
1704
Alan Cox978e5952008-04-30 00:53:59 -07001705static void cy_flush_buffer(struct tty_struct *tty)
1706{
1707 struct cyclades_port *info = tty->driver_data;
1708 struct cyclades_card *card;
1709 int channel, retval;
1710 unsigned long flags;
1711
1712#ifdef CY_DEBUG_IO
1713 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1714#endif
1715
1716 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1717 return;
1718
1719 card = info->card;
1720 channel = info->line - card->first_line;
1721
1722 spin_lock_irqsave(&card->card_lock, flags);
1723 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1724 spin_unlock_irqrestore(&card->card_lock, flags);
1725
Jiri Slaby2693f482009-06-11 12:31:06 +01001726 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001727 buffers as well */
1728 spin_lock_irqsave(&card->card_lock, flags);
1729 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1730 if (retval != 0) {
1731 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1732 "was %x\n", info->line, retval);
1733 }
1734 spin_unlock_irqrestore(&card->card_lock, flags);
1735 }
1736 tty_wakeup(tty);
1737} /* cy_flush_buffer */
1738
1739
Alan Coxe936ffd2009-09-19 13:13:22 -07001740static void cy_do_close(struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741{
Alan Coxe936ffd2009-09-19 13:13:22 -07001742 struct cyclades_port *info = container_of(port, struct cyclades_port,
1743 port);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001744 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001745 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001746 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001748 card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001749 channel = info->line - card->first_line;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001750 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001751
Jiri Slaby2693f482009-06-11 12:31:06 +01001752 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001753 /* Stop accepting input */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001754 cyy_writeb(info, CyCAR, channel & 0x03);
1755 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001756 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001757 /* Waiting for on-board buffers to be empty before
1758 closing the port */
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001759 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001760 cy_wait_until_sent(port->tty, info->timeout);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001761 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001762 }
1763 } else {
1764#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001765 /* Waiting for on-board buffers to be empty before closing
1766 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001767 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001768 int retval;
1769
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001770 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001771 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001772 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001773 printk(KERN_DEBUG "cyc:cy_close retval on "
1774 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001775 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001776 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001777 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001778 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001779 }
1780#endif
1781 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001782 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001783 cy_shutdown(info, port->tty);
1784}
Jiri Slaby02f11752006-12-08 02:39:28 -08001785
Alan Coxe936ffd2009-09-19 13:13:22 -07001786/*
1787 * This routine is called when a particular tty device is closed.
1788 */
1789static void cy_close(struct tty_struct *tty, struct file *filp)
1790{
1791 struct cyclades_port *info = tty->driver_data;
1792 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1793 return;
1794 tty_port_close(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001795} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797/* This routine gets called when tty_write has put something into
1798 * the write_queue. The characters may come from user space or
1799 * kernel space.
1800 *
1801 * This routine will return the number of characters actually
1802 * accepted for writing.
1803 *
1804 * If the port is not already transmitting stuff, start it off by
1805 * enabling interrupts. The interrupt service routine will then
1806 * ensure that the characters are sent.
1807 * If the port is already active, there is no need to kick it.
1808 *
1809 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001810static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001812 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 unsigned long flags;
1814 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
1816#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001817 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818#endif
1819
Alan Cox15ed6cc2008-04-30 00:53:55 -07001820 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001821 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
Alan Cox77451e52008-07-16 21:57:02 +01001823 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001824 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001826 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001827 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001828 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1829 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Jiri Slaby02f11752006-12-08 02:39:28 -08001831 if (c <= 0)
1832 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
Alan Cox77451e52008-07-16 21:57:02 +01001834 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001835 info->xmit_head = (info->xmit_head + c) &
1836 (SERIAL_XMIT_SIZE - 1);
1837 info->xmit_cnt += c;
1838 buf += c;
1839 count -= c;
1840 ret += c;
1841 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001842 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Jiri Slaby02f11752006-12-08 02:39:28 -08001844 info->idle_stats.xmit_bytes += ret;
1845 info->idle_stats.xmit_idle = jiffies;
1846
Alan Cox15ed6cc2008-04-30 00:53:55 -07001847 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001848 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001849
Jiri Slaby02f11752006-12-08 02:39:28 -08001850 return ret;
1851} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853/*
1854 * This routine is called by the kernel to write a single
1855 * character to the tty device. If the kernel uses this routine,
1856 * it must call the flush_chars() routine (if defined) when it is
1857 * done stuffing characters into the driver. If there is no room
1858 * in the queue, the character is ignored.
1859 */
Alan Cox76b25a52008-04-30 00:54:03 -07001860static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001862 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001863 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001866 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867#endif
1868
Jiri Slaby02f11752006-12-08 02:39:28 -08001869 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001870 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Alan Cox77451e52008-07-16 21:57:02 +01001872 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001873 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001875 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001876 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001877 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001878 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Alan Cox77451e52008-07-16 21:57:02 +01001881 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001882 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1883 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 info->idle_stats.xmit_bytes++;
1885 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07001886 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001887 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001888} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890/*
1891 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001892 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001894static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001896 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001899 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900#endif
1901
Jiri Slaby02f11752006-12-08 02:39:28 -08001902 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1903 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Jiri Slaby02f11752006-12-08 02:39:28 -08001905 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001906 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Jiri Slaby02f11752006-12-08 02:39:28 -08001909 start_xmit(info);
1910} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912/*
1913 * This routine returns the numbers of characters the tty driver
1914 * will accept for queuing to be written. This number is subject
1915 * to change as output buffers get emptied, or if the output flow
1916 * control is activated.
1917 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001918static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001920 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001921 int ret;
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001924 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925#endif
1926
Jiri Slaby02f11752006-12-08 02:39:28 -08001927 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1928 return 0;
1929 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1930 if (ret < 0)
1931 ret = 0;
1932 return ret;
1933} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Jiri Slaby02f11752006-12-08 02:39:28 -08001935static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001937 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
Jiri Slaby02f11752006-12-08 02:39:28 -08001939 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1940 return 0;
1941
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001943 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001944#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001946 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1947 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001949 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08001951 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001952 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001953 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07001954 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001956 tx_get = readl(&buf_ctrl->tx_get);
1957 tx_put = readl(&buf_ctrl->tx_put);
1958 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08001959 if (tx_put >= tx_get)
1960 char_count = tx_put - tx_get;
1961 else
1962 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001964 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1965 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966#endif
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001967 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08001968 }
1969#endif /* Z_EXT_CHARS_IN_BUFFER */
1970} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
1972/*
1973 * ------------------------------------------------------------
1974 * cy_ioctl() and friends
1975 * ------------------------------------------------------------
1976 */
1977
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001978static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
Jiri Slaby02f11752006-12-08 02:39:28 -08001980 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001981 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08001982 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
Jiri Slaby02f11752006-12-08 02:39:28 -08001984 if (baud == 0) {
1985 info->tbpr = info->tco = info->rbpr = info->rco = 0;
1986 return;
1987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Jiri Slaby02f11752006-12-08 02:39:28 -08001989 /* determine which prescaler to use */
1990 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
1991 if (cy_clock / co_val / baud > 63)
1992 break;
1993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Jiri Slaby02f11752006-12-08 02:39:28 -08001995 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
1996 if (bpr > 255)
1997 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 info->tbpr = info->rbpr = bpr;
2000 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001}
2002
2003/*
2004 * This routine finds or computes the various line characteristics.
2005 * It used to be called config_setup
2006 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002007static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008{
Jiri Slaby875b2062007-05-08 00:36:49 -07002009 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002010 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002011 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002012 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08002013 int baud, baud_rate = 0;
2014 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Jiri Slabyd13549f2009-09-19 13:13:12 -07002016 if (!tty->termios) /* XXX can this happen at all? */
Jiri Slaby02f11752006-12-08 02:39:28 -08002017 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002018
2019 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002020 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002021
Jiri Slabyd13549f2009-09-19 13:13:12 -07002022 cflag = tty->termios->c_cflag;
2023 iflag = tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Jiri Slaby02f11752006-12-08 02:39:28 -08002025 /*
2026 * Set up the tty->alt_speed kludge
2027 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002028 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2029 tty->alt_speed = 57600;
2030 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2031 tty->alt_speed = 115200;
2032 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2033 tty->alt_speed = 230400;
2034 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2035 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Jiri Slaby02f11752006-12-08 02:39:28 -08002037 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002038 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002039
Jiri Slaby2693f482009-06-11 12:31:06 +01002040 if (!cy_is_Z(card)) {
Jiri Slaby46fb7822009-09-19 13:13:17 -07002041 u32 cflags;
2042
Jiri Slaby02f11752006-12-08 02:39:28 -08002043 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002044 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002045 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002046 ASYNC_SPD_CUST) {
2047 if (info->custom_divisor)
2048 baud_rate = info->baud / info->custom_divisor;
2049 else
2050 baud_rate = info->baud;
2051 } else if (baud > CD1400_MAX_SPEED) {
2052 baud = CD1400_MAX_SPEED;
2053 }
2054 /* find the baud index */
2055 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002056 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002057 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002058 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002059 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002060 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002061
Alan Cox77451e52008-07-16 21:57:02 +01002062 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002063 ASYNC_SPD_CUST) {
2064 cyy_baud_calc(info, baud_rate);
2065 } else {
2066 if (info->chip_rev >= CD1400_REV_J) {
2067 /* It is a CD1400 rev. J or later */
2068 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2069 info->tco = baud_co_60[i]; /* Tx CO */
2070 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2071 info->rco = baud_co_60[i]; /* Rx CO */
2072 } else {
2073 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2074 info->tco = baud_co_25[i]; /* Tx CO */
2075 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2076 info->rco = baud_co_25[i]; /* Rx CO */
2077 }
2078 }
2079 if (baud_table[i] == 134) {
2080 /* get it right for 134.5 baud */
2081 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2082 2;
Alan Cox77451e52008-07-16 21:57:02 +01002083 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002084 ASYNC_SPD_CUST) {
2085 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2086 baud_rate) + 2;
2087 } else if (baud_table[i]) {
2088 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2089 baud_table[i]) + 2;
2090 /* this needs to be propagated into the card info */
2091 } else {
2092 info->timeout = 0;
2093 }
2094 /* By tradition (is it a standard?) a baud rate of zero
2095 implies the line should be/has been closed. A bit
2096 later in this routine such a test is performed. */
2097
2098 /* byte size and parity */
2099 info->cor5 = 0;
2100 info->cor4 = 0;
2101 /* receive threshold */
2102 info->cor3 = (info->default_threshold ?
2103 info->default_threshold : baud_cor3[i]);
2104 info->cor2 = CyETC;
2105 switch (cflag & CSIZE) {
2106 case CS5:
2107 info->cor1 = Cy_5_BITS;
2108 break;
2109 case CS6:
2110 info->cor1 = Cy_6_BITS;
2111 break;
2112 case CS7:
2113 info->cor1 = Cy_7_BITS;
2114 break;
2115 case CS8:
2116 info->cor1 = Cy_8_BITS;
2117 break;
2118 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002119 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002120 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002121
Jiri Slaby02f11752006-12-08 02:39:28 -08002122 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002123 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002124 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002125 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002126 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002127 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002128 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002129
2130 /* CTS flow control flag */
2131 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002132 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002133 info->cor2 |= CyCtsAE;
2134 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002135 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002136 info->cor2 &= ~CyCtsAE;
2137 }
2138 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002139 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002140 else
Alan Cox77451e52008-07-16 21:57:02 +01002141 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
2143 /***********************************************
2144 The hardware option, CyRtsAO, presents RTS when
2145 the chip has characters to send. Since most modems
2146 use RTS as reverse (inbound) flow control, this
2147 option is not used. If inbound flow control is
2148 necessary, DTR can be programmed to provide the
2149 appropriate signals for use with a non-standard
2150 cable. Contact Marcio Saito for details.
2151 ***********************************************/
2152
Jiri Slaby02f11752006-12-08 02:39:28 -08002153 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002155 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002156 cyy_writeb(info, CyCAR, channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Jiri Slaby02f11752006-12-08 02:39:28 -08002158 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002160 cyy_writeb(info, CyTCOR, info->tco);
2161 cyy_writeb(info, CyTBPR, info->tbpr);
2162 cyy_writeb(info, CyRCOR, info->rco);
2163 cyy_writeb(info, CyRBPR, info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Jiri Slaby02f11752006-12-08 02:39:28 -08002165 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002167 cyy_writeb(info, CySCHR1, START_CHAR(tty));
2168 cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2169 cyy_writeb(info, CyCOR1, info->cor1);
2170 cyy_writeb(info, CyCOR2, info->cor2);
2171 cyy_writeb(info, CyCOR3, info->cor3);
2172 cyy_writeb(info, CyCOR4, info->cor4);
2173 cyy_writeb(info, CyCOR5, info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002175 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2176 CyCOR3ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Alan Cox15ed6cc2008-04-30 00:53:55 -07002178 /* !!! Is this needed? */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002179 cyy_writeb(info, CyCAR, channel);
2180 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08002181 (info->default_timeout ? info->default_timeout : 0x02));
2182 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Jiri Slaby46fb7822009-09-19 13:13:17 -07002184 cflags = CyCTS;
2185 if (!C_CLOCAL(tty))
2186 cflags |= CyDSR | CyRI | CyDCD;
2187 /* without modem intr */
2188 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2189 /* act on 1->0 modem transitions */
2190 if ((cflag & CRTSCTS) && info->rflow)
2191 cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2192 else
2193 cyy_writeb(info, CyMCOR1, cflags);
2194 /* act on 0->1 modem transitions */
2195 cyy_writeb(info, CyMCOR2, cflags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002196
Jiri Slaby4d768202009-09-19 13:13:15 -07002197 if (i == 0) /* baud rate is zero, turn off line */
2198 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2199 else
2200 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Jiri Slabyd13549f2009-09-19 13:13:12 -07002202 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002203 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002206 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002207 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002208 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Jiri Slaby2693f482009-06-11 12:31:06 +01002210 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002211 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Jiri Slaby02f11752006-12-08 02:39:28 -08002213 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002214 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002215 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 ASYNC_SPD_CUST) {
2217 if (info->custom_divisor)
2218 baud_rate = info->baud / info->custom_divisor;
2219 else
2220 baud_rate = info->baud;
2221 } else if (baud > CYZ_MAX_SPEED) {
2222 baud = CYZ_MAX_SPEED;
2223 }
2224 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Jiri Slaby02f11752006-12-08 02:39:28 -08002226 if (baud == 134) {
2227 /* get it right for 134.5 baud */
2228 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2229 2;
Alan Cox77451e52008-07-16 21:57:02 +01002230 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002231 ASYNC_SPD_CUST) {
2232 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2233 baud_rate) + 2;
2234 } else if (baud) {
2235 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2236 baud) + 2;
2237 /* this needs to be propagated into the card info */
2238 } else {
2239 info->timeout = 0;
2240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
Jiri Slaby02f11752006-12-08 02:39:28 -08002242 /* byte size and parity */
2243 switch (cflag & CSIZE) {
2244 case CS5:
2245 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2246 break;
2247 case CS6:
2248 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2249 break;
2250 case CS7:
2251 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2252 break;
2253 case CS8:
2254 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2255 break;
2256 }
2257 if (cflag & CSTOPB) {
2258 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002259 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002260 } else {
2261 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002262 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002263 }
2264 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002265 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002266 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002267 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002268 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002269 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002270 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271
Jiri Slaby02f11752006-12-08 02:39:28 -08002272 /* CTS flow control flag */
2273 if (cflag & CRTSCTS) {
2274 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002275 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002276 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002277 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2278 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002279 }
2280 /* As the HW flow control is done in firmware, the driver
2281 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002282 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002283
2284 /* XON/XOFF/XANY flow control flags */
2285 sw_flow = 0;
2286 if (iflag & IXON) {
2287 sw_flow |= C_FL_OXX;
2288 if (iflag & IXANY)
2289 sw_flow |= C_FL_OIXANY;
2290 }
2291 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2292
Jiri Slaby875b2062007-05-08 00:36:49 -07002293 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002294 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002295 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2296 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002297 }
2298
2299 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002300 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002301 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002302 else
Alan Cox77451e52008-07-16 21:57:02 +01002303 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002304
2305 if (baud == 0) { /* baud rate is zero, turn off line */
2306 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002307 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002309 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002311 } else {
2312 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002313 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002315 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Alan Cox15ed6cc2008-04-30 00:53:55 -07002319 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002320 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002321 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2322 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
Jiri Slabyd13549f2009-09-19 13:13:12 -07002325 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002327} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
Jiri Slaby6c281812009-09-19 13:13:15 -07002329static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002330 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331{
Jiri Slaby875b2062007-05-08 00:36:49 -07002332 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002333 struct serial_struct tmp = {
2334 .type = info->type,
2335 .line = info->line,
2336 .port = (info->card - cy_card) * 0x100 + info->line -
2337 cinfo->first_line,
2338 .irq = cinfo->irq,
2339 .flags = info->port.flags,
2340 .close_delay = info->port.close_delay,
2341 .closing_wait = info->port.closing_wait,
2342 .baud_base = info->baud,
2343 .custom_divisor = info->custom_divisor,
2344 .hub6 = 0, /*!!! */
2345 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002346 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002347}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002350cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002351 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352{
Jiri Slaby02f11752006-12-08 02:39:28 -08002353 struct serial_struct new_serial;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002354 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
Jiri Slaby02f11752006-12-08 02:39:28 -08002356 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2357 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
Alan Cox25c3cdf2010-06-01 22:52:47 +02002359 mutex_lock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002360 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002361 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002362 new_serial.baud_base != info->baud ||
2363 (new_serial.flags & ASYNC_FLAGS &
2364 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002365 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Alan Cox25c3cdf2010-06-01 22:52:47 +02002366 {
2367 mutex_unlock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002368 return -EPERM;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002369 }
Alan Cox77451e52008-07-16 21:57:02 +01002370 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002371 (new_serial.flags & ASYNC_USR_MASK);
2372 info->baud = new_serial.baud_base;
2373 info->custom_divisor = new_serial.custom_divisor;
2374 goto check_and_exit;
2375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
Jiri Slaby02f11752006-12-08 02:39:28 -08002377 /*
2378 * OK, past this point, all the error checking has been done.
2379 * At this point, we start making changes.....
2380 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Jiri Slaby02f11752006-12-08 02:39:28 -08002382 info->baud = new_serial.baud_base;
2383 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002384 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002385 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002386 info->port.close_delay = new_serial.close_delay * HZ / 100;
2387 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
2389check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002390 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002391 cy_set_line_char(info, tty);
Alan Cox25c3cdf2010-06-01 22:52:47 +02002392 ret = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002393 } else {
Alan Cox25c3cdf2010-06-01 22:52:47 +02002394 ret = cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002395 }
Alan Cox25c3cdf2010-06-01 22:52:47 +02002396 mutex_unlock(&info->port.mutex);
2397 return ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002398} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
2400/*
2401 * get_lsr_info - get line status register info
2402 *
2403 * Purpose: Let user call ioctl() to get info when the UART physically
2404 * is emptied. On bus types like RS485, the transmitter must
2405 * release the bus after transmitting. This must be done when
2406 * the transmit shift register is empty, not be done when the
2407 * transmit holding register is empty. This functionality
2408 * allows an RS485 driver to be written in user space.
2409 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002410static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002412 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002413 unsigned int result;
2414 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002415 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Jiri Slaby2693f482009-06-11 12:31:06 +01002417 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002418 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002419 status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002420 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002421 result = (status ? 0 : TIOCSER_TEMT);
2422 } else {
2423 /* Not supported yet */
2424 return -EINVAL;
2425 }
2426 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427}
2428
Alan Cox60b33c12011-02-14 16:26:14 +00002429static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002431 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002432 struct cyclades_card *card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002433 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002435 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002436 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Jiri Slaby02f11752006-12-08 02:39:28 -08002438 card = info->card;
Jiri Slaby0d348722009-09-19 13:13:16 -07002439
Jiri Slaby2693f482009-06-11 12:31:06 +01002440 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002441 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002442 int channel = info->line - card->first_line;
2443 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002445 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002446 cyy_writeb(info, CyCAR, channel & 0x03);
2447 status = cyy_readb(info, CyMSVR1);
2448 status |= cyy_readb(info, CyMSVR2);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002449 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
Jiri Slaby02f11752006-12-08 02:39:28 -08002451 if (info->rtsdtr_inv) {
2452 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2453 ((status & CyDTR) ? TIOCM_RTS : 0);
2454 } else {
2455 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2456 ((status & CyDTR) ? TIOCM_DTR : 0);
2457 }
2458 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2459 ((status & CyRI) ? TIOCM_RNG : 0) |
2460 ((status & CyDSR) ? TIOCM_DSR : 0) |
2461 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002463 u32 lstatus;
2464
2465 if (!cyz_is_loaded(card)) {
2466 result = -ENODEV;
2467 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002468 }
2469
Jiri Slaby0d348722009-09-19 13:13:16 -07002470 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2471 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2472 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2473 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2474 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2475 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2476 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002478end:
Jiri Slaby02f11752006-12-08 02:39:28 -08002479 return result;
2480} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482static int
Alan Cox20b9d172011-02-14 16:26:50 +00002483cy_tiocmset(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002484 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002486 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002487 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002488 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002490 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002491 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
Jiri Slaby02f11752006-12-08 02:39:28 -08002493 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002494 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002495 spin_lock_irqsave(&card->card_lock, flags);
2496 cyy_change_rts_dtr(info, set, clear);
2497 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002498 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002499 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2500 int retval, channel = info->line - card->first_line;
2501 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002502
Jiri Slaby0d348722009-09-19 13:13:16 -07002503 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002504 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002505
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002506 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002507 rs = readl(&ch_ctrl->rs_control);
2508 if (set & TIOCM_RTS)
2509 rs |= C_RS_RTS;
2510 if (clear & TIOCM_RTS)
2511 rs &= ~C_RS_RTS;
2512 if (set & TIOCM_DTR) {
2513 rs |= C_RS_DTR;
2514#ifdef CY_DEBUG_DTR
2515 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2516#endif
2517 }
2518 if (clear & TIOCM_DTR) {
2519 rs &= ~C_RS_DTR;
2520#ifdef CY_DEBUG_DTR
2521 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2522 "Z DTR\n");
2523#endif
2524 }
2525 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002526 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002527 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002528 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002529 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2530 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002533 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002534}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
2536/*
2537 * cy_break() --- routine which turns the break handling on or off
2538 */
Alan Cox9e989662008-07-22 11:18:03 +01002539static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002541 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002542 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002543 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002544 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
Jiri Slaby02f11752006-12-08 02:39:28 -08002546 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002547 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002549 card = info->card;
2550
2551 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002552 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002553 /* Let the transmit ISR take care of this (since it
2554 requires stuffing characters into the output stream).
2555 */
2556 if (break_state == -1) {
2557 if (!info->breakon) {
2558 info->breakon = 1;
2559 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002560 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002561 start_xmit(info);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002562 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002563 }
2564 }
2565 } else {
2566 if (!info->breakoff) {
2567 info->breakoff = 1;
2568 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002569 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002570 start_xmit(info);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002571 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002572 }
2573 }
2574 }
2575 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002576 if (break_state == -1) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002577 retval = cyz_issue_cmd(card,
2578 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002579 C_CM_SET_BREAK, 0L);
2580 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002581 printk(KERN_ERR "cyc:cy_break (set) retval on "
2582 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002583 }
2584 } else {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002585 retval = cyz_issue_cmd(card,
2586 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002587 C_CM_CLR_BREAK, 0L);
2588 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002589 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2590 "on ttyC%d was %x\n", info->line,
2591 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002592 }
2593 }
2594 }
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002595 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002596 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002597} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Jiri Slaby02f11752006-12-08 02:39:28 -08002599static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002601 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002602 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
Jiri Slaby2693f482009-06-11 12:31:06 +01002604 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002605 info->cor3 &= ~CyREC_FIFO;
2606 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002608 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002609 cyy_writeb(info, CyCOR3, info->cor3);
2610 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002611 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002614} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615
Alan Cox15ed6cc2008-04-30 00:53:55 -07002616static int get_threshold(struct cyclades_port *info,
2617 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002619 struct cyclades_card *card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
Jiri Slaby2693f482009-06-11 12:31:06 +01002621 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002622 u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002623 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002624 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002625 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002626} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
Jiri Slaby02f11752006-12-08 02:39:28 -08002628static int set_timeout(struct cyclades_port *info, unsigned long value)
2629{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002630 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002631 unsigned long flags;
2632
Jiri Slaby2693f482009-06-11 12:31:06 +01002633 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002634 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002635 cyy_writeb(info, CyRTPR, value & 0xff);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002636 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002637 }
2638 return 0;
2639} /* set_timeout */
2640
Alan Cox15ed6cc2008-04-30 00:53:55 -07002641static int get_timeout(struct cyclades_port *info,
2642 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002643{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002644 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002645
Jiri Slaby2693f482009-06-11 12:31:06 +01002646 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002647 u8 tmp = cyy_readb(info, CyRTPR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002648 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002649 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002650 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002651} /* get_timeout */
2652
Jiri Slaby6c281812009-09-19 13:13:15 -07002653static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2654 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002655{
Jiri Slaby6c281812009-09-19 13:13:15 -07002656 struct cyclades_icount cnow;
2657 unsigned long flags;
2658 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002659
Jiri Slaby6c281812009-09-19 13:13:15 -07002660 spin_lock_irqsave(&info->card->card_lock, flags);
2661 cnow = info->icount; /* atomic copy */
2662 spin_unlock_irqrestore(&info->card->card_lock, flags);
2663
2664 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2665 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2666 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2667 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2668
2669 *cprev = cnow;
2670
2671 return ret;
2672}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
2674/*
2675 * This routine allows the tty driver to implement device-
2676 * specific ioctl's. If the ioctl number passed in cmd is
2677 * not recognized by the driver, it should return ENOIOCTLCMD.
2678 */
2679static int
Alan Cox6caa76b2011-02-14 16:27:22 +00002680cy_ioctl(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002681 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002683 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002684 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002685 int ret_val = 0;
2686 unsigned long flags;
2687 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688
Jiri Slaby02f11752006-12-08 02:39:28 -08002689 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2690 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002693 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2694 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695#endif
2696
Jiri Slaby02f11752006-12-08 02:39:28 -08002697 switch (cmd) {
2698 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002699 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2700 ret_val = -EFAULT;
2701 break;
2702 }
2703 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002705 case CYGETTHRESH:
2706 ret_val = get_threshold(info, argp);
2707 break;
2708 case CYSETTHRESH:
2709 ret_val = set_threshold(info, arg);
2710 break;
2711 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002712 ret_val = put_user(info->default_threshold,
2713 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002714 break;
2715 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002716 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002717 break;
2718 case CYGETTIMEOUT:
2719 ret_val = get_timeout(info, argp);
2720 break;
2721 case CYSETTIMEOUT:
2722 ret_val = set_timeout(info, arg);
2723 break;
2724 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002725 ret_val = put_user(info->default_timeout,
2726 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002727 break;
2728 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002729 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002730 break;
2731 case CYSETRFLOW:
2732 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002733 break;
2734 case CYGETRFLOW:
2735 ret_val = info->rflow;
2736 break;
2737 case CYSETRTSDTR_INV:
2738 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002739 break;
2740 case CYGETRTSDTR_INV:
2741 ret_val = info->rtsdtr_inv;
2742 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002744 ret_val = info->chip_rev;
2745 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746#ifndef CONFIG_CYZ_INTR
2747 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002748 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002749 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002751 ret_val = (cyz_polling_cycle * 1000) / HZ;
2752 break;
2753#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002755 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002756 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002758 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002759 break;
2760 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002761 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002762 break;
2763 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002764 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002765 break;
2766 case TIOCSERGETLSR: /* Get line status register */
2767 ret_val = get_lsr_info(info, argp);
2768 break;
2769 /*
2770 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2771 * - mask passed in arg for lines of interest
2772 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2773 * Caller should use TIOCGICOUNT to see which one it was
2774 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 case TIOCMIWAIT:
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002776 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002777 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002778 cnow = info->icount;
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002779 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Coxbdc04e32009-09-19 13:13:31 -07002780 ret_val = wait_event_interruptible(info->port.delta_msr_wait,
Jiri Slaby6c281812009-09-19 13:13:15 -07002781 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002782 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002783
2784 /*
2785 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2786 * Return: write counters to the user passed counter struct
2787 * NB: both 1->0 and 0->1 transitions are counted except for
2788 * RI where only 0->1 is counted.
2789 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002790 default:
2791 ret_val = -ENOIOCTLCMD;
2792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
2794#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002795 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002797 return ret_val;
2798} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
Alan Cox05871022010-09-16 18:21:52 +01002800static int cy_get_icount(struct tty_struct *tty,
2801 struct serial_icounter_struct *sic)
2802{
2803 struct cyclades_port *info = tty->driver_data;
2804 struct cyclades_icount cnow; /* Used to snapshot */
2805 unsigned long flags;
2806
2807 spin_lock_irqsave(&info->card->card_lock, flags);
2808 cnow = info->icount;
2809 spin_unlock_irqrestore(&info->card->card_lock, flags);
2810
2811 sic->cts = cnow.cts;
2812 sic->dsr = cnow.dsr;
2813 sic->rng = cnow.rng;
2814 sic->dcd = cnow.dcd;
2815 sic->rx = cnow.rx;
2816 sic->tx = cnow.tx;
2817 sic->frame = cnow.frame;
2818 sic->overrun = cnow.overrun;
2819 sic->parity = cnow.parity;
2820 sic->brk = cnow.brk;
2821 sic->buf_overrun = cnow.buf_overrun;
2822 return 0;
2823}
2824
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825/*
2826 * This routine allows the tty driver to be notified when
2827 * device's termios settings have changed. Note that a
2828 * well-designed tty driver should be prepared to accept the case
2829 * where old == NULL, and try to do something rational.
2830 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002831static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002833 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834
2835#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002836 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837#endif
2838
Jiri Slabyd13549f2009-09-19 13:13:12 -07002839 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
Jiri Slaby02f11752006-12-08 02:39:28 -08002841 if ((old_termios->c_cflag & CRTSCTS) &&
2842 !(tty->termios->c_cflag & CRTSCTS)) {
2843 tty->hw_stopped = 0;
2844 cy_start(tty);
2845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002847 /*
2848 * No need to wake up processes in open wait, since they
2849 * sample the CLOCAL flag once, and don't recheck it.
2850 * XXX It's not clear whether the current behavior is correct
2851 * or not. Hence, this may change.....
2852 */
2853 if (!(old_termios->c_cflag & CLOCAL) &&
2854 (tty->termios->c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01002855 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002857} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859/* This function is used to send a high-priority XON/XOFF character to
2860 the device.
2861*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002862static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002864 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002865 struct cyclades_card *card;
2866 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
Jiri Slaby02f11752006-12-08 02:39:28 -08002868 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return;
2870
Jiri Slaby02f11752006-12-08 02:39:28 -08002871 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872
2873 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08002874 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
2876 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002877 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
Jiri Slaby2693f482009-06-11 12:31:06 +01002879 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002880 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002881 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002882 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002883 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 }
2885}
2886
2887/* This routine is called by the upper-layer tty layer to signal
2888 that incoming characters should be throttled because the input
2889 buffers are close to full.
2890 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002891static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002893 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002894 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002895 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002898 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
Jiri Slaby21719192007-05-08 00:36:42 -07002900 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08002901 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902#endif
2903
Alan Cox15ed6cc2008-04-30 00:53:55 -07002904 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002905 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
Jiri Slaby02f11752006-12-08 02:39:28 -08002907 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
Jiri Slaby02f11752006-12-08 02:39:28 -08002909 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002910 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002911 cy_send_xchar(tty, STOP_CHAR(tty));
2912 else
2913 info->throttle = 1;
2914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
Jiri Slaby02f11752006-12-08 02:39:28 -08002916 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002917 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002918 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002919 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002920 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002921 } else {
2922 info->throttle = 1;
2923 }
2924 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002925} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
2927/*
2928 * This routine notifies the tty driver that it should signal
2929 * that characters can now be sent to the tty without fear of
2930 * overrunning the input buffers of the line disciplines.
2931 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002932static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002934 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002935 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002936 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
2938#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002939 char buf[64];
2940
Jiri Slaby21719192007-05-08 00:36:42 -07002941 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07002942 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943#endif
2944
Alan Cox15ed6cc2008-04-30 00:53:55 -07002945 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002946 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
Jiri Slaby02f11752006-12-08 02:39:28 -08002948 if (I_IXOFF(tty)) {
2949 if (info->x_char)
2950 info->x_char = 0;
2951 else
2952 cy_send_xchar(tty, START_CHAR(tty));
2953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954
Jiri Slaby02f11752006-12-08 02:39:28 -08002955 if (tty->termios->c_cflag & CRTSCTS) {
2956 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002957 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002958 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002959 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002960 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002961 } else {
2962 info->throttle = 0;
2963 }
2964 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002965} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
2967/* cy_start and cy_stop provide software output flow control as a
2968 function of XON/XOFF, software CTS, and other such stuff.
2969*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002970static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971{
Jiri Slaby02f11752006-12-08 02:39:28 -08002972 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002973 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002974 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002975 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002978 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979#endif
2980
Jiri Slaby02f11752006-12-08 02:39:28 -08002981 if (serial_paranoia_check(info, tty->name, "cy_stop"))
2982 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
Jiri Slaby875b2062007-05-08 00:36:49 -07002984 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002985 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002986 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002987 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002988 cyy_writeb(info, CyCAR, channel & 0x03);
2989 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07002990 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002992} /* cy_stop */
2993
2994static void cy_start(struct tty_struct *tty)
2995{
2996 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002997 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002998 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002999 unsigned long flags;
3000
3001#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003002 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08003003#endif
3004
3005 if (serial_paranoia_check(info, tty->name, "cy_start"))
3006 return;
3007
Jiri Slaby875b2062007-05-08 00:36:49 -07003008 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003009 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01003010 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003011 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003012 cyy_writeb(info, CyCAR, channel & 0x03);
3013 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b2007-05-08 00:36:57 -07003014 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003015 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003016} /* cy_start */
3017
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018/*
3019 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3020 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003021static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003023 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003024
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003026 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027#endif
3028
Jiri Slaby02f11752006-12-08 02:39:28 -08003029 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3030 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031
Jiri Slaby02f11752006-12-08 02:39:28 -08003032 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003033 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003034 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003035} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Jiri Slabyf0737572009-09-19 13:13:12 -07003037static int cyy_carrier_raised(struct tty_port *port)
3038{
3039 struct cyclades_port *info = container_of(port, struct cyclades_port,
3040 port);
3041 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003042 unsigned long flags;
3043 int channel = info->line - cinfo->first_line;
Jiri Slabyf0737572009-09-19 13:13:12 -07003044 u32 cd;
3045
Jiri Slabyf0737572009-09-19 13:13:12 -07003046 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003047 cyy_writeb(info, CyCAR, channel & 0x03);
3048 cd = cyy_readb(info, CyMSVR1) & CyDCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003049 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3050
3051 return cd;
3052}
3053
3054static void cyy_dtr_rts(struct tty_port *port, int raise)
3055{
3056 struct cyclades_port *info = container_of(port, struct cyclades_port,
3057 port);
3058 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003059 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003060
3061 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003062 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3063 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003064 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3065}
3066
3067static int cyz_carrier_raised(struct tty_port *port)
3068{
3069 struct cyclades_port *info = container_of(port, struct cyclades_port,
3070 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003071
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003072 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003073}
3074
3075static void cyz_dtr_rts(struct tty_port *port, int raise)
3076{
3077 struct cyclades_port *info = container_of(port, struct cyclades_port,
3078 port);
3079 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003080 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003081 int ret, channel = info->line - cinfo->first_line;
3082 u32 rs;
3083
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003084 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003085 if (raise)
3086 rs |= C_RS_RTS | C_RS_DTR;
3087 else
3088 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003089 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003090 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3091 if (ret != 0)
3092 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3093 __func__, info->line, ret);
3094#ifdef CY_DEBUG_DTR
3095 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3096#endif
3097}
3098
3099static const struct tty_port_operations cyy_port_ops = {
3100 .carrier_raised = cyy_carrier_raised,
3101 .dtr_rts = cyy_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003102 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003103};
3104
3105static const struct tty_port_operations cyz_port_ops = {
3106 .carrier_raised = cyz_carrier_raised,
3107 .dtr_rts = cyz_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003108 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003109};
3110
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111/*
3112 * ---------------------------------------------------------------------
3113 * cy_init() and friends
3114 *
3115 * cy_init() is called at boot-time to initialize the serial driver.
3116 * ---------------------------------------------------------------------
3117 */
3118
Jiri Slabydd025c02007-05-08 00:37:02 -07003119static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003120{
3121 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003122 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003123
Jiri Slaby3046d502007-05-08 00:36:46 -07003124 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003125 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003126
Jiri Slaby963118e2009-06-11 12:34:27 +01003127 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3128 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003129 if (cinfo->ports == NULL) {
3130 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3131 return -ENOMEM;
3132 }
3133
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003134 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3135 channel++, port++) {
3136 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003137 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003138 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003139 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003140 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003141
Alan Cox44b7d1b2008-07-16 21:57:18 +01003142 info->port.closing_wait = CLOSING_WAIT_DELAY;
3143 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003144 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003145 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003146
Jiri Slaby2693f482009-06-11 12:31:06 +01003147 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003148 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3149 struct ZFW_CTRL *zfw_ctrl;
3150
Jiri Slabyf0737572009-09-19 13:13:12 -07003151 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003152 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003153
3154 zfw_ctrl = cinfo->base_addr +
3155 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3156 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3157 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3158
Jiri Slaby101b8152009-06-11 12:30:10 +01003159 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003160 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3161 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003162 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003163#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003164 setup_timer(&cyz_rx_full_timer[port],
3165 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003166#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003167 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003168 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003169 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003170
Jiri Slabyf0737572009-09-19 13:13:12 -07003171 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003172 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003173 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003174 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003175 info->cor2 = CyETC;
3176 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003177
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003178 chip_number = channel / CyPORTS_PER_CHIP;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003179 info->u.cyy.base_addr = cinfo->base_addr +
3180 (cy_chip_offset[chip_number] << index);
3181 info->chip_rev = cyy_readb(info, CyGFRCR);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003182
3183 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003184 /* It is a CD1400 rev. J or later */
3185 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3186 info->tco = baud_co_60[13]; /* Tx CO */
3187 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3188 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003189 info->rtsdtr_inv = 1;
3190 } else {
3191 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3192 info->tco = baud_co_25[13]; /* Tx CO */
3193 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3194 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003195 info->rtsdtr_inv = 0;
3196 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003197 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3198 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003199 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003200
Jiri Slaby0809e262007-05-08 00:36:14 -07003201 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003202
3203#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003204 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003205 mod_timer(&cyz_timerlist, jiffies + 1);
3206#ifdef CY_PCI_DEBUG
3207 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3208#endif
3209 }
3210#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003211 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003212}
3213
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214/* initialize chips on Cyclom-Y card -- return number of valid
3215 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003216static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3217 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218{
Jiri Slaby02f11752006-12-08 02:39:28 -08003219 unsigned int chip_number;
3220 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
Jiri Slaby02f11752006-12-08 02:39:28 -08003222 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3223 /* Cy_HwReset is 0x1400 */
3224 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3225 /* Cy_ClrIntr is 0x1800 */
3226 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
Alan Cox15ed6cc2008-04-30 00:53:55 -07003228 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3229 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003230 base_addr =
3231 true_base_addr + (cy_chip_offset[chip_number] << index);
3232 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003233 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003234 /*************
3235 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3236 chip_number, (unsigned long)base_addr);
3237 *************/
3238 return chip_number;
3239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
Jiri Slaby02f11752006-12-08 02:39:28 -08003241 cy_writeb(base_addr + (CyGFRCR << index), 0);
3242 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
Jiri Slaby02f11752006-12-08 02:39:28 -08003244 /* The Cyclom-16Y does not decode address bit 9 and therefore
3245 cannot distinguish between references to chip 0 and a non-
3246 existent chip 4. If the preceding clearing of the supposed
3247 chip 4 GFRCR register appears at chip 0, there is no chip 4
3248 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3249 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003250 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003251 (cy_chip_offset[0] << index) +
3252 (CyGFRCR << index)) == 0) {
3253 return chip_number;
3254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
Jiri Slaby02f11752006-12-08 02:39:28 -08003256 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3257 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003259 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003260 /*
3261 printk(" chip #%d at %#6lx is not responding ",
3262 chip_number, (unsigned long)base_addr);
3263 printk("(GFRCR stayed 0)\n",
3264 */
3265 return chip_number;
3266 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003267 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003268 0x40) {
3269 /*
3270 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3271 "%#2x)\n",
3272 chip_number, (unsigned long)base_addr,
3273 base_addr[CyGFRCR<<index]);
3274 */
3275 return chip_number;
3276 }
3277 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003278 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003279 /* It is a CD1400 rev. J or later */
3280 /* Impossible to reach 5ms with this chip.
3281 Changed to 2ms instead (f = 500 Hz). */
3282 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3283 } else {
3284 /* f = 200 Hz */
3285 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3286 }
3287
3288 /*
3289 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3290 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003291 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003292 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003294 return chip_number;
3295} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
3297/*
3298 * ---------------------------------------------------------------------
3299 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3300 * sets global variables and return the number of ISA boards found.
3301 * ---------------------------------------------------------------------
3302 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003303static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
3305#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08003306 unsigned short cy_isa_irq, nboard;
3307 void __iomem *cy_isa_address;
3308 unsigned short i, j, cy_isa_nchan;
Jiri Slaby02f11752006-12-08 02:39:28 -08003309 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310
Jiri Slaby02f11752006-12-08 02:39:28 -08003311 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003314 for (i = 0; i < NR_CARDS; i++) {
3315 if (maddr[i] || i) {
3316 isparam = 1;
3317 cy_isa_addresses[i] = maddr[i];
3318 }
3319 if (!maddr[i])
3320 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322
Jiri Slaby02f11752006-12-08 02:39:28 -08003323 /* scan the address table probing for Cyclom-Y/ISA boards */
3324 for (i = 0; i < NR_ISA_ADDRS; i++) {
3325 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003326 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003327 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328
Jiri Slaby02f11752006-12-08 02:39:28 -08003329 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003330 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003331 if (cy_isa_address == NULL) {
3332 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3333 "address\n");
3334 continue;
3335 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003336 cy_isa_nchan = CyPORTS_PER_CHIP *
3337 cyy_init_card(cy_isa_address, 0);
3338 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003339 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003340 continue;
3341 }
Bartlomiej Zolnierkiewicz20904362009-12-09 12:34:14 -08003342
Roel Kluin196b3162009-10-01 15:44:24 -07003343 if (isparam && i < NR_CARDS && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003344 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 else
Jiri Slaby02f11752006-12-08 02:39:28 -08003346 /* find out the board's irq by probing */
3347 cy_isa_irq = detect_isa_irq(cy_isa_address);
3348 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003349 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3350 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003351 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003352 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003353 continue;
3354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355
Jiri Slaby02f11752006-12-08 02:39:28 -08003356 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003357 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3358 "more channels are available. Change NR_PORTS "
3359 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003360 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003361 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003362 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003363 }
3364 /* fill the next cy_card structure available */
3365 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07003366 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003367 break;
3368 }
3369 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003370 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3371 "more cards can be used. Change NR_CARDS in "
3372 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003373 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003374 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003375 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
Jiri Slaby02f11752006-12-08 02:39:28 -08003378 /* allocate IRQ */
3379 if (request_irq(cy_isa_irq, cyy_interrupt,
3380 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07003381 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3382 "could not allocate IRQ#%d.\n",
3383 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003384 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003385 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
Jiri Slaby02f11752006-12-08 02:39:28 -08003388 /* set cy_card */
3389 cy_card[j].base_addr = cy_isa_address;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003390 cy_card[j].ctl_addr.p9050 = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08003391 cy_card[j].irq = (int)cy_isa_irq;
3392 cy_card[j].bus_index = 0;
3393 cy_card[j].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003394 cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3395 cy_card[j].nports = cy_isa_nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003396 if (cy_init_card(&cy_card[j])) {
3397 cy_card[j].base_addr = NULL;
3398 free_irq(cy_isa_irq, &cy_card[j]);
3399 iounmap(cy_isa_address);
3400 continue;
3401 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003402 nboard++;
3403
Jiri Slaby21719192007-05-08 00:36:42 -07003404 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3405 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003406 j + 1, (unsigned long)cy_isa_address,
3407 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003408 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3409
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003410 for (j = cy_next_channel;
3411 j < cy_next_channel + cy_isa_nchan; j++)
3412 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003413 cy_next_channel += cy_isa_nchan;
3414 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003415 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003417 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003418#endif /* CONFIG_ISA */
3419} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
Jiri Slaby58936d82007-05-08 00:36:13 -07003421#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003422static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3423{
3424 unsigned int a;
3425
3426 for (a = 0; a < size && *str; a++, str++)
3427 if (*str & 0x80)
3428 return -EINVAL;
3429
3430 for (; a < size; a++, str++)
3431 if (*str)
3432 return -EINVAL;
3433
3434 return 0;
3435}
3436
David Woodhousef61e7612008-05-23 23:57:19 +01003437static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003438 unsigned int size)
3439{
3440 for (; size > 0; size--) {
3441 cy_writel(fpga, *data++);
3442 udelay(10);
3443 }
3444}
3445
3446static void __devinit plx_init(struct pci_dev *pdev, int irq,
3447 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
Jiri Slaby02f11752006-12-08 02:39:28 -08003449 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003450 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003451 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003452 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
Jiri Slaby02f11752006-12-08 02:39:28 -08003454 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003455 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003456 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003457 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3458
3459 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3460 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3461 * registers. This will remain here until we find a permanent fix.
3462 */
3463 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3464}
3465
3466static int __devinit __cyz_load_fw(const struct firmware *fw,
3467 const char *name, const u32 mailbox, void __iomem *base,
3468 void __iomem *fpga)
3469{
David Woodhousef61e7612008-05-23 23:57:19 +01003470 const void *ptr = fw->data;
3471 const struct zfile_header *h = ptr;
3472 const struct zfile_config *c, *cs;
3473 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003474 unsigned int a, tmp, len = fw->size;
3475#define BAD_FW KERN_ERR "Bad firmware: "
3476 if (len < sizeof(*h)) {
3477 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3478 return -EINVAL;
3479 }
3480
3481 cs = ptr + h->config_offset;
3482 bs = ptr + h->block_offset;
3483
3484 if ((void *)(cs + h->n_config) > ptr + len ||
3485 (void *)(bs + h->n_blocks) > ptr + len) {
3486 printk(BAD_FW "too short");
3487 return -EINVAL;
3488 }
3489
3490 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3491 cyc_isfwstr(h->date, sizeof(h->date))) {
3492 printk(BAD_FW "bad formatted header string\n");
3493 return -EINVAL;
3494 }
3495
3496 if (strncmp(name, h->name, sizeof(h->name))) {
3497 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3498 return -EINVAL;
3499 }
3500
3501 tmp = 0;
3502 for (c = cs; c < cs + h->n_config; c++) {
3503 for (a = 0; a < c->n_blocks; a++)
3504 if (c->block_list[a] > h->n_blocks) {
3505 printk(BAD_FW "bad block ref number in cfgs\n");
3506 return -EINVAL;
3507 }
3508 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3509 tmp++;
3510 }
3511 if (!tmp) {
3512 printk(BAD_FW "nothing appropriate\n");
3513 return -EINVAL;
3514 }
3515
3516 for (b = bs; b < bs + h->n_blocks; b++)
3517 if (b->file_offset + b->size > len) {
3518 printk(BAD_FW "bad block data offset\n");
3519 return -EINVAL;
3520 }
3521
3522 /* everything is OK, let's seek'n'load it */
3523 for (c = cs; c < cs + h->n_config; c++)
3524 if (c->mailbox == mailbox && c->function == 0)
3525 break;
3526
3527 for (a = 0; a < c->n_blocks; a++) {
3528 b = &bs[c->block_list[a]];
3529 if (b->type == ZBLOCK_FPGA) {
3530 if (fpga != NULL)
3531 cyz_fpga_copy(fpga, ptr + b->file_offset,
3532 b->size);
3533 } else {
3534 if (base != NULL)
3535 memcpy_toio(base + b->ram_offset,
3536 ptr + b->file_offset, b->size);
3537 }
3538 }
3539#undef BAD_FW
3540 return 0;
3541}
3542
3543static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3544 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3545{
3546 const struct firmware *fw;
3547 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3548 struct CUSTOM_REG __iomem *cust = base_addr;
3549 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003550 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003551 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003552 unsigned int i;
3553 int retval;
3554
3555 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3556 if (retval) {
3557 dev_err(&pdev->dev, "can't get firmware\n");
3558 goto err;
3559 }
3560
3561 /* Check whether the firmware is already loaded and running. If
3562 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003563 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003564 u32 cntval = readl(base_addr + 0x190);
3565
3566 udelay(100);
3567 if (cntval != readl(base_addr + 0x190)) {
3568 /* FW counter is working, FW is running */
3569 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3570 "Skipping board.\n");
3571 retval = 0;
3572 goto err_rel;
3573 }
3574 }
3575
3576 /* start boot */
3577 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3578 ~0x00030800UL);
3579
3580 mailbox = readl(&ctl_addr->mail_box_0);
3581
Jiri Slaby2693f482009-06-11 12:31:06 +01003582 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003583 /* stops CPU and set window to beginning of RAM */
3584 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3585 cy_writel(&cust->cpu_stop, 0);
3586 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3587 udelay(100);
3588 }
3589
3590 plx_init(pdev, irq, ctl_addr);
3591
3592 if (mailbox != 0) {
3593 /* load FPGA */
3594 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3595 base_addr);
3596 if (retval)
3597 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003598 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003599 dev_err(&pdev->dev, "fw upload successful, but fw is "
3600 "not loaded\n");
3601 goto err_rel;
3602 }
3603 }
3604
3605 /* stops CPU and set window to beginning of RAM */
3606 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3607 cy_writel(&cust->cpu_stop, 0);
3608 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3609 udelay(100);
3610
3611 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003612 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003613 cy_writeb(tmp, 255);
3614 if (mailbox != 0) {
3615 /* set window to last 512K of RAM */
3616 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003617 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003618 cy_writeb(tmp, 255);
3619 /* set window to beginning of RAM */
3620 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003621 }
3622
3623 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3624 release_firmware(fw);
3625 if (retval)
3626 goto err;
3627
3628 /* finish boot and start boards */
3629 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3630 cy_writel(&cust->cpu_start, 0);
3631 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3632 i = 0;
3633 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3634 msleep(100);
3635 if (status != ZFIRM_ID) {
3636 if (status == ZFIRM_HLT) {
3637 dev_err(&pdev->dev, "you need an external power supply "
3638 "for this number of ports. Firmware halted and "
3639 "board reset.\n");
3640 retval = -EIO;
3641 goto err;
3642 }
3643 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3644 "some more time\n", status);
3645 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3646 i++ < 200)
3647 msleep(100);
3648 if (status != ZFIRM_ID) {
3649 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3650 "Giving up. (fid->signature = 0x%x)\n",
3651 status);
3652 dev_info(&pdev->dev, "*** Warning ***: if you are "
3653 "upgrading the FW, please power cycle the "
3654 "system before loading the new FW to the "
3655 "Cyclades-Z.\n");
3656
Jiri Slaby2693f482009-06-11 12:31:06 +01003657 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003658 plx_init(pdev, irq, ctl_addr);
3659
3660 retval = -EIO;
3661 goto err;
3662 }
3663 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3664 i / 10);
3665 }
3666 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3667
3668 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3669 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3670 base_addr + readl(&fid->zfwctrl_addr));
3671
Jiri Slaby963118e2009-06-11 12:34:27 +01003672 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003673 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003674 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003675
Jiri Slaby963118e2009-06-11 12:34:27 +01003676 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003677 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3678 "check the connection between the Z host card and the "
3679 "serial expanders.\n");
3680
Jiri Slaby2693f482009-06-11 12:31:06 +01003681 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003682 plx_init(pdev, irq, ctl_addr);
3683
3684 dev_info(&pdev->dev, "Null number of ports detected. Board "
3685 "reset.\n");
3686 retval = 0;
3687 goto err;
3688 }
3689
3690 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3691 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3692
3693 /*
3694 Early firmware failed to start looking for commands.
3695 This enables firmware interrupts for those commands.
3696 */
3697 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3698 (1 << 17));
3699 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3700 0x00030800UL);
3701
Jiri Slaby963118e2009-06-11 12:34:27 +01003702 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003703err_rel:
3704 release_firmware(fw);
3705err:
3706 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707}
3708
Jiri Slaby58936d82007-05-08 00:36:13 -07003709static int __devinit cy_pci_probe(struct pci_dev *pdev,
3710 const struct pci_device_id *ent)
3711{
Jiri Slaby31375532007-05-08 00:37:04 -07003712 void __iomem *addr0 = NULL, *addr2 = NULL;
3713 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003714 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003715 unsigned int device_id, nchan = 0, card_no, i;
3716 unsigned char plx_ver;
3717 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003718
3719 retval = pci_enable_device(pdev);
3720 if (retval) {
3721 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003722 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003723 }
3724
3725 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003726 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003727 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3728
Jiri Slaby31375532007-05-08 00:37:04 -07003729#if defined(__alpha__)
3730 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3731 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3732 "addresses on Alpha systems.\n");
3733 retval = -EIO;
3734 goto err_dis;
3735 }
3736#endif
3737 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3738 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3739 "addresses\n");
3740 retval = -EIO;
3741 goto err_dis;
3742 }
3743
3744 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3745 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3746 "it...\n");
3747 pdev->resource[2].flags &= ~IORESOURCE_IO;
3748 }
3749
3750 retval = pci_request_regions(pdev, "cyclades");
3751 if (retval) {
3752 dev_err(&pdev->dev, "failed to reserve resources\n");
3753 goto err_dis;
3754 }
3755
3756 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003757 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3758 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003759 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003760
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003761 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3762 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003763 if (addr0 == NULL) {
3764 dev_err(&pdev->dev, "can't remap ctl region\n");
3765 goto err_reg;
3766 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003767 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3768 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003769 if (addr2 == NULL) {
3770 dev_err(&pdev->dev, "can't remap base region\n");
3771 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003772 }
3773
Jiri Slaby31375532007-05-08 00:37:04 -07003774 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3775 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003776 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3777 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003778 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003779 }
Jiri Slaby31375532007-05-08 00:37:04 -07003780 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3781 struct RUNTIME_9060 __iomem *ctl_addr;
3782
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003783 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3784 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003785 if (addr0 == NULL) {
3786 dev_err(&pdev->dev, "can't remap ctl region\n");
3787 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003788 }
3789
Jiri Slaby31375532007-05-08 00:37:04 -07003790 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003791 cy_writew(&ctl_addr->intr_ctrl_stat,
3792 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003793
Jiri Slaby054f5b02007-07-17 04:05:16 -07003794 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003795
Jiri Slaby101b8152009-06-11 12:30:10 +01003796 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003797
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003798 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3799 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003800 if (addr2 == NULL) {
3801 dev_err(&pdev->dev, "can't remap base region\n");
3802 goto err_unmap;
3803 }
3804
3805 if (mailbox == ZE_V1) {
3806 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003807 } else {
3808 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003809#ifdef CY_PCI_DEBUG
3810 if (mailbox == ZO_V1) {
3811 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3812 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3813 "id %lx, ver %lx\n", (ulong)(0xff &
3814 readl(&((struct CUSTOM_REG *)addr2)->
3815 fpga_id)), (ulong)(0xff &
3816 readl(&((struct CUSTOM_REG *)addr2)->
3817 fpga_version)));
3818 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3819 } else {
3820 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3821 "Cyclades-Z board. FPGA not loaded\n");
3822 }
3823#endif
3824 /* The following clears the firmware id word. This
3825 ensures that the driver will not attempt to talk to
3826 the board until it has been properly initialized.
3827 */
3828 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3829 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003830 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003831
3832 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003833 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003834 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003835 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003836 }
3837
3838 if ((cy_next_channel + nchan) > NR_PORTS) {
3839 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3840 "channels are available. Change NR_PORTS in "
3841 "cyclades.c and recompile kernel.\n");
3842 goto err_unmap;
3843 }
3844 /* fill the next cy_card structure available */
3845 for (card_no = 0; card_no < NR_CARDS; card_no++) {
3846 if (cy_card[card_no].base_addr == NULL)
3847 break;
3848 }
3849 if (card_no == NR_CARDS) { /* no more cy_cards available */
3850 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3851 "more cards can be used. Change NR_CARDS in "
3852 "cyclades.c and recompile kernel.\n");
3853 goto err_unmap;
3854 }
3855
3856 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3857 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003858 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07003859 retval = request_irq(irq, cyy_interrupt,
3860 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07003861 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07003862 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003863 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003864 }
Jiri Slaby963118e2009-06-11 12:34:27 +01003865 cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07003866 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003867 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3868 struct ZFW_CTRL __iomem *zfw_ctrl;
3869
3870 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3871
Jiri Slaby101b8152009-06-11 12:30:10 +01003872 cy_card[card_no].hw_ver = mailbox;
3873 cy_card[card_no].num_chips = (unsigned int)-1;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003874 cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07003875#ifdef CONFIG_CYZ_INTR
3876 /* allocate IRQ only if board has an IRQ */
3877 if (irq != 0 && irq != 255) {
3878 retval = request_irq(irq, cyz_interrupt,
3879 IRQF_SHARED, "Cyclades-Z",
3880 &cy_card[card_no]);
3881 if (retval) {
3882 dev_err(&pdev->dev, "could not allocate IRQ\n");
3883 goto err_unmap;
3884 }
3885 }
3886#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07003887 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003888
Jiri Slaby31375532007-05-08 00:37:04 -07003889 /* set cy_card */
3890 cy_card[card_no].base_addr = addr2;
Jiri Slaby97e87f82009-06-11 12:29:27 +01003891 cy_card[card_no].ctl_addr.p9050 = addr0;
Jiri Slaby31375532007-05-08 00:37:04 -07003892 cy_card[card_no].irq = irq;
3893 cy_card[card_no].bus_index = 1;
3894 cy_card[card_no].first_line = cy_next_channel;
Jiri Slaby963118e2009-06-11 12:34:27 +01003895 cy_card[card_no].nports = nchan;
Jiri Slaby31375532007-05-08 00:37:04 -07003896 retval = cy_init_card(&cy_card[card_no]);
3897 if (retval)
3898 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07003899
Jiri Slaby31375532007-05-08 00:37:04 -07003900 pci_set_drvdata(pdev, &cy_card[card_no]);
3901
3902 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3903 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003904 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07003905 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07003906 switch (plx_ver) {
3907 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07003908 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07003909 break;
3910
3911 case PLX_9060:
3912 case PLX_9080:
3913 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003914 {
3915 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3916 plx_init(pdev, irq, ctl_addr);
3917 cy_writew(&ctl_addr->intr_ctrl_stat,
3918 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07003919 break;
3920 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01003921 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003922 }
3923
Jiri Slaby31375532007-05-08 00:37:04 -07003924 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3925 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
3926 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
3927 tty_register_device(cy_serial_driver, i, &pdev->dev);
3928 cy_next_channel += nchan;
3929
Jiri Slaby58936d82007-05-08 00:36:13 -07003930 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07003931err_null:
3932 cy_card[card_no].base_addr = NULL;
3933 free_irq(irq, &cy_card[card_no]);
3934err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003935 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003936 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003937 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07003938err_reg:
3939 pci_release_regions(pdev);
3940err_dis:
3941 pci_disable_device(pdev);
3942err:
3943 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07003944}
Jiri Slaby58936d82007-05-08 00:36:13 -07003945
Jiri Slaby6747cd92007-05-08 00:36:34 -07003946static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947{
Jiri Slaby38d09092007-05-08 00:36:10 -07003948 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07003949 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07003950
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003951 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01003952 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07003953 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01003954 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003955 else
3956#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003957 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003958#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01003959 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3960 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3961 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003962
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003963 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01003964 if (cinfo->ctl_addr.p9050)
3965 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07003966 if (cinfo->irq
3967#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003968 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07003969#endif /* CONFIG_CYZ_INTR */
3970 )
3971 free_irq(cinfo->irq, cinfo);
3972 pci_release_regions(pdev);
3973
3974 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003975 for (i = cinfo->first_line; i < cinfo->first_line +
3976 cinfo->nports; i++)
3977 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07003978 cinfo->nports = 0;
3979 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07003980}
3981
Jiri Slaby6747cd92007-05-08 00:36:34 -07003982static struct pci_driver cy_pci_driver = {
3983 .name = "cyclades",
3984 .id_table = cy_pci_dev_id,
3985 .probe = cy_pci_probe,
3986 .remove = __devexit_p(cy_pci_remove)
3987};
3988#endif
3989
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003990static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991{
Jiri Slaby02f11752006-12-08 02:39:28 -08003992 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07003993 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08003994 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003996 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08003997 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998
Jiri Slaby02f11752006-12-08 02:39:28 -08003999 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07004000 for (i = 0; i < NR_CARDS; i++)
4001 for (j = 0; j < cy_card[i].nports; j++) {
4002 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08004003
Jiri Slabyd13549f2009-09-19 13:13:12 -07004004 if (info->port.count) {
4005 /* XXX is the ldisc num worth this? */
4006 struct tty_struct *tty;
4007 struct tty_ldisc *ld;
4008 int num = 0;
4009 tty = tty_port_tty_get(&info->port);
4010 if (tty) {
4011 ld = tty_ldisc_ref(tty);
4012 if (ld) {
4013 num = ld->ops->num;
4014 tty_ldisc_deref(ld);
4015 }
4016 tty_kref_put(tty);
4017 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004018 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004019 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004020 (cur_jifs - info->idle_stats.in_use) /
4021 HZ, info->idle_stats.xmit_bytes,
4022 (cur_jifs - info->idle_stats.xmit_idle)/
4023 HZ, info->idle_stats.recv_bytes,
4024 (cur_jifs - info->idle_stats.recv_idle)/
4025 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004026 num);
4027 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004028 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004029 "%10lu %8lu %9lu %6ld\n",
4030 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004031 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004032 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033}
4034
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004035static int cyclades_proc_open(struct inode *inode, struct file *file)
4036{
4037 return single_open(file, cyclades_proc_show, NULL);
4038}
4039
4040static const struct file_operations cyclades_proc_fops = {
4041 .owner = THIS_MODULE,
4042 .open = cyclades_proc_open,
4043 .read = seq_read,
4044 .llseek = seq_lseek,
4045 .release = single_release,
4046};
4047
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048/* The serial driver boot-time initialization code!
4049 Hardware I/O ports are mapped to character special devices on a
4050 first found, first allocated manner. That is, this code searches
4051 for Cyclom cards in the system. As each is found, it is probed
4052 to discover how many chips (and thus how many ports) are present.
4053 These ports are mapped to the tty ports 32 and upward in monotonic
4054 fashion. If an 8-port card is replaced with a 16-port card, the
4055 port mapping on a following card will shift.
4056
4057 This approach is different from what is used in the other serial
4058 device driver because the Cyclom is more properly a multiplexer,
4059 not just an aggregation of serial ports on one card.
4060
4061 If there are more cards with more ports than have been
4062 statically allocated above, a warning is printed and the
4063 extra ports are ignored.
4064 */
4065
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004066static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004067 .open = cy_open,
4068 .close = cy_close,
4069 .write = cy_write,
4070 .put_char = cy_put_char,
4071 .flush_chars = cy_flush_chars,
4072 .write_room = cy_write_room,
4073 .chars_in_buffer = cy_chars_in_buffer,
4074 .flush_buffer = cy_flush_buffer,
4075 .ioctl = cy_ioctl,
4076 .throttle = cy_throttle,
4077 .unthrottle = cy_unthrottle,
4078 .set_termios = cy_set_termios,
4079 .stop = cy_stop,
4080 .start = cy_start,
4081 .hangup = cy_hangup,
4082 .break_ctl = cy_break,
4083 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004084 .tiocmget = cy_tiocmget,
4085 .tiocmset = cy_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +01004086 .get_icount = cy_get_icount,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004087 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088};
4089
Jiri Slaby02f11752006-12-08 02:39:28 -08004090static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091{
Jiri Slabydd025c02007-05-08 00:37:02 -07004092 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004093 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094
Jiri Slaby02f11752006-12-08 02:39:28 -08004095 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4096 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004097 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004098
Michal Marek64a14b52011-04-01 12:41:20 +02004099 printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100
Jiri Slaby02f11752006-12-08 02:39:28 -08004101 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102
Jiri Slaby02f11752006-12-08 02:39:28 -08004103 cy_serial_driver->owner = THIS_MODULE;
4104 cy_serial_driver->driver_name = "cyclades";
4105 cy_serial_driver->name = "ttyC";
4106 cy_serial_driver->major = CYCLADES_MAJOR;
4107 cy_serial_driver->minor_start = 0;
4108 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4109 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4110 cy_serial_driver->init_termios = tty_std_termios;
4111 cy_serial_driver->init_termios.c_cflag =
4112 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004113 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004114 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004116 retval = tty_register_driver(cy_serial_driver);
4117 if (retval) {
4118 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4119 goto err_frtty;
4120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Jiri Slaby02f11752006-12-08 02:39:28 -08004122 /* the code below is responsible to find the boards. Each different
4123 type of board has its own detection routine. If a board is found,
4124 the next cy_card structure available is set by the detection
4125 routine. These functions are responsible for checking the
4126 availability of cy_card and cy_port data structures and updating
4127 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Jiri Slaby02f11752006-12-08 02:39:28 -08004129 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004130 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131
Jiri Slaby6747cd92007-05-08 00:36:34 -07004132#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004133 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004134 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004135 if (retval && !nboards) {
4136 tty_unregister_driver(cy_serial_driver);
4137 goto err_frtty;
4138 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004139#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004140
4141 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004142err_frtty:
4143 put_tty_driver(cy_serial_driver);
4144err:
4145 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004146} /* cy_init */
4147
4148static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149{
Jiri Slabydd025c02007-05-08 00:37:02 -07004150 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004151 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
4153#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004154 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155#endif /* CONFIG_CYZ_INTR */
4156
Alan Cox15ed6cc2008-04-30 00:53:55 -07004157 e1 = tty_unregister_driver(cy_serial_driver);
4158 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004159 printk(KERN_ERR "failed to unregister Cyclades serial "
4160 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161
Jiri Slaby6747cd92007-05-08 00:36:34 -07004162#ifdef CONFIG_PCI
4163 pci_unregister_driver(&cy_pci_driver);
4164#endif
4165
Jiri Slaby02f11752006-12-08 02:39:28 -08004166 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004167 card = &cy_card[i];
4168 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004169 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004170 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4171 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004172 if (card->ctl_addr.p9050)
4173 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004174 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004176 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004178 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004179 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004180 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004181 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004182 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004183 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004184 }
4185 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004186
4187 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188} /* cy_cleanup_module */
4189
4190module_init(cy_init);
4191module_exit(cy_cleanup_module);
4192
4193MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004194MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad2009-04-06 17:33:04 +01004195MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00004196MODULE_FIRMWARE("cyzfirm.bin");