cyclades.c revision 64a14b51bed6427a2e6d68ed687027f065f5a156
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	BLOCKMOVE
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	Z_WAKE
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	Z_EXT_CHARS_IN_BUFFER
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/drivers/char/cyclades.c
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file contains the driver for the Cyclades async multiport
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial boards.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Much of the design and some of the code came from serial.c
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which was copyright (C) 1991, 1992  Linus Torvalds.  It was
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and then fixed as suggested by Michael K. Johnson 12/12/92.
20c8e1693a4f63e317966f3dfe8f815eda95e26610Jiri Slaby * Converted to pci probing and cleaned up by Jiri Slaby.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby#define CY_VERSION	"2.6"
25096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If you need to install more boards than NR_CARDS, change the constant
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   in the definition below. No other change is necessary to support up to
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   eight boards. Beyond that you'll have to extend cy_isa_addresses. */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#define NR_CARDS	4
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If the total number of ports is larger than NR_PORTS, change this
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   constant in the definition below. No other change is necessary to
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   support more boards/ports. */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#define NR_PORTS	256
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZO_V1	0
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZO_V2	1
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZE_V1	2
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	SERIAL_PARANOIA_CHECK
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_OPEN
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_THROTTLE
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_OTHER
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_IO
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_COUNT
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_DTR
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_WAIT_UNTIL_SENT
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_INTERRUPTS
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_16Y_HACK
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_ENABLE_MONITORING
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_PCI_DEBUG
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * Include section
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
6633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox#include <linux/tty_flip.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cyclades.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
79054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#include <linux/firmware.h>
809f56fad741163fe2111cbbcfb7ff795ebdabdab1Scott James Remnant#include <linux/device.h>
815a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox#include <linux/io.h>
8415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox#include <linux/uaccess.h>
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h>
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
91444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan#include <linux/seq_file.h>
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_send_xchar(struct tty_struct *tty, char ch);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SERIAL_XMIT_SIZE
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	SERIAL_XMIT_SIZE	(min(PAGE_SIZE, 4096))
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STD_COM_FLAGS (0)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby/* firmware stuff */
102054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define ZL_MAX_BLOCKS	16
103054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define DRIVER_VERSION	0x02010203
104054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define RAM_SIZE 0x80000
105054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
106054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyenum zblock_type {
107054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	ZBLOCK_PRG = 0,
108054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	ZBLOCK_FPGA = 1
109054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby};
110054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
111054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystruct zfile_header {
112054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char name[64];
113054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char date[32];
114054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char aux[32];
115054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 n_config;
116054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 config_offset;
117054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 n_blocks;
118054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 block_offset;
119054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 reserved[9];
120054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby} __attribute__ ((packed));
121054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
122054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystruct zfile_config {
123054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char name[64];
124054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 mailbox;
125054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 function;
126054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 n_blocks;
127054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 block_list[ZL_MAX_BLOCKS];
128054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby} __attribute__ ((packed));
129054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
130054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystruct zfile_block {
131054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 type;
132054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 file_offset;
133054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 ram_offset;
134054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 size;
135054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby} __attribute__ ((packed));
136054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *cy_serial_driver;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is the address lookup table. The driver will probe for
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Cyclom-Y/ISA boards at all addresses in here. If you want the
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   driver to probe addresses at a different address, add it to
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   this table.  If the driver is probing some other board and
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   causing problems, remove the offending address from this table.
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int cy_isa_addresses[] = {
14802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD0000,
14902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD2000,
15002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD4000,
15102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD6000,
15202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD8000,
15302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xDA000,
15402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xDC000,
15502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xDE000,
15602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0, 0, 0, 0, 0, 0, 0, 0
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
159fe971071a89c5c5184fc9f3482c7a8e997cf0520Tobias Klauser#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1613046d50ea58676759453faeefccf57fbc9b72a90Jiri Slabystatic long maddr[NR_CARDS];
1623046d50ea58676759453faeefccf57fbc9b72a90Jiri Slabystatic int irq[NR_CARDS];
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(maddr, long, NULL, 0);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is the per-card data structure containing address, irq, number of
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   channels, etc. This driver supports a maximum of NR_CARDS cards.
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cyclades_card cy_card[NR_CARDS];
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_next_channel;	/* next minor available */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is used to look up the divisor speeds and the timeouts
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We're normally limited to 15 distinct baud rates.  The extra
17977451e53e0a509a98eda272567869cfe96431ba9Alan Cox * are accessed via settings in info->port.flags.
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                               HI            VHI
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     20
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
185ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const int baud_table[] = {
18602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
18702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
18802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	230400, 0
18902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
19002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
191ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_co_25[] = {	/* 25 MHz clock option table */
19202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* value =>    00    01   02    03    04 */
19302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* divide by    8    32   128   512  2048 */
19402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
19502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
19602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
19702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
198ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_bpr_25[] = {	/* 25 MHz baud rate period table */
19902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
20002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
20102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
20202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
203ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_co_60[] = {	/* 60 MHz clock option table (CD1400 J) */
20402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* value =>    00    01   02    03    04 */
20502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* divide by    8    32   128   512  2048 */
20602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
20702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
20802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00
20902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
21002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
211ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_bpr_60[] = {	/* 60 MHz baud rate period table (CD1400 J) */
21202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
21302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
21402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x21
21502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
21602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
217ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_cor3[] = {	/* receive threshold */
21802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
21902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
22002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x07
22102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The Cyclades driver implements HW flow control as any serial driver.
22515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * The cyclades_port structure member rflow and the vector rflow_thr
22615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * allows us to take advantage of a special feature in the CD1400 to avoid
22715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * data loss even when the system interrupt latency is too high. These flags
22815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * are to be used only with very special applications. Setting these flags
22915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * requires the use of a special cable (DTR and RTS reversed). In the new
23015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * CD1400-based boards (rev. 6.00 or later), there is no need for special
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cables.
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
234ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char rflow_thr[] = {	/* rflow threshold */
23502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
23702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0a
23802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*  The Cyclom-Ye has placed the sequential chips in non-sequential
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  address order.  This look-up table overcomes that problem.
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
243f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slabystatic const unsigned int cy_chip_offset[] = { 0x0000,
24402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0400,
24502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0800,
24602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0C00,
24702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0200,
24802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0600,
24902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0A00,
25002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0E00
25102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCI related definitions */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
256ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const struct pci_device_id cy_pci_dev_id[] = {
25715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* PCI < 1Mb */
25815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
25915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* PCI > 1Mb */
26015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
26115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 4Y PCI < 1Mb */
26215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
26315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 4Y PCI > 1Mb */
26415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
26515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 8Y PCI < 1Mb */
26615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
26715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 8Y PCI > 1Mb */
26815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
26915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* Z PCI < 1Mb */
27015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
27115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* Z PCI > 1Mb */
27215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
273893de2dffb0923d9bdba4abd66afcec3cf9103baJiri Slaby	{ }			/* end of table */
27402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
275893de2dffb0923d9bdba4abd66afcec3cf9103baJiri SlabyMODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cy_start(struct tty_struct *);
279d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
2801a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielkastatic int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned detect_isa_irq(void __iomem *);
28302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyz_poll(unsigned long);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The Cyclades-Z polling cycle is defined by this variable */
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long cyz_polling_cycle = CZ_DEF_POLL;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2918d06afab73a75f40ae2864e6c296356bab1ab473Ingo Molnarstatic DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#else				/* CONFIG_CYZ_INTR */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyz_rx_restart(unsigned long);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list cyz_rx_full_timer[NR_PORTS];
29602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2983aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
2993aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby{
3003aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = port->card;
3013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3023aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
3033aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3043aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3053aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
3063aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby{
3073aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = port->card;
3083aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3093aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	return readb(port->u.cyy.base_addr + (reg << card->bus_index));
3103aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3113aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3122693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool cy_is_Z(struct cyclades_card *card)
3132693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3142693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return card->num_chips == (unsigned int)-1;
3152693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3162693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3172693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
3182693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3192693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return readl(&ctl_addr->init_ctrl) & (1 << 17);
3202693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3212693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3222693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool cyz_fpga_loaded(struct cyclades_card *card)
3232693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3242693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return __cyz_fpga_loaded(card->ctl_addr.p9060);
3252693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3262693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3272693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool cyz_is_loaded(struct cyclades_card *card)
3282693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3292693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
3302693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3312693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
3322693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			readl(&fw_id->signature) == ZFIRM_ID;
3332693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3342693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
33502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic inline int serial_paranoia_check(struct cyclades_port *info,
336ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby		const char *name, const char *routine)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SERIAL_PARANOIA_CHECK
33902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!info) {
340217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
341217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"in %s\n", name, routine);
34202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 1;
34302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
34402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
34502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->magic != CYCLADES_MAGIC) {
346217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_WARNING "cyc Warning: bad magic number for serial "
347217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"struct (%s) in %s\n", name, routine);
34802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 1;
34902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
35102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
352ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby}
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********* Start of block of Cyclom-Y specific code ********/
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine waits up to 1000 micro-seconds for the previous
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   command to the Cirrus chip to complete and then issues the
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   new command.  An error is returned if the previous command
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   didn't finish within the time limit.
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This function is only called from inside spinlock-protected code.
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3643aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	void __iomem *ccr = base_addr + (CyCCR << index);
367ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby	unsigned int i;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Check to see that the previous command has completed */
37002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < 100; i++) {
3713aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		if (readb(ccr) == 0)
37202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
37302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(10L);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* if the CCR never cleared, the previous command
37602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   didn't finish within the "reasonable time" */
37702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (i == 100)
378096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return -1;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Issue the new command */
3813aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cy_writeb(ccr, cmd);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
3843aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3853aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3863aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
3873aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby{
3883aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
3893aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			port->card->bus_index);
3903aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ISA interrupt detection code */
39415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic unsigned detect_isa_irq(void __iomem *address)
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int irq;
39702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long irqs, flags;
39802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int save_xir, save_car;
39902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int index = 0;		/* IRQ probing is only for ISA */
40002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
40102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* forget possible initially masked and pending IRQ */
40202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	irq = probe_irq_off(probe_irq_on());
40302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
40402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Clear interrupts on the board first */
40502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (Cy_ClrIntr << index), 0);
40602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
40702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
40802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	irqs = probe_irq_on();
40902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Wait ... */
410f6e208c1119206e2382ef7df6e47aaee18eb7f10Jiri Slaby	msleep(5);
41102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Enable the Tx interrupts on the CD1400 */
41302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	local_irq_save(flags);
41402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), 0);
4153aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	__cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
41602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), 0);
41802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CySRER << index),
419db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		  readb(address + (CySRER << index)) | CyTxRdy);
42002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	local_irq_restore(flags);
42102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
42202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Wait ... */
423f6e208c1119206e2382ef7df6e47aaee18eb7f10Jiri Slaby	msleep(5);
42402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
42502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Check which interrupt is in use */
42602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	irq = probe_irq_off(irqs);
42702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
42802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Clean up */
429db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	save_xir = (u_char) readb(address + (CyTIR << index));
430db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	save_car = readb(address + (CyCAR << index));
43102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
43202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CySRER << index),
433db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		  readb(address + (CySRER << index)) & ~CyTxRdy);
43402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
43502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), (save_car));
43602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (Cy_ClrIntr << index), 0);
43702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
43802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
43902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return (irq > 0) ? irq : 0;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
443ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabystatic void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
444ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		void __iomem *base_addr)
445e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby{
446e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	struct cyclades_port *info;
447e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	struct tty_struct *tty;
44865f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int len, index = cinfo->bus_index;
4493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	u8 ivr, save_xir, channel, save_car, data, char_count;
450e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
451e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_DEBUG_INTERRUPTS
452ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
453e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
454ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* determine the channel & change to that context */
45565f76a82ec7a0374fad85211535330e203740475Jiri Slaby	save_xir = readb(base_addr + (CyRIR << index));
45665f76a82ec7a0374fad85211535330e203740475Jiri Slaby	channel = save_xir & CyIRChannel;
457ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	info = &cinfo->ports[channel + chip * 4];
4583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	save_car = cyy_readb(info, CyCAR);
4593aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_xir);
4603aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
461ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
462d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty = tty_port_tty_get(&info->port);
463ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* if there is nowhere to put the data, discard it */
464d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (tty == NULL) {
4653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		if (ivr == CyIVRRxEx) {	/* exception */
4663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			data = cyy_readb(info, CyRDSR);
467ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {	/* normal character reception */
4683aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			char_count = cyy_readb(info, CyRDCR);
469ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			while (char_count--)
4703aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				data = cyy_readb(info, CyRDSR);
471ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
472ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		goto end;
473ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
474ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* there is an open port for this data */
4753aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	if (ivr == CyIVRRxEx) {	/* exception */
4763aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		data = cyy_readb(info, CyRDSR);
477ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
478ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* For statistics only */
479ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (data & CyBREAK)
480ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.brk++;
481ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		else if (data & CyFRAME)
482ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.frame++;
483ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		else if (data & CyPARITY)
484ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.parity++;
485ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		else if (data & CyOVERRUN)
486ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.overrun++;
487ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
488ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (data & info->ignore_status_mask) {
489ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.rx++;
490d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty_kref_put(tty);
491ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			return;
492ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
493ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (tty_buffer_request_room(tty, 1)) {
494ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (data & info->read_status_mask) {
495ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (data & CyBREAK) {
496ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty,
4973aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
4983aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_BREAK);
499ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
50077451e53e0a509a98eda272567869cfe96431ba9Alan Cox					if (info->port.flags & ASYNC_SAK)
501ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby						do_SAK(tty);
502ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else if (data & CyFRAME) {
50315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox					tty_insert_flip_char(tty,
5043aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
5053aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_FRAME);
506ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
507ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->idle_stats.frame_errs++;
508ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else if (data & CyPARITY) {
509ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					/* Pieces of seven... */
510ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty,
5113aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
5123aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_PARITY);
513ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
514ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->idle_stats.parity_errs++;
515ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else if (data & CyOVERRUN) {
516ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty, 0,
517ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby							TTY_OVERRUN);
518ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
519ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					/* If the flip buffer itself is
520ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					   overflowing, we still lose
521ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					   the next incoming character.
522ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					 */
523ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty,
5243aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
5253aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_FRAME);
52602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					info->icount.rx++;
52702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					info->idle_stats.overruns++;
528ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* These two conditions may imply */
529ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* a normal read should be done. */
530ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* } else if(data & CyTIMEOUT) { */
531ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* } else if(data & CySPECHAR) { */
532ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else {
533ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty, 0,
534ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby							TTY_NORMAL);
535ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
53602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
537ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			} else {
538ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				tty_insert_flip_char(tty, 0, TTY_NORMAL);
539ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				info->icount.rx++;
540ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			}
541ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {
542ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			/* there was a software buffer overrun and nothing
543ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			 * could be done about it!!! */
544ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.buf_overrun++;
545ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->idle_stats.overruns++;
546ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
547ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	} else {	/* normal character reception */
548ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* load # chars available from the chip */
5493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		char_count = cyy_readb(info, CyRDCR);
550e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
551e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_ENABLE_MONITORING
552ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		++info->mon.int_count;
553ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->mon.char_count += char_count;
554ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (char_count > info->mon.char_max)
555ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->mon.char_max = char_count;
556ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->mon.char_last = char_count;
557e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
558ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		len = tty_buffer_request_room(tty, char_count);
559ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		while (len--) {
5603aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			data = cyy_readb(info, CyRDSR);
561ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			tty_insert_flip_char(tty, data, TTY_NORMAL);
562ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->idle_stats.recv_bytes++;
563ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.rx++;
564e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_16Y_HACK
565ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			udelay(10L);
566e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
567e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
568ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->idle_stats.recv_idle = jiffies;
569e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	}
570ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	tty_schedule_flip(tty);
571d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_kref_put(tty);
572ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabyend:
573ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* end of service */
5743aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyRIR, save_xir & 0x3f);
5753aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_car);
576ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby}
577e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
57865f76a82ec7a0374fad85211535330e203740475Jiri Slabystatic void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
579ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		void __iomem *base_addr)
580ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby{
581ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	struct cyclades_port *info;
582d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	struct tty_struct *tty;
58365f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int char_count, index = cinfo->bus_index;
58465f76a82ec7a0374fad85211535330e203740475Jiri Slaby	u8 save_xir, channel, save_car, outch;
585ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
586ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* Since we only get here when the transmit buffer
587ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	   is empty, we know we can always stuff a dozen
588ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	   characters. */
589e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_DEBUG_INTERRUPTS
590ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
591e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
592e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
593ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* determine the channel & change to that context */
59465f76a82ec7a0374fad85211535330e203740475Jiri Slaby	save_xir = readb(base_addr + (CyTIR << index));
59565f76a82ec7a0374fad85211535330e203740475Jiri Slaby	channel = save_xir & CyIRChannel;
596ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	save_car = readb(base_addr + (CyCAR << index));
597ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	cy_writeb(base_addr + (CyCAR << index), save_xir);
598ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
599ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	info = &cinfo->ports[channel + chip * 4];
600d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty = tty_port_tty_get(&info->port);
601d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (tty == NULL) {
6023aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
603ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		goto end;
604ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
60502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
606ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* load the on-chip space for outbound data */
607ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	char_count = info->xmit_fifo_size;
60802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
609ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (info->x_char) {	/* send special char */
610ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		outch = info->x_char;
6113aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTDR, outch);
612ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		char_count--;
613ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->icount.tx++;
614ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->x_char = 0;
615ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
61602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
617ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (info->breakon || info->breakoff) {
618ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (info->breakon) {
6193aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0);
6203aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0x81);
621ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->breakon = 0;
622ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			char_count -= 2;
623e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
624ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (info->breakoff) {
6253aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0);
6263aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0x83);
627ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->breakoff = 0;
628ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			char_count -= 2;
629e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
630ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
63102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
632ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	while (char_count-- > 0) {
633ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (!info->xmit_cnt) {
6343aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			if (cyy_readb(info, CySRER) & CyTxMpty) {
6353aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER,
6363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					cyy_readb(info, CySRER) & ~CyTxMpty);
637ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			} else {
6383aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER, CyTxMpty |
6393aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					(cyy_readb(info, CySRER) & ~CyTxRdy));
64002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
641ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			goto done;
642ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
64377451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.xmit_buf == NULL) {
6443aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CySRER,
6453aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_readb(info, CySRER) & ~CyTxRdy);
646ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			goto done;
647ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
648d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		if (tty->stopped || tty->hw_stopped) {
6493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CySRER,
6503aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_readb(info, CySRER) & ~CyTxRdy);
651ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			goto done;
652ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
653ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* Because the Embedded Transmit Commands have been enabled,
654ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * we must check to see if the escape character, NULL, is being
655ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * sent. If it is, we must ensure that there is room for it to
656ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * be doubled in the output stream.  Therefore we no longer
657ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * advance the pointer when the character is fetched, but
658ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * rather wait until after the check for a NULL output
659ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * character. This is necessary because there may not be room
660ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * for the two chars needed to send a NULL.)
661ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 */
66277451e53e0a509a98eda272567869cfe96431ba9Alan Cox		outch = info->port.xmit_buf[info->xmit_tail];
663ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (outch) {
664ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->xmit_cnt--;
665ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->xmit_tail = (info->xmit_tail + 1) &
666ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					(SERIAL_XMIT_SIZE - 1);
6673aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, outch);
668ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.tx++;
669ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {
670ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (char_count > 1) {
67102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->xmit_cnt--;
67202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->xmit_tail = (info->xmit_tail + 1) &
673ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					(SERIAL_XMIT_SIZE - 1);
6743aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CyTDR, outch);
6753aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CyTDR, 0);
67602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->icount.tx++;
677ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				char_count--;
67802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
679e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
680e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	}
681e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
682ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabydone:
683d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_wakeup(tty);
684d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_kref_put(tty);
685ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabyend:
686ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* end of service */
6873aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyTIR, save_xir & 0x3f);
6883aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_car);
689ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby}
69002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
691ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabystatic void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
692ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		void __iomem *base_addr)
693ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby{
694ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	struct cyclades_port *info;
695d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	struct tty_struct *tty;
69665f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int index = cinfo->bus_index;
69765f76a82ec7a0374fad85211535330e203740475Jiri Slaby	u8 save_xir, channel, save_car, mdm_change, mdm_status;
698ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
699ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* determine the channel & change to that context */
70065f76a82ec7a0374fad85211535330e203740475Jiri Slaby	save_xir = readb(base_addr + (CyMIR << index));
70165f76a82ec7a0374fad85211535330e203740475Jiri Slaby	channel = save_xir & CyIRChannel;
702ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	info = &cinfo->ports[channel + chip * 4];
7033aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	save_car = cyy_readb(info, CyCAR);
7043aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_xir);
705ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
7063aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	mdm_change = cyy_readb(info, CyMISR);
7073aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	mdm_status = cyy_readb(info, CyMSVR1);
708ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
709d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty = tty_port_tty_get(&info->port);
710d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (!tty)
711ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		goto end;
712ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
713ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (mdm_change & CyANY_DELTA) {
714ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* For statistics only */
715ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyDCD)
716ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.dcd++;
717ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyCTS)
718ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.cts++;
719ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyDSR)
720ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.dsr++;
721ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyRI)
722ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.rng++;
723ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
724bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		wake_up_interruptible(&info->port.delta_msr_wait);
725ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
726ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
72777451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
728174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby		if (mdm_status & CyDCD)
729174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby			wake_up_interruptible(&info->port.open_wait);
730174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby		else
731d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty_hangup(tty);
732ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
73377451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
734d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		if (tty->hw_stopped) {
735ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (mdm_status & CyCTS) {
736ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* cy_start isn't used
737ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				   because... !!! */
738d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty->hw_stopped = 0;
7393aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER,
7403aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					cyy_readb(info, CySRER) | CyTxRdy);
741d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty_wakeup(tty);
74202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
743ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {
744ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (!(mdm_status & CyCTS)) {
745ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* cy_stop isn't used
746ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				   because ... !!! */
747d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty->hw_stopped = 1;
7483aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER,
7493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					cyy_readb(info, CySRER) & ~CyTxRdy);
75002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
751e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
752e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	}
753ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby/*	if (mdm_change & CyDSR) {
754ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
755ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (mdm_change & CyRI) {
756ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}*/
757d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_kref_put(tty);
758ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabyend:
759ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* end of service */
7603aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyMIR, save_xir & 0x3f);
7613aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_car);
762e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby}
763e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The real interrupt service routine is called
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   whenever the card wants its hand held--chars
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   received, out buffer empty, modem change, etc.
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
76802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic irqreturn_t cyy_interrupt(int irq, void *dev_id)
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
77002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int status;
771f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	struct cyclades_card *cinfo = dev_id;
77202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *base_addr, *card_base_addr;
77365f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int chip, too_many, had_work;
77402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int index;
77502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
776f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	if (unlikely(cinfo == NULL)) {
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
77815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
77915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox				irq);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
78102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return IRQ_NONE;	/* spurious interrupt */
78202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
78302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
78402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card_base_addr = cinfo->base_addr;
78502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	index = cinfo->bus_index;
78602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
787f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby	/* card was not initialized yet (e.g. DEBUG_SHIRQ) */
788f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby	if (unlikely(card_base_addr == NULL))
789f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby		return IRQ_HANDLED;
790f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby
79102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* This loop checks all chips in the card.  Make a note whenever
79202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   _any_ chip had some work to do, as this is considered an
79302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   indication that there will be more to do.  Only when no chip
79402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   has any work does this outermost loop exit.
79502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
79602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	do {
79702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		had_work = 0;
79802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (chip = 0; chip < cinfo->num_chips; chip++) {
79902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			base_addr = cinfo->base_addr +
80002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(cy_chip_offset[chip] << index);
80102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			too_many = 0;
802db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			while ((status = readb(base_addr +
80302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						(CySVRR << index))) != 0x00) {
80402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				had_work++;
80502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* The purpose of the following test is to ensure that
80602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   no chip can monopolize the driver.  This forces the
80702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   chips to be checked in a round-robin fashion (after
80802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   draining each of a bunch (1000) of characters).
80902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
810ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (1000 < too_many++)
81102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					break;
8121c0a387c1f9e48e480579d3b4e0f9c1a36c77751Jiri Slaby				spin_lock(&cinfo->card_lock);
813ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (status & CySRReceive) /* rx intr */
814ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					cyy_chip_rx(cinfo, chip, base_addr);
815ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (status & CySRTransmit) /* tx intr */
816ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					cyy_chip_tx(cinfo, chip, base_addr);
817ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (status & CySRModem) /* modem intr */
818ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					cyy_chip_modem(cinfo, chip, base_addr);
8191c0a387c1f9e48e480579d3b4e0f9c1a36c77751Jiri Slaby				spin_unlock(&cinfo->card_lock);
82002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
82102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
82202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} while (had_work);
82302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
82402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* clear interrupts */
82502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	spin_lock(&cinfo->card_lock);
82602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
82702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
82802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	spin_unlock(&cinfo->card_lock);
82902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return IRQ_HANDLED;
83002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyy_interrupt */
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8324d7682005ca88a37667c4af03908798e188b5224Jiri Slabystatic void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
8334d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		unsigned int clear)
8344d7682005ca88a37667c4af03908798e188b5224Jiri Slaby{
8354d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	struct cyclades_card *card = info->card;
8363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel = info->line - card->first_line;
8370d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	u32 rts, dtr, msvrr, msvrd;
8384d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
8394d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	channel &= 0x03;
8404d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
8410d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	if (info->rtsdtr_inv) {
8420d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrr = CyMSVR2;
8430d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrd = CyMSVR1;
8440d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rts = CyDTR;
8450d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		dtr = CyRTS;
8460d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	} else {
8470d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrr = CyMSVR1;
8480d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrd = CyMSVR2;
8490d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rts = CyRTS;
8500d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		dtr = CyDTR;
8510d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	}
8524d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (set & TIOCM_RTS) {
8533aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8543aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrr, rts);
8554d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8564d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (clear & TIOCM_RTS) {
8573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrr, ~rts);
8594d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8604d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (set & TIOCM_DTR) {
8613aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8623aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrd, dtr);
8634d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#ifdef CY_DEBUG_DTR
8644d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
8654d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
8663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR1),
8673aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR2));
8684d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#endif
8694d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8704d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (clear & TIOCM_DTR) {
8713aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8723aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrd, ~dtr);
8734d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#ifdef CY_DEBUG_DTR
8744d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
8754d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
8763aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR1),
8773aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR2));
8784d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#endif
8794d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8804d7682005ca88a37667c4af03908798e188b5224Jiri Slaby}
8814d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********* End of block of Cyclom-Y specific code **********/
88415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox/******** Start of block of Cyclades-Z specific code *******/
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
88802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabycyz_fetch_msg(struct cyclades_card *cinfo,
88915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		__u32 *channel, __u8 *cmd, __u32 *param)
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
891f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
89202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long loc_doorbell;
89302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
89497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
89502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (loc_doorbell) {
89602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		*cmd = (char)(0xff & loc_doorbell);
897db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		*channel = readl(&board_ctrl->fwcmd_channel);
898db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		*param = (__u32) readl(&board_ctrl->fwcmd_param);
89997e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
90002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 1;
90102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
90202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
90302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_fetch_msg */
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
90602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabycyz_issue_cmd(struct cyclades_card *cinfo,
9071a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka		__u32 channel, __u8 cmd, __u32 param)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
909f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
9101a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u32 __iomem *pci_doorbell;
91165f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int index;
91202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
9132693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cyz_is_loaded(cinfo))
914096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return -1;
91515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
91602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	index = 0;
91797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
918db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	while ((readl(pci_doorbell) & 0xff) != 0) {
91915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (index++ == 1000)
920db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			return (int)(readl(pci_doorbell) & 0xff);
92102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(50L);
92202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
92302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writel(&board_ctrl->hcmd_channel, channel);
92402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writel(&board_ctrl->hcmd_param, param);
92502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writel(pci_doorbell, (long)cmd);
92602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
927096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
92802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_issue_cmd */
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
930f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slabystatic void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
932f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
933875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
93465f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int char_count;
93502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int len;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
937ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby	unsigned char *buf;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
93902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char data;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
941ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby	__u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
943db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
944db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_put = readl(&buf_ctrl->rx_put);
945db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_bufsize = readl(&buf_ctrl->rx_bufsize);
946db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
94702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (rx_put >= rx_get)
94802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = rx_put - rx_get;
94902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	else
95002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = rx_put - rx_get + rx_bufsize;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_count) {
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_ENABLE_MONITORING
95402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->mon.int_count++;
95502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->mon.char_count += char_count;
95602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (char_count > info->mon.char_max)
95702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->mon.char_max = char_count;
95802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->mon.char_last = char_count;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
960f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby		if (tty == NULL) {
96102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* flush received characters */
96202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			new_rx_get = (new_rx_get + char_count) &
96302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(rx_bufsize - 1);
96402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->rflush_count++;
96502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
96702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
96802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   for performance, but because of buffer boundaries, there
96902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   may be several steps to the operation */
970ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby			while (1) {
971ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				len = tty_prepare_flip_string(tty, &buf,
972ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby						char_count);
973ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				if (!len)
974ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby					break;
975ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby
976ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				len = min_t(unsigned int, min(len, char_count),
977ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby						rx_bufsize - new_rx_get);
978ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby
979ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				memcpy_fromio(buf, cinfo->base_addr +
980ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby						rx_bufaddr + new_rx_get, len);
981ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby
982ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				new_rx_get = (new_rx_get + len) &
98302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						(rx_bufsize - 1);
984ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				char_count -= len;
985ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				info->icount.rx += len;
986ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				info->idle_stats.recv_bytes += len;
98702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
98902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			len = tty_buffer_request_room(tty, char_count);
99002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			while (len--) {
991db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				data = readb(cinfo->base_addr + rx_bufaddr +
99202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						new_rx_get);
99315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox				new_rx_get = (new_rx_get + 1) &
99415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox							(rx_bufsize - 1);
99502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				tty_insert_flip_char(tty, data, TTY_NORMAL);
99602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->idle_stats.recv_bytes++;
99702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->icount.rx++;
99802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
100102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Recalculate the number of chars in the RX buffer and issue
100202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   a cmd in case it's higher than the RX high water mark */
1003db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			rx_put = readl(&buf_ctrl->rx_put);
100402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (rx_put >= rx_get)
100502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				char_count = rx_put - rx_get;
100602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
100702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				char_count = rx_put - rx_get + rx_bufsize;
100865f76a82ec7a0374fad85211535330e203740475Jiri Slaby			if (char_count >= readl(&buf_ctrl->rx_threshold) &&
1009ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby					!timer_pending(&cyz_rx_full_timer[
1010ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby							info->line]))
1011ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby				mod_timer(&cyz_rx_full_timer[info->line],
1012ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby						jiffies + 1);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
101402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->idle_stats.recv_idle = jiffies;
101502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_schedule_flip(tty);
101602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
101702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Update rx_get */
101802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&buf_ctrl->rx_get, new_rx_get);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1022f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slabystatic void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1024f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1025875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
102665f76a82ec7a0374fad85211535330e203740475Jiri Slaby	u8 data;
102765f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int char_count;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
102902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int small_count;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1031ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby	__u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
103402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1036db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_get = readl(&buf_ctrl->tx_get);
1037db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_put = readl(&buf_ctrl->tx_put);
1038db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1039db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
104002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tx_put >= tx_get)
104102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = tx_get - tx_put - 1 + tx_bufsize;
104202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	else
104302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = tx_get - tx_put - 1;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
104502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_count) {
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1047f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby		if (tty == NULL)
104802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			goto ztxdone;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
105002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->x_char) {	/* send special char */
105102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			data = info->x_char;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
105302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
105402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tx_put = (tx_put + 1) & (tx_bufsize - 1);
105502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->x_char = 0;
105602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count--;
105702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.tx++;
105802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
106002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		while (0 < (small_count = min_t(unsigned int,
106102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				tx_bufsize - tx_put, min_t(unsigned int,
106202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(SERIAL_XMIT_SIZE - info->xmit_tail),
106302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					min_t(unsigned int, info->xmit_cnt,
106402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						char_count))))) {
106502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
106602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
106702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					tx_put),
106877451e53e0a509a98eda272567869cfe96431ba9Alan Cox					&info->port.xmit_buf[info->xmit_tail],
106902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					small_count);
107002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
107102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tx_put = (tx_put + small_count) & (tx_bufsize - 1);
107202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count -= small_count;
107302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.tx += small_count;
107402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_cnt -= small_count;
107502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_tail = (info->xmit_tail + small_count) &
107602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(SERIAL_XMIT_SIZE - 1);
107702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
107902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		while (info->xmit_cnt && char_count) {
108077451e53e0a509a98eda272567869cfe96431ba9Alan Cox			data = info->port.xmit_buf[info->xmit_tail];
108102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_cnt--;
108202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_tail = (info->xmit_tail + 1) &
108302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(SERIAL_XMIT_SIZE - 1);
108402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
108502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
108602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tx_put = (tx_put + 1) & (tx_bufsize - 1);
108702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count--;
108802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.tx++;
108902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1091ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby		tty_wakeup(tty);
10927fa57a0cd98bdd163eeb5f15cbe234c3a0cf68a1Jiri Slabyztxdone:
109302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Update tx_put */
109402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&buf_ctrl->tx_put, tx_put);
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cyz_handle_cmd(struct cyclades_card *cinfo)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1100f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
110102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct tty_struct *tty;
110202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
1103101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby	__u32 channel, param, fw_ver;
11041a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u8 cmd;
110502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int special_count;
110602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int delta_count;
110702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1108db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	fw_ver = readl(&board_ctrl->fw_version);
110902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
111002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
111102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		special_count = 0;
111202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		delta_count = 0;
1113dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		info = &cinfo->ports[channel];
1114d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty = tty_port_tty_get(&info->port);
111515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (tty == NULL)
111602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
1117f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby
111802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cmd) {
111902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_PR_ERROR:
112002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_insert_flip_char(tty, 0, TTY_PARITY);
112102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rx++;
112202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			special_count++;
112302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
112402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_FR_ERROR:
112502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_insert_flip_char(tty, 0, TTY_FRAME);
112602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rx++;
112702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			special_count++;
112802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
112902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_RXBRK:
113002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_insert_flip_char(tty, 0, TTY_BREAK);
113102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rx++;
113202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			special_count++;
113302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
113402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MDCD:
113502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.dcd++;
113602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
113777451e53e0a509a98eda272567869cfe96431ba9Alan Cox			if (info->port.flags & ASYNC_CHECK_CD) {
1138f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				u32 dcd = fw_ver > 241 ? param :
1139f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby					readl(&info->u.cyz.ch_ctrl->rs_status);
1140174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby				if (dcd & C_RS_DCD)
114177451e53e0a509a98eda272567869cfe96431ba9Alan Cox					wake_up_interruptible(&info->port.open_wait);
1142174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby				else
1143d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					tty_hangup(tty);
114402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
114502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
114602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MCTS:
114702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.cts++;
114802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
114902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
115002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MRI:
115102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rng++;
115202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
115302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
115402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MDSR:
115502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.dsr++;
115602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
115702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_WAKE
115902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_IOCTLW:
1160ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby			complete(&info->shutdown_wait);
116102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
116402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_RXHIWM:
116502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_RXNNDT:
116602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_INTBACK2:
116702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Reception Interrupt */
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
1169217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1170217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"port %ld\n", info->card, channel);
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1172f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			cyz_handle_rx(info, tty);
117302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
117402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_TXBEMPTY:
117502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_TXLOWWM:
117602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_INTBACK:
117702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Transmission Interrupt */
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
1179217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1180217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"port %ld\n", info->card, channel);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1182f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			cyz_handle_tx(info, tty);
118302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
118402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
118502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_FATAL:
118602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* should do something with this !!! */
118702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
118802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		default:
118902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
119002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
119102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (delta_count)
1192bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox			wake_up_interruptible(&info->port.delta_msr_wait);
119302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (special_count)
119402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_schedule_flip(tty);
1195d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty_kref_put(tty);
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
120002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic irqreturn_t cyz_interrupt(int irq, void *dev_id)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1202f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	struct cyclades_card *cinfo = dev_id;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12042693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (unlikely(!cyz_is_loaded(cinfo))) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
1206217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1207217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"(IRQ%d).\n", irq);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
120902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return IRQ_NONE;
121002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Handle the interrupts */
121302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cyz_handle_cmd(cinfo);
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return IRQ_HANDLED;
121602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_interrupt */
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cyz_rx_restart(unsigned long arg)
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
122002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info = (struct cyclades_port *)arg;
1221875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card = info->card;
122202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int retval;
1223875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	__u32 channel = info->line - card->first_line;
122402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
122502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
12269fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
1227875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
122802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (retval != 0) {
1229217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
123002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->line, retval);
123102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
12329fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#else				/* CONFIG_CYZ_INTR */
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cyz_poll(unsigned long arg)
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
123902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
124002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
1241b70509066cba24067757f1422c899c43e433429dJiri Slaby	unsigned long expires = jiffies + HZ;
124265f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int port, card;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (card = 0; card < NR_CARDS; card++) {
124502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cinfo = &cy_card[card];
124602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
12472693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(cinfo))
124802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
12492693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(cinfo))
125002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
125102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Skip first polling cycle to avoid racing conditions with the FW */
125302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (!cinfo->intr_enabled) {
125402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cinfo->intr_enabled = 1;
125502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
125602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cyz_handle_cmd(cinfo);
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
126002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (port = 0; port < cinfo->nports; port++) {
1261d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			struct tty_struct *tty;
1262d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby
1263dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			info = &cinfo->ports[port];
1264d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty = tty_port_tty_get(&info->port);
1265d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			/* OK to pass NULL to the handle functions below.
1266d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			   They need to drop the data in that case. */
1267d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby
126802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->throttle)
1269f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				cyz_handle_rx(info, tty);
1270f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			cyz_handle_tx(info, tty);
1271d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty_kref_put(tty);
127202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
127302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* poll every 'cyz_polling_cycle' period */
1274b70509066cba24067757f1422c899c43e433429dJiri Slaby		expires = jiffies + cyz_polling_cycle;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1276b70509066cba24067757f1422c899c43e433429dJiri Slaby	mod_timer(&cyz_timerlist, expires);
127702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_poll */
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** End of block of Cyclades-Z specific code *********/
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is called whenever a port becomes active;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   interrupts are enabled and DTR & RTS are turned on.
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1287d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1289875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
129002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
129102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int retval = 0;
1292cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	int channel;
129302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long page;
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
129502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
1296875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
129802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	page = get_zeroed_page(GFP_KERNEL);
129902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!page)
130002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENOMEM;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13029fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1304cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	if (info->port.flags & ASYNC_INITIALIZED)
130502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto errout;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
130702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!info->type) {
1308d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		set_bit(TTY_IO_ERROR, &tty->flags);
130902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto errout;
131002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131277451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (info->port.xmit_buf)
131302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		free_page(page);
131402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	else
131577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.xmit_buf = (unsigned char *)page;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13179fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1319d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_set_line_char(info, tty);
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13212693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
132202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		channel &= 0x03;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13249fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13263aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13283aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR,
132902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(info->default_timeout ? info->default_timeout : 0x02));
133002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* 10ms rx timeout */
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13323aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13344d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
133702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
1338f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13402693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
134102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1344217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1345f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			"base_addr %p\n", card, channel, card->base_addr);
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
13479fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1349f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_WAKE
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
1352f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable,
135302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
135402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1356f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable,
135702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_IOCTLW | C_IN_MDCD);
135802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
1361f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable,
136202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
136302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_RXNNDT | C_IN_MDCD);
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1365f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
136602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
136702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_WAKE */
136802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1369875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
137002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
1371217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1372217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"%x\n", info->line, retval);
137302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
137502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Flush RX buffers before raising DTR and RTS */
1376875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
137702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
1378217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1379217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"%x\n", info->line, retval);
138002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
138202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set timeout !!! */
138302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set RTS and DTR !!! */
13844d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		tty_port_raise_dtr_rts(&info->port);
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
138602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* enable send, recv, modem !!! */
1387cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	}
138802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1389cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->port.flags |= ASYNC_INITIALIZED;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	clear_bit(TTY_IO_ERROR, &tty->flags);
1392cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1393cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->breakon = info->breakoff = 0;
1394cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1395cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->idle_stats.in_use =
1396cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->idle_stats.recv_idle =
1397cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->idle_stats.xmit_idle = jiffies;
1398cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby
1399cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1402217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc startup done\n");
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserrout:
14079fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
1408cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	free_page(page);
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
141002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* startup */
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void start_xmit(struct cyclades_port *info)
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14143aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
141502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
14163aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel = info->line - card->first_line;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14182693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
14199fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
14203aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
14213aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
14229fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
142302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
142502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14279fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
1428875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
142902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
1430217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1431217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"%x\n", info->line, retval);
143202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
14339fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
143402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#else				/* CONFIG_CYZ_INTR */
143502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Don't have to do anything at this time */
143602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
143702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
143802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* start_xmit */
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine shuts down a serial port; interrupts are disabled,
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and DTR is dropped if the hangup on close termio flag is on.
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1444d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1446875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
144702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
14483aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
144902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
145077451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!(info->port.flags & ASYNC_INITIALIZED))
145102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
145202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
145302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
1454875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
14552693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
14569fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
145702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
145802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Clear delta_msr_wait queue to avoid mem leaks. */
1459bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		wake_up_interruptible(&info->port.delta_msr_wait);
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
146177451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.xmit_buf) {
146202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			unsigned char *temp;
146377451e53e0a509a98eda272567869cfe96431ba9Alan Cox			temp = info->port.xmit_buf;
146477451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.xmit_buf = NULL;
146502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			free_page((unsigned long)temp);
146602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
14674d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (tty->termios->c_cflag & HUPCL)
14684d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
14694d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
14703aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
147102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* it may be appropriate to clear _XMIT at
147202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   some later date (after testing)!!! */
147302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1474d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		set_bit(TTY_IO_ERROR, &tty->flags);
147577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_INITIALIZED;
14769fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
147702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1479217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
1480f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			"base_addr %p\n", card, channel, card->base_addr);
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14832693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
148402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14869fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.xmit_buf) {
148902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			unsigned char *temp;
149077451e53e0a509a98eda272567869cfe96431ba9Alan Cox			temp = info->port.xmit_buf;
149177451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.xmit_buf = NULL;
149202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			free_page((unsigned long)temp);
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
149402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
14954d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (tty->termios->c_cflag & HUPCL)
14964d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			tty_port_lower_dtr_rts(&info->port);
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1498d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		set_bit(TTY_IO_ERROR, &tty->flags);
149977451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_INITIALIZED;
150002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
15019fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
150202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1505217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc shutdown done\n");
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
150702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* shutdown */
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_open() and friends
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called whenever a serial port is opened.  It
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * performs the serial-specific initialization for the tty structure.
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
151902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_open(struct tty_struct *tty, struct file *filp)
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
152102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
152265f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int i, line;
152365f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int retval;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	line = tty->index;
152615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (tty->index < 0 || NR_PORTS <= line)
152702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
152815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
1529dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	for (i = 0; i < NR_CARDS; i++)
1530dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		if (line < cy_card[i].first_line + cy_card[i].nports &&
1531dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby				line >= cy_card[i].first_line)
1532dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			break;
1533dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	if (i >= NR_CARDS)
1534dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		return -ENODEV;
1535dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	info = &cy_card[i].ports[line - cy_card[i].first_line];
153615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->line < 0)
153702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* If the card's firmware hasn't been loaded,
154002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   treat it as absent from the system.  This
154102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   will make the user pay attention.
154202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
15432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(info->card)) {
1544875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		struct cyclades_card *cinfo = info->card;
154502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
154602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
15472693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(cinfo)) {
15482693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
1549101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby					readl(&firm_id->signature) ==
1550101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby					ZFIRM_HLT) {
1551217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1552217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"need an external power supply for "
1553217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"this number of ports.\nFirmware "
1554217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"halted.\n");
155502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			} else {
1556217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1557217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"yet loaded\n");
155802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
155902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
156002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
156102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CONFIG_CYZ_INTR
156202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else {
156302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* In case this Z board is operating in interrupt mode, its
156402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   interrupts should be enabled as soon as the first open
156502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   happens to one of its ports. */
156602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!cinfo->intr_enabled) {
156797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				u16 intr;
156802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
156902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* Enable interrupts on the PLX chip */
157097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				intr = readw(&cinfo->ctl_addr.p9060->
157197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby						intr_ctrl_stat) | 0x0900;
157297e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				cy_writew(&cinfo->ctl_addr.p9060->
157397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby						intr_ctrl_stat, intr);
157402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* Enable interrupts on the FW */
157502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				retval = cyz_issue_cmd(cinfo, 0,
157602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						C_CM_IRQ_ENBL, 0L);
157702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (retval != 0) {
1578217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					printk(KERN_ERR "cyc:IRQ enable retval "
1579217191910c0286e0b3c7e3011630273695253da3Jiri Slaby						"was %x\n", retval);
158002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
158102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cinfo->intr_enabled = 1;
158202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
158402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
158502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Make sure this Z port really exists in hardware */
158602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->line > (cinfo->first_line + cinfo->nports - 1))
158702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
1590217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
159202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	tty->driver_data = info;
159315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_open"))
159402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
159515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1597217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
159877451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.count);
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
160077451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.count++;
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_COUNT
1602217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
160377451e53e0a509a98eda272567869cfe96431ba9Alan Cox		current->pid, info->port.count);
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
160602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
160702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * If the port is the middle of closing, bail out now
160802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
160977451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1610be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann		wait_event_interruptible_tty(info->port.close_wait,
161177451e53e0a509a98eda272567869cfe96431ba9Alan Cox				!(info->port.flags & ASYNC_CLOSING));
161277451e53e0a509a98eda272567869cfe96431ba9Alan Cox		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
161302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
161602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Start up serial port
161702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
1618d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	retval = cy_startup(info, tty);
161915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (retval)
162002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return retval;
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1622f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	retval = tty_port_block_til_ready(&info->port, tty, filp);
162302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (retval) {
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1625217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1626217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			"with %d\n", retval);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
162802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return retval;
162902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
163102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->throttle = 0;
1632d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_port_tty_set(&info->port, tty);
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
163402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CY_DEBUG_OPEN
1635217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open done\n");
163602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif
163702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
163802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_open */
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_wait_until_sent() --- wait until the transmitter is empty
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
164302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_wait_until_sent(struct tty_struct *tty, int timeout)
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1645875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
1646cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
164702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long orig_jiffies;
164802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int char_time;
164902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
165002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
165102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
165202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
165302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_fifo_size == 0)
165402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;		/* Just in case.... */
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
165602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	orig_jiffies = jiffies;
165702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
165802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Set the check interval to be 1/5 of the estimated time to
165902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * send a single character, and make it at least 1.  The check
166002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * interval should also be less than the timeout.
166102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 *
166202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Note: we have to use pretty tight timings here to satisfy
166302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * the NIST-PCTS.
166402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
166502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
166602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char_time = char_time / 5;
166702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_time <= 0)
166802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_time = 1;
166902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (timeout < 0)
167002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		timeout = 0;
167102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (timeout)
167202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_time = min(char_time, timeout);
167302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
167402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * If the transmitter hasn't cleared in twice the approximate
167502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * amount of time to send the entire FIFO, it probably won't
167602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * ever clear.  This assumes the UART isn't doing flow
167702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * control, which is currently the case.  Hence, if it ever
167802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * takes longer than info->timeout, this is probably due to a
167902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * UART bug of some kind.  So, we clamp the timeout parameter at
168002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * 2*info->timeout.
168102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
168202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!timeout || timeout > 2 * info->timeout)
168302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		timeout = 2 * info->timeout;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_WAIT_UNTIL_SENT
1685217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
1686217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		timeout, char_time, jiffies);
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
168802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
16892693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
16903aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		while (cyy_readb(info, CySRER) & CyTxRdy) {
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_WAIT_UNTIL_SENT
1692217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
169402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (msleep_interruptible(jiffies_to_msecs(char_time)))
169502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
169602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (timeout && time_after(jiffies, orig_jiffies +
169702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					timeout))
169802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
169902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
170102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Run one more char cycle */
170202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	msleep_interruptible(jiffies_to_msecs(char_time * 5));
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_WAIT_UNTIL_SENT
1704217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1708978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Coxstatic void cy_flush_buffer(struct tty_struct *tty)
1709978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox{
1710978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct cyclades_port *info = tty->driver_data;
1711978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct cyclades_card *card;
1712978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	int channel, retval;
1713978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	unsigned long flags;
1714978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1715978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox#ifdef CY_DEBUG_IO
1716978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1717978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox#endif
1718978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1719978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1720978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		return;
1721978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1722978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	card = info->card;
1723978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	channel = info->line - card->first_line;
1724978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1725978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_lock_irqsave(&card->card_lock, flags);
1726978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1727978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_unlock_irqrestore(&card->card_lock, flags);
1728978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
17292693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1730978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox					   buffers as well */
1731978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		spin_lock_irqsave(&card->card_lock, flags);
1732978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1733978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		if (retval != 0) {
1734978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox			printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1735978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox				"was %x\n", info->line, retval);
1736978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		}
1737978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		spin_unlock_irqrestore(&card->card_lock, flags);
1738978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	}
1739978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	tty_wakeup(tty);
1740978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox}				/* cy_flush_buffer */
1741978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1742978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1743e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Coxstatic void cy_do_close(struct tty_port *port)
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1745e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	struct cyclades_port *info = container_of(port, struct cyclades_port,
1746e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox								port);
17479fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	struct cyclades_card *card;
174802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
17493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17519fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	card = info->card;
17523aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	channel = info->line - card->first_line;
17539fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
175402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
17552693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
175602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Stop accepting input */
17573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
17583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
175977451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.flags & ASYNC_INITIALIZED) {
176015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			/* Waiting for on-board buffers to be empty before
176115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			   closing the port */
17629fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
1763e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox			cy_wait_until_sent(port->tty, info->timeout);
17649fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
176502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
176602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
176702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef Z_WAKE
176815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		/* Waiting for on-board buffers to be empty before closing
176915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		   the port */
1770f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
177102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
177202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1773f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
17749fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
177502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
1776217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_DEBUG "cyc:cy_close retval on "
1777217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"ttyC%d was %x\n", info->line, retval);
177802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
17799fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
17802c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby			wait_for_completion_interruptible(&info->shutdown_wait);
17819fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
178202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
178402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
17859fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
1786e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	cy_shutdown(info, port->tty);
1787e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox}
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1789e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox/*
1790e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox * This routine is called when a particular tty device is closed.
1791e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox */
1792e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Coxstatic void cy_close(struct tty_struct *tty, struct file *filp)
1793e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox{
1794e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	struct cyclades_port *info = tty->driver_data;
1795e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1796e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox		return;
1797e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	tty_port_close(&info->port, tty, filp);
179802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_close */
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine gets called when tty_write has put something into
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the write_queue.  The characters may come from user space or
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kernel space.
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will return the number of characters actually
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accepted for writing.
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is not already transmitting stuff, start it off by
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabling interrupts.  The interrupt service routine will then
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that the characters are sent.
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is already active, there is no need to kick it.
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
181302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1815cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
181602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
181702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int c, ret = 0;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1820217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
182315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_write"))
182402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
182677451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!info->port.xmit_buf)
182702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18299fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
183002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	while (1) {
18311a4e2351e7fcf2d10bb5524b0ace7797ffad4d98Harvey Harrison		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
18321a4e2351e7fcf2d10bb5524b0ace7797ffad4d98Harvey Harrison		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
183302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
183402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (c <= 0)
183502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
183602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
183777451e53e0a509a98eda272567869cfe96431ba9Alan Cox		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
183802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->xmit_head = (info->xmit_head + c) &
183902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(SERIAL_XMIT_SIZE - 1);
184002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->xmit_cnt += c;
184102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		buf += c;
184202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		count -= c;
184302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret += c;
184402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
18459fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
184602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
184702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->idle_stats.xmit_bytes += ret;
184802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->idle_stats.xmit_idle = jiffies;
184902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
185015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
185102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		start_xmit(info);
185215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
185302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret;
185402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_write */
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the kernel to write a single
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * character to the tty device.  If the kernel uses this routine,
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it must call the flush_chars() routine (if defined) when it is
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * done stuffing characters into the driver.  If there is no room
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the queue, the character is ignored.
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
186376b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Coxstatic int cy_put_char(struct tty_struct *tty, unsigned char ch)
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1865cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
186602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1869217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
187202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
187376b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
187577451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!info->port.xmit_buf)
187676b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18789fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
187990cc301859ea8840634324a7f5b9680312377667Jiri Slaby	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
18809fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&info->card->card_lock, flags);
188176b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
188202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188477451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.xmit_buf[info->xmit_head++] = ch;
188502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
188602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->xmit_cnt++;
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->idle_stats.xmit_bytes++;
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->idle_stats.xmit_idle = jiffies;
18899fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
189076b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox	return 1;
189102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_put_char */
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the kernel after it has written a
189515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * series of characters to the tty device using put_char().
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
189702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_flush_chars(struct tty_struct *tty)
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1899cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
190002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1902217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
190502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
190602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
190802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
190977451e53e0a509a98eda272567869cfe96431ba9Alan Cox			!info->port.xmit_buf)
191002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	start_xmit(info);
191302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_flush_chars */
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine returns the numbers of characters the tty driver
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will accept for queuing to be written.  This number is subject
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to change as output buffers get emptied, or if the output flow
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control is activated.
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
192102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_write_room(struct tty_struct *tty)
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1923cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
192402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int ret;
192502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1927217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
193002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_write_room"))
193102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
193202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
193302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (ret < 0)
193402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret = 0;
193502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret;
193602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_write_room */
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
193802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_chars_in_buffer(struct tty_struct *tty)
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1940cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
194202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
194302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
194402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_EXT_CHARS_IN_BUFFER
1946f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	if (!cy_is_Z(info->card)) {
194702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_EXT_CHARS_IN_BUFFER */
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1949217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1950217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			info->line, info->xmit_cnt);
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
195202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return info->xmit_cnt;
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_EXT_CHARS_IN_BUFFER
195402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
1955f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
195602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int char_count;
1957ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby		__u32 tx_put, tx_get, tx_bufsize;
195802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1959db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_get = readl(&buf_ctrl->tx_get);
1960db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_put = readl(&buf_ctrl->tx_put);
1961db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
196202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (tx_put >= tx_get)
196302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count = tx_put - tx_get;
196402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
196502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count = tx_put - tx_get + tx_bufsize;
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1967217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1968217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			info->line, info->xmit_cnt + char_count);
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1970096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return info->xmit_cnt + char_count;
197102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
197202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_EXT_CHARS_IN_BUFFER */
197302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_chars_in_buffer */
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_ioctl() and friends
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19811a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielkastatic void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
198302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int co, co_val, bpr;
19841a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
198502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			25000000);
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (baud == 0) {
198802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->tbpr = info->tco = info->rbpr = info->rco = 0;
198902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
199002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* determine which prescaler to use */
199302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
199402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_clock / co_val / baud > 63)
199502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
199602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
199902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (bpr > 255)
200002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		bpr = 255;
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
200202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->tbpr = info->rbpr = bpr;
200302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->tco = info->rco = co;
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine finds or computes the various line characteristics.
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It used to be called config_setup
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2010d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2012875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
201302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
20143aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
201502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned cflag, iflag;
201602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int baud, baud_rate = 0;
201702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int i;
201802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2019d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (!tty->termios) /* XXX can this happen at all? */
202002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
202115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
202215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->line == -1)
202302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
202415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
2025d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cflag = tty->termios->c_cflag;
2026d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	iflag = tty->termios->c_iflag;
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
202802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
202902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Set up the tty->alt_speed kludge
203002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
2031d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2032d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 57600;
2033d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2034d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 115200;
2035d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2036d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 230400;
2037d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2038d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 460800;
203902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
204002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
2041875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
204202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
20432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
204446fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		u32 cflags;
204546fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby
204602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* baud rate */
2047d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		baud = tty_get_baud_rate(tty);
204877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
204902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
205002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->custom_divisor)
205102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud / info->custom_divisor;
205202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
205302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud;
205402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud > CD1400_MAX_SPEED) {
205502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			baud = CD1400_MAX_SPEED;
205602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
205702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* find the baud index */
205802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (i = 0; i < 20; i++) {
205915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (baud == baud_table[i])
206002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
206102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
206215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (i == 20)
206302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			i = 19;	/* CD1400_MAX_SPEED */
206402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
206577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
206602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
206702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cyy_baud_calc(info, baud_rate);
206802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
206902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->chip_rev >= CD1400_REV_J) {
207002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* It is a CD1400 rev. J or later */
207102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tbpr = baud_bpr_60[i];	/* Tx BPR */
207202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tco = baud_co_60[i];	/* Tx CO */
207302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rbpr = baud_bpr_60[i];	/* Rx BPR */
207402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rco = baud_co_60[i];	/* Rx CO */
207502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			} else {
207602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tbpr = baud_bpr_25[i];	/* Tx BPR */
207702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tco = baud_co_25[i];	/* Tx CO */
207802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rbpr = baud_bpr_25[i];	/* Rx BPR */
207902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rco = baud_co_25[i];	/* Rx CO */
208002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
208102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
208202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud_table[i] == 134) {
208302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* get it right for 134.5 baud */
208402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
208502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					2;
208677451e53e0a509a98eda272567869cfe96431ba9Alan Cox		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
208702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
208802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
208902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_rate) + 2;
209002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud_table[i]) {
209102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
209202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_table[i]) + 2;
209302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* this needs to be propagated into the card info */
209402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
209502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = 0;
209602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
209702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* By tradition (is it a standard?) a baud rate of zero
209802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   implies the line should be/has been closed.  A bit
209902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   later in this routine such a test is performed. */
210002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
210102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* byte size and parity */
210202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor5 = 0;
210302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor4 = 0;
210402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* receive threshold */
210502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 = (info->default_threshold ?
210602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->default_threshold : baud_cor3[i]);
210702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor2 = CyETC;
210802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cflag & CSIZE) {
210902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS5:
211002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_5_BITS;
211102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
211202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS6:
211302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_6_BITS;
211402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
211502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS7:
211602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_7_BITS;
211702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
211802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS8:
211902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_8_BITS;
212002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
212102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
212215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (cflag & CSTOPB)
212302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 |= Cy_2_STOP;
212415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
212502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & PARENB) {
212615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (cflag & PARODD)
212702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->cor1 |= CyPARITY_O;
212815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			else
212902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->cor1 |= CyPARITY_E;
213015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		} else
213102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 |= CyPARITY_NONE;
213202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
213302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CTS flow control flag */
213402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CRTSCTS) {
213577451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CTS_FLOW;
213602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor2 |= CyCtsAE;
213702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
213877451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CTS_FLOW;
213902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor2 &= ~CyCtsAE;
214002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
214102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CLOCAL)
214277451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CHECK_CD;
214302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
214477451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CHECK_CD;
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 /***********************************************
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    The hardware option, CyRtsAO, presents RTS when
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    the chip has characters to send.  Since most modems
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    use RTS as reverse (inbound) flow control, this
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    option is not used.  If inbound flow control is
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    necessary, DTR can be programmed to provide the
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    appropriate signals for use with a non-standard
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cable.  Contact Marcio Saito for details.
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 ***********************************************/
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
215602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		channel &= 0x03;
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21589fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
21593aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
216002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
216102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* tx and rx baud rate */
216202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21633aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTCOR, info->tco);
21643aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTBPR, info->tbpr);
21653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRCOR, info->rco);
21663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRBPR, info->rbpr);
216702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
216802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set line characteristics  according configuration */
216902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21703aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySCHR1, START_CHAR(tty));
21713aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
21723aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR1, info->cor1);
21733aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR2, info->cor2);
21743aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR3, info->cor3);
21753aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR4, info->cor4);
21763aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR5, info->cor5);
217702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21783aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
21793aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				CyCOR3ch);
218002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
218115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		/* !!! Is this needed? */
21823aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
21833aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR,
218402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(info->default_timeout ? info->default_timeout : 0x02));
218502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* 10ms rx timeout */
218602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
218746fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cflags = CyCTS;
218846fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		if (!C_CLOCAL(tty))
218946fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cflags |= CyDSR | CyRI | CyDCD;
219046fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* without modem intr */
219146fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
219246fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* act on 1->0 modem transitions */
219346fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		if ((cflag & CRTSCTS) && info->rflow)
219446fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
219546fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		else
219646fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cyy_writeb(info, CyMCOR1, cflags);
219746fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* act on 0->1 modem transitions */
219846fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cyy_writeb(info, CyMCOR2, cflags);
219902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
22004d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (i == 0)	/* baud rate is zero, turn off line */
22014d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_DTR);
22024d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		else
22034d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, TIOCM_DTR, 0);
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2205d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		clear_bit(TTY_IO_ERROR, &tty->flags);
22069fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2209f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
22101a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka		__u32 sw_flow;
221102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22132693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
221402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return;
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* baud rate */
2217d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		baud = tty_get_baud_rate(tty);
221877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
221902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
222002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->custom_divisor)
222102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud / info->custom_divisor;
222202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
222302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud;
222402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud > CYZ_MAX_SPEED) {
222502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			baud = CYZ_MAX_SPEED;
222602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
222702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&ch_ctrl->comm_baud, baud);
222802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
222902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud == 134) {
223002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* get it right for 134.5 baud */
223102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
223202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					2;
223377451e53e0a509a98eda272567869cfe96431ba9Alan Cox		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
223402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
223502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
223602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_rate) + 2;
223702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud) {
223802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
223902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud) + 2;
224002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* this needs to be propagated into the card info */
224102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
224202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = 0;
224302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
224502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* byte size and parity */
224602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cflag & CSIZE) {
224702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS5:
224802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
224902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
225002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS6:
225102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
225202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
225302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS7:
225402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
225502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
225602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS8:
225702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
225802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
225902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
226002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CSTOPB) {
226102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l,
2262db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
226302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
226402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l,
2265db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
226602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
226702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & PARENB) {
226815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (cflag & PARODD)
226902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
227015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			else
227102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
227215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		} else
227302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
227502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CTS flow control flag */
227602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CRTSCTS) {
227702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->hw_flow,
2278db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
227902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
2280db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2281db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby					~(C_RS_CTS | C_RS_RTS));
228202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
228302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* As the HW flow control is done in firmware, the driver
228402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   doesn't need to care about it */
228577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_CTS_FLOW;
228602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
228702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* XON/XOFF/XANY flow control flags */
228802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		sw_flow = 0;
228902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (iflag & IXON) {
229002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			sw_flow |= C_FL_OXX;
229102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (iflag & IXANY)
229202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				sw_flow |= C_FL_OIXANY;
229302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
229402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&ch_ctrl->sw_flow, sw_flow);
229502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2296875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
229702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2298217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2299217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
230002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
230102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
230202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CD sensitivity */
230315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (cflag & CLOCAL)
230477451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CHECK_CD;
230515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		else
230677451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CHECK_CD;
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
230802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud == 0) {	/* baud rate is zero, turn off line */
230902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->rs_control,
2310db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
2312217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
231402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
231502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->rs_control,
2316db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
2318217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
232002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
232215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
232302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2324217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2325217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
232602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2328d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		clear_bit(TTY_IO_ERROR, &tty->flags);
23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
233002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_line_char */
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23326c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slabystatic int cy_get_serial_info(struct cyclades_port *info,
233315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		struct serial_struct __user *retinfo)
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2335875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
23366c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct serial_struct tmp = {
23376c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.type = info->type,
23386c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.line = info->line,
23396c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.port = (info->card - cy_card) * 0x100 + info->line -
23406c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			cinfo->first_line,
23416c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.irq = cinfo->irq,
23426c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.flags = info->port.flags,
23436c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.close_delay = info->port.close_delay,
23446c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.closing_wait = info->port.closing_wait,
23456c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.baud_base = info->baud,
23466c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.custom_divisor = info->custom_divisor,
23476c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.hub6 = 0,		/*!!! */
23486c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	};
234902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
23506c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby}
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2353d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabycy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
235415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		struct serial_struct __user *new_info)
23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
235602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct serial_struct new_serial;
235725c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	int ret;
235802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
235902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
236002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -EFAULT;
236102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
236225c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	mutex_lock(&info->port.mutex);
236302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!capable(CAP_SYS_ADMIN)) {
236444b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		if (new_serial.close_delay != info->port.close_delay ||
236502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				new_serial.baud_base != info->baud ||
236602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(new_serial.flags & ASYNC_FLAGS &
236702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					~ASYNC_USR_MASK) !=
236877451e53e0a509a98eda272567869cfe96431ba9Alan Cox				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
236925c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		{
237025c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox			mutex_unlock(&info->port.mutex);
237102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -EPERM;
237225c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		}
237377451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
237402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(new_serial.flags & ASYNC_USR_MASK);
237502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->baud = new_serial.baud_base;
237602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->custom_divisor = new_serial.custom_divisor;
237702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto check_and_exit;
237802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
237902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
238002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
238102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * OK, past this point, all the error checking has been done.
238202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * At this point, we start making changes.....
238302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
238402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
238502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->baud = new_serial.baud_base;
238602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->custom_divisor = new_serial.custom_divisor;
238777451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
238802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(new_serial.flags & ASYNC_FLAGS);
238944b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	info->port.close_delay = new_serial.close_delay * HZ / 100;
239044b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_and_exit:
239377451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (info->port.flags & ASYNC_INITIALIZED) {
2394d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		cy_set_line_char(info, tty);
239525c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		ret = 0;
239602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
239725c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		ret = cy_startup(info, tty);
239802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
239925c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	mutex_unlock(&info->port.mutex);
240025c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	return ret;
240102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_serial_info */
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_lsr_info - get line status register info
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Purpose: Let user call ioctl() to get info when the UART physically
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    is emptied.  On bus types like RS485, the transmitter must
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    release the bus after transmitting. This must be done when
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    the transmit shift register is empty, not be done when the
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    transmit holding register is empty.  This functionality
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    allows an RS485 driver to be written in user space.
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
241315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24153aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
241602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned int result;
241702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
24183aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	u8 status;
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24202693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24219fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24223aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
24239fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
242402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		result = (status ? 0 : TIOCSER_TEMT);
242502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
242602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Not supported yet */
242702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -EINVAL;
242802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
242902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return put_user(result, (unsigned long __user *)value);
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243260b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int cy_tiocmget(struct tty_struct *tty)
24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2434cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2435875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
24363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int result;
243702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2438bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison	if (serial_paranoia_check(info, tty->name, __func__))
243902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
24420d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24440d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		unsigned long flags;
24453aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		int channel = info->line - card->first_line;
24463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 status;
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24489fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
24503aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status = cyy_readb(info, CyMSVR1);
24513aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status |= cyy_readb(info, CyMSVR2);
24529fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
245302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
245402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->rtsdtr_inv) {
245502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			result = ((status & CyRTS) ? TIOCM_DTR : 0) |
245602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				((status & CyDTR) ? TIOCM_RTS : 0);
245702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
245802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			result = ((status & CyRTS) ? TIOCM_RTS : 0) |
245902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				((status & CyDTR) ? TIOCM_DTR : 0);
246002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
246102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
246202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyRI) ? TIOCM_RNG : 0) |
246302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyDSR) ? TIOCM_DSR : 0) |
246402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyCTS) ? TIOCM_CTS : 0);
24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
24660d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		u32 lstatus;
24670d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24680d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (!cyz_is_loaded(card)) {
24690d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			result = -ENODEV;
24700d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			goto end;
247102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24730d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
24740d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
24750d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
24760d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
24770d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
24780d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
24790d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
248002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
24810d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slabyend:
248202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return result;
248302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_tiomget */
24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
248620b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxcy_tiocmset(struct tty_struct *tty,
248702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		unsigned int set, unsigned int clear)
24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2489cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2490875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
249102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
249202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2493bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison	if (serial_paranoia_check(info, tty->name, __func__))
249402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
249502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
249602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
24972693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24984d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24994d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		cyy_change_rts_dtr(info, set, clear);
25004d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
250102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
25020d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
25030d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		int retval, channel = info->line - card->first_line;
25040d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		u32 rs;
25050d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
25060d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (!cyz_is_loaded(card))
25070d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			return -ENODEV;
25080d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
25090d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
25100d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rs = readl(&ch_ctrl->rs_control);
25110d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (set & TIOCM_RTS)
25120d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs |= C_RS_RTS;
25130d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (clear & TIOCM_RTS)
25140d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs &= ~C_RS_RTS;
25150d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (set & TIOCM_DTR) {
25160d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs |= C_RS_DTR;
25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
25180d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
25200d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		}
25210d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (clear & TIOCM_DTR) {
25220d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs &= ~C_RS_DTR;
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
25240d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			printk(KERN_DEBUG "cyc:set_modem_info clearing "
25250d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby				"Z DTR\n");
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
252702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
25280d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		cy_writel(&ch_ctrl->rs_control, rs);
25299fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
25300d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
253102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2532217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2533217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
253402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
253602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
25370d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby}
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_break() --- routine which turns the break handling on or off
25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
25429e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int cy_break(struct tty_struct *tty, int break_state)
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2544cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
25459fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	struct cyclades_card *card;
254602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
25479e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	int retval = 0;
25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
254902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_break"))
25509e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox		return -EINVAL;
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25529fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	card = info->card;
25539fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby
25549fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
25552693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
255602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Let the transmit ISR take care of this (since it
255702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   requires stuffing characters into the output stream).
255802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
255902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (break_state == -1) {
256002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->breakon) {
256102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->breakon = 1;
256202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (!info->xmit_cnt) {
25639fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_unlock_irqrestore(&card->card_lock, flags);
256402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					start_xmit(info);
25659fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_lock_irqsave(&card->card_lock, flags);
256602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
256702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
256802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
256902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->breakoff) {
257002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->breakoff = 1;
257102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (!info->xmit_cnt) {
25729fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_unlock_irqrestore(&card->card_lock, flags);
257302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					start_xmit(info);
25749fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_lock_irqsave(&card->card_lock, flags);
257502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
257602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
257902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (break_state == -1) {
25809fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card,
25819fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby				info->line - card->first_line,
258202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				C_CM_SET_BREAK, 0L);
258302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
2584217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:cy_break (set) retval on "
2585217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"ttyC%d was %x\n", info->line, retval);
258602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
258702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
25889fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card,
25899fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby				info->line - card->first_line,
259002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				C_CM_CLR_BREAK, 0L);
259102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
2592217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2593217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"on ttyC%d was %x\n", info->line,
2594217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					retval);
259502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25989fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
25999e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	return retval;
260002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_break */
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int set_threshold(struct cyclades_port *info, unsigned long value)
26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26043aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
260502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26072693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
260802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 &= ~CyREC_FIFO;
260902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 |= value & CyREC_FIFO;
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26119fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
26123aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR3, info->cor3);
26133aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
26149fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
261502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
261602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
261702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_threshold */
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_threshold(struct cyclades_port *info,
262015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox						unsigned long __user *value)
26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26223aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26242693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26253aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
262602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return put_user(tmp, value);
262702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2628f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	return 0;
262902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* get_threshold */
26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
263102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int set_timeout(struct cyclades_port *info, unsigned long value)
26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
263402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26362693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26379fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
26383aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR, value & 0xff);
26399fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
264002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
264102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
264202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_timeout */
26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
264415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_timeout(struct cyclades_port *info,
264515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox						unsigned long __user *value)
26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26473aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26492693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26503aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 tmp = cyy_readb(info, CyRTPR);
265102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return put_user(tmp, value);
265202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2653f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	return 0;
265402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* get_timeout */
26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26566c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slabystatic int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
26576c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		struct cyclades_icount *cprev)
26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26596c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct cyclades_icount cnow;
26606c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	unsigned long flags;
26616c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	int ret;
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26636c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
26646c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	cnow = info->icount;	/* atomic copy */
26656c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
26666c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26676c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
26686c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
26696c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
26706c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
26716c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26726c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	*cprev = cnow;
26736c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26746c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	return ret;
26756c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby}
26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine allows the tty driver to implement device-
26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific ioctl's.  If the ioctl number passed in cmd is
26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not recognized by the driver, it should return ENOIOCTLCMD.
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
26836caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxcy_ioctl(struct tty_struct *tty,
268402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 unsigned int cmd, unsigned long arg)
26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2686cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
26876c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct cyclades_icount cnow;	/* kernel counter temps */
268802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int ret_val = 0;
268902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
269002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __user *argp = (void __user *)arg;
269102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
269202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
269302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2696217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2697217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		info->line, cmd, arg);
26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
270002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	switch (cmd) {
270102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETMON:
27026c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
27036c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			ret_val = -EFAULT;
27046c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			break;
27056c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		}
27066c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		memset(&info->mon, 0, sizeof(info->mon));
270702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETTHRESH:
270902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_threshold(info, argp);
271002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETTHRESH:
271202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = set_threshold(info, arg);
271302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETDEFTHRESH:
27156c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = put_user(info->default_threshold,
27166c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				(unsigned long __user *)argp);
271702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETDEFTHRESH:
27196c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		info->default_threshold = arg & 0x0f;
272002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
272102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETTIMEOUT:
272202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_timeout(info, argp);
272302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
272402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETTIMEOUT:
272502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = set_timeout(info, arg);
272602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
272702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETDEFTIMEOUT:
27286c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = put_user(info->default_timeout,
27296c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				(unsigned long __user *)argp);
273002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
273102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETDEFTIMEOUT:
27326c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		info->default_timeout = arg & 0xff;
273302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETRFLOW:
273502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->rflow = (int)arg;
273602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETRFLOW:
273802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->rflow;
273902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETRTSDTR_INV:
274102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->rtsdtr_inv = (int)arg;
274202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETRTSDTR_INV:
274402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->rtsdtr_inv;
274502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETCD1400VER:
274702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->chip_rev;
274802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYZSETPOLLCYCLE:
275102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cyz_polling_cycle = (arg * HZ) / 1000;
275202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYZGETPOLLCYCLE:
275402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = (cyz_polling_cycle * 1000) / HZ;
275502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETWAIT:
275844b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.closing_wait = (unsigned short)arg * HZ / 100;
275902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETWAIT:
276144b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		ret_val = info->port.closing_wait / (HZ / 100);
276202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
276302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCGSERIAL:
27646c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = cy_get_serial_info(info, argp);
276502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
276602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCSSERIAL:
2767d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		ret_val = cy_set_serial_info(info, tty, argp);
276802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
276902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCSERGETLSR:	/* Get line status register */
277002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_lsr_info(info, argp);
277102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
277202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
277302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
277402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * - mask passed in arg for lines of interest
277502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
277602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Caller should use TIOCGICOUNT to see which one it was
277702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCMIWAIT:
27799fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&info->card->card_lock, flags);
278002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* note the counters on entry */
27812c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		cnow = info->icount;
27829fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&info->card->card_lock, flags);
2783bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
27846c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				cy_cflags_changed(info, arg, &cnow));
27852c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		break;
27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
278702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
278802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
278902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Return: write counters to the user passed counter struct
279002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * NB: both 1->0 and 0->1 transitions are counted except for
279102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 *     RI where only 0->1 is counted.
279202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
279302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	default:
279402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = -ENOIOCTLCMD;
279502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2798217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
280002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret_val;
280102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_ioctl */
28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28030587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int cy_get_icount(struct tty_struct *tty,
28040587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox				struct serial_icounter_struct *sic)
28050587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox{
28060587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	struct cyclades_port *info = tty->driver_data;
28070587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	struct cyclades_icount cnow;	/* Used to snapshot */
28080587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	unsigned long flags;
28090587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
28100587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	spin_lock_irqsave(&info->card->card_lock, flags);
28110587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	cnow = info->icount;
28120587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	spin_unlock_irqrestore(&info->card->card_lock, flags);
28130587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
28140587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->cts = cnow.cts;
28150587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->dsr = cnow.dsr;
28160587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->rng = cnow.rng;
28170587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->dcd = cnow.dcd;
28180587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->rx = cnow.rx;
28190587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->tx = cnow.tx;
28200587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->frame = cnow.frame;
28210587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->overrun = cnow.overrun;
28220587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->parity = cnow.parity;
28230587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->brk = cnow.brk;
28240587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->buf_overrun = cnow.buf_overrun;
28250587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	return 0;
28260587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox}
28270587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine allows the tty driver to be notified when
28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's termios settings have changed.  Note that a
28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well-designed tty driver should be prepared to accept the case
28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where old == NULL, and try to do something rational.
28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
283402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2836cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2839217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2842d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_set_line_char(info, tty);
284302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
284402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if ((old_termios->c_cflag & CRTSCTS) &&
284502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			!(tty->termios->c_cflag & CRTSCTS)) {
284602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		tty->hw_stopped = 0;
284702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_start(tty);
284802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
285002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
285102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * No need to wake up processes in open wait, since they
285202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * sample the CLOCAL flag once, and don't recheck it.
285302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * XXX  It's not clear whether the current behavior is correct
285402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * or not.  Hence, this may change.....
285502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
285602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!(old_termios->c_cflag & CLOCAL) &&
285702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	    (tty->termios->c_cflag & CLOCAL))
285877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		wake_up_interruptible(&info->port.open_wait);
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
286002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_set_termios */
28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This function is used to send a high-priority XON/XOFF character to
28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the device.
28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
286502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_send_xchar(struct tty_struct *tty, char ch)
28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2867cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2868875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
2869875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	int channel;
28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
287102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
287402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->x_char = ch;
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch)
287702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_start(tty);
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card = info->card;
2880875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28822693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(card)) {
288302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (ch == STOP_CHAR(tty))
2884875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
288502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else if (ch == START_CHAR(tty))
2886875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine is called by the upper-layer tty layer to signal
28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   that incoming characters should be throttled because the input
28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   buffers are close to full.
28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
289402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_throttle(struct tty_struct *tty)
28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2896cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2897875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
289802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_THROTTLE
290102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char buf[64];
29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2903217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
290402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty->ldisc.chars_in_buffer(tty), info->line);
29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
290715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
290802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
290902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
291002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
291102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
291202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (I_IXOFF(tty)) {
29132693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card))
291402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_send_xchar(tty, STOP_CHAR(tty));
291502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
291602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 1;
291702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tty->termios->c_cflag & CRTSCTS) {
29202693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card)) {
29219fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
29224d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
29239fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
292402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
292502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 1;
292602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
292702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
292802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_throttle */
29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine notifies the tty driver that it should signal
29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that characters can now be sent to the tty without fear of
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * overrunning the input buffers of the line disciplines.
29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
293502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_unthrottle(struct tty_struct *tty)
29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2937cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2938875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
293902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_THROTTLE
294202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char buf[64];
294302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2944217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
294515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
294815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
294902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
295102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (I_IXOFF(tty)) {
295202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->x_char)
295302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->x_char = 0;
295402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
295502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_send_xchar(tty, START_CHAR(tty));
29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
295802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tty->termios->c_cflag & CRTSCTS) {
295902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		card = info->card;
29602693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card)) {
29619fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
29624d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
29639fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
296402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
296502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 0;
296602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
296702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
296802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_unthrottle */
29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* cy_start and cy_stop provide software output flow control as a
29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   function of XON/XOFF, software CTS, and other such stuff.
29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
297302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_stop(struct tty_struct *tty)
29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
297502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
2976cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
29773aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
297802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2981217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
298402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_stop"))
298502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2987875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	cinfo = info->card;
298802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	channel = info->line - cinfo->first_line;
29892693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo)) {
29909fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&cinfo->card_lock, flags);
29913aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
29923aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
29939fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&cinfo->card_lock, flags);
299402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
299502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_stop */
29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
299702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_start(struct tty_struct *tty)
29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
299902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
3000cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
30013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
300202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
3005217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
300802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_start"))
300902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	cinfo = info->card;
301202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	channel = info->line - cinfo->first_line;
30132693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo)) {
30149fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&cinfo->card_lock, flags);
30153aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
30163aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
30179fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&cinfo->card_lock, flags);
301802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
301902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_start */
30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
302402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_hangup(struct tty_struct *tty)
30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3026cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
302702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
3029217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
303202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
303302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
303502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_flush_buffer(tty);
3036d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_shutdown(info, tty);
3037174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby	tty_port_hangup(&info->port);
303802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_hangup */
30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3040f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic int cyy_carrier_raised(struct tty_port *port)
3041f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3042f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3043f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3044f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3045f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	unsigned long flags;
3046f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	int channel = info->line - cinfo->first_line;
3047f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	u32 cd;
3048f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3049f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_lock_irqsave(&cinfo->card_lock, flags);
30503aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, channel & 0x03);
30513aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cd = cyy_readb(info, CyMSVR1) & CyDCD;
3052f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_unlock_irqrestore(&cinfo->card_lock, flags);
3053f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3054f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	return cd;
3055f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3056f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3057f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic void cyy_dtr_rts(struct tty_port *port, int raise)
3058f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3059f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3060f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3061f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3062f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	unsigned long flags;
3063f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3064f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_lock_irqsave(&cinfo->card_lock, flags);
30654d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
30664d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
3067f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_unlock_irqrestore(&cinfo->card_lock, flags);
3068f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3069f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3070f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic int cyz_carrier_raised(struct tty_port *port)
3071f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3072f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3073f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3074f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3075f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
3076f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3077f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3078f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic void cyz_dtr_rts(struct tty_port *port, int raise)
3079f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3080f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3081f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3082f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3083f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
3084f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	int ret, channel = info->line - cinfo->first_line;
3085f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	u32 rs;
3086f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3087f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	rs = readl(&ch_ctrl->rs_control);
3088f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	if (raise)
3089f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		rs |= C_RS_RTS | C_RS_DTR;
3090f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	else
3091f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		rs &= ~(C_RS_RTS | C_RS_DTR);
3092f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	cy_writel(&ch_ctrl->rs_control, rs);
3093f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3094f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	if (ret != 0)
3095f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3096f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby				__func__, info->line, ret);
3097f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby#ifdef CY_DEBUG_DTR
3098f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3099f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby#endif
3100f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3101f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3102f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic const struct tty_port_operations cyy_port_ops = {
3103f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.carrier_raised = cyy_carrier_raised,
3104f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.dtr_rts = cyy_dtr_rts,
3105e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	.shutdown = cy_do_close,
3106f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby};
3107f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3108f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic const struct tty_port_operations cyz_port_ops = {
3109f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.carrier_raised = cyz_carrier_raised,
3110f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.dtr_rts = cyz_dtr_rts,
3111e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	.shutdown = cy_do_close,
3112f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby};
3113f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_init() and friends
31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_init() is called at boot-time to initialize the serial driver.
31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3122dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slabystatic int __devinit cy_init_card(struct cyclades_card *cinfo)
31230809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby{
31240809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby	struct cyclades_port *info;
3125f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	unsigned int channel, port;
31260809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby
31273046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby	spin_lock_init(&cinfo->card_lock);
3128963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cinfo->intr_enabled = 0;
31293046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
3130963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3131963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby			GFP_KERNEL);
3132dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	if (cinfo->ports == NULL) {
3133dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3134dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		return -ENOMEM;
3135dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	}
3136dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby
3137f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3138f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			channel++, port++) {
3139f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		info = &cinfo->ports[channel];
314044b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		tty_port_init(&info->port);
31413046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		info->magic = CYCLADES_MAGIC;
3142875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		info->card = cinfo;
31433046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		info->line = port;
31443046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
314544b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.closing_wait = CLOSING_WAIT_DELAY;
314644b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.close_delay = 5 * HZ / 10;
314777451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags = STD_COM_FLAGS;
31482c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		init_completion(&info->shutdown_wait);
31493046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31502693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (cy_is_Z(cinfo)) {
3151f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3152f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			struct ZFW_CTRL *zfw_ctrl;
3153f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3154f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			info->port.ops = &cyz_port_ops;
31550809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->type = PORT_STARTECH;
3156f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3157f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			zfw_ctrl = cinfo->base_addr +
3158f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
3159f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3160f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3161f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3162101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby			if (cinfo->hw_ver == ZO_V1)
31630809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->xmit_fifo_size = CYZ_FIFO_SIZE;
31640809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			else
31653046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
31660809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby#ifdef CONFIG_CYZ_INTR
31673991428d9efc7185312196f82cc36e9df4a2ddb0Jiri Slaby			setup_timer(&cyz_rx_full_timer[port],
31683991428d9efc7185312196f82cc36e9df4a2ddb0Jiri Slaby				cyz_rx_restart, (unsigned long)info);
31690809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby#endif
31703046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		} else {
3171f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			unsigned short chip_number;
3172963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby			int index = cinfo->bus_index;
3173f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3174f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			info->port.ops = &cyy_port_ops;
31750809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->type = PORT_CIRRUS;
31760809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
31773046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
31780809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->cor2 = CyETC;
31790809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->cor3 = 0x08;	/* _very_ small rcv threshold */
31803046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
3181f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			chip_number = channel / CyPORTS_PER_CHIP;
31823aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			info->u.cyy.base_addr = cinfo->base_addr +
31833aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				(cy_chip_offset[chip_number] << index);
31843aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			info->chip_rev = cyy_readb(info, CyGFRCR);
318515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
318615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (info->chip_rev >= CD1400_REV_J) {
31870809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				/* It is a CD1400 rev. J or later */
31880809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tbpr = baud_bpr_60[13];	/* Tx BPR */
31890809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tco = baud_co_60[13];	/* Tx CO */
31900809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rbpr = baud_bpr_60[13];	/* Rx BPR */
31910809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rco = baud_co_60[13];	/* Rx CO */
31920809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rtsdtr_inv = 1;
31930809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			} else {
31940809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tbpr = baud_bpr_25[13];	/* Tx BPR */
31950809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tco = baud_co_25[13];	/* Tx CO */
31960809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rbpr = baud_bpr_25[13];	/* Rx BPR */
31970809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rco = baud_co_25[13];	/* Rx CO */
31980809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rtsdtr_inv = 0;
31990809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			}
32003046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby			info->read_status_mask = CyTIMEOUT | CySPECHAR |
32013046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
32020809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby		}
32033046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
32040809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby	}
32053046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
32063046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#ifndef CONFIG_CYZ_INTR
32072693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
32083046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		mod_timer(&cyz_timerlist, jiffies + 1);
32093046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#ifdef CY_PCI_DEBUG
32103046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
32113046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#endif
32123046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby	}
32133046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#endif
3214dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	return 0;
32150809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby}
32160809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby
32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize chips on Cyclom-Y card -- return number of valid
32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   chips (which is number of ports/4) */
321931b4f0a118a7ade8444059ec898af8f07de206e9Jiri Slabystatic unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
322031b4f0a118a7ade8444059ec898af8f07de206e9Jiri Slaby		int index)
32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
322202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned int chip_number;
322302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *base_addr;
322402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
322502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
322602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_HwReset is 0x1400 */
322702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
322802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
322902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(500L);
323002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
323115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
323215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox							chip_number++) {
323302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		base_addr =
323402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		    true_base_addr + (cy_chip_offset[chip_number] << index);
323502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		mdelay(1);
3236db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyCCR << index)) != 0x00) {
323702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*************
323802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
323902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			chip_number, (unsigned long)base_addr);
324002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			*************/
324102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
324202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
324302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
324402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyGFRCR << index), 0);
324502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(10L);
324602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
324702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* The Cyclom-16Y does not decode address bit 9 and therefore
324802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   cannot distinguish between references to chip 0 and a non-
324902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   existent chip 4.  If the preceding clearing of the supposed
325002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   chip 4 GFRCR register appears at chip 0, there is no chip 4
325102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   and this must be a Cyclom-16Y, not a Cyclom-32Ye.
325202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
3253db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (chip_number == 4 && readb(true_base_addr +
325402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(cy_chip_offset[0] << index) +
325502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(CyGFRCR << index)) == 0) {
325602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
325702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
325802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
325902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
326002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		mdelay(1);
326102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3262db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
326302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*
326402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   printk(" chip #%d at %#6lx is not responding ",
326502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   chip_number, (unsigned long)base_addr);
326602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   printk("(GFRCR stayed 0)\n",
326702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
326802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
326902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
3270db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
327102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				0x40) {
327202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*
327302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			printk(" chip #%d at %#6lx is not valid (GFRCR == "
327402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					"%#2x)\n",
327502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					chip_number, (unsigned long)base_addr,
327602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					base_addr[CyGFRCR<<index]);
327702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
327802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
327902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
328002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
3281db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
328202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* It is a CD1400 rev. J or later */
328302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Impossible to reach 5ms with this chip.
328402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   Changed to 2ms instead (f = 500 Hz). */
328502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
328602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
328702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* f = 200 Hz */
328802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
328902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
329102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
329202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
329302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   chip_number, (unsigned long)base_addr,
3294db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		   readb(base_addr+(CyGFRCR<<index)));
329502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
329602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
329702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return chip_number;
329802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyy_init_card */
32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sets global variables and return the number of ISA boards found.
33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
330602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int __init cy_detect_isa(void)
33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
330902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned short cy_isa_irq, nboard;
331002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *cy_isa_address;
331102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned short i, j, cy_isa_nchan;
331202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int isparam = 0;
33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	nboard = 0;
33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for module parameters */
331702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_CARDS; i++) {
331802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (maddr[i] || i) {
331902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			isparam = 1;
332002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_addresses[i] = maddr[i];
332102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
332202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (!maddr[i])
332302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
332602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* scan the address table probing for Cyclom-Y/ISA boards */
332702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_ISA_ADDRS; i++) {
332802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		unsigned int isa_address = cy_isa_addresses[i];
332915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (isa_address == 0x0000)
3330096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
333202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* probe for CD1400... */
3333cd989b3a8c30148c872c7677c7a0415584f1658cAlan Cox		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
33343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_isa_address == NULL) {
33353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
33363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"address\n");
33373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			continue;
33383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
333902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_isa_nchan = CyPORTS_PER_CHIP *
334002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cyy_init_card(cy_isa_address, 0);
334102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_isa_nchan == 0) {
33423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
334302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
334402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
33452090436357c20afad377a61c789f502c36d637deBartlomiej Zolnierkiewicz
3346196b3167efd13a02cdd34acc1a12316b9f45f41dRoel Kluin		if (isparam && i < NR_CARDS && irq[i])
334702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_irq = irq[i];
33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
334902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* find out the board's irq by probing */
335002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_irq = detect_isa_irq(cy_isa_address);
335102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_isa_irq == 0) {
3352217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3353217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"IRQ could not be detected.\n",
335402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33553137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
335602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
335702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
335802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
335902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
3360217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3361217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"more channels are available. Change NR_PORTS "
3362217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"in cyclades.c and recompile kernel.\n",
336302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33643137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3365096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
336602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
336702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* fill the next cy_card structure available */
336802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (j = 0; j < NR_CARDS; j++) {
3369f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby			if (cy_card[j].base_addr == NULL)
337002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
337102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
337202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (j == NR_CARDS) {	/* no more cy_cards available */
3373217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3374217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"more cards can be used. Change NR_CARDS in "
3375217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"cyclades.c and recompile kernel.\n",
337602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33773137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3378096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
337902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
338002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
338102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* allocate IRQ */
338202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (request_irq(cy_isa_irq, cyy_interrupt,
338302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
3384217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3385217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"could not allocate IRQ#%d.\n",
3386217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				(unsigned long)cy_isa_address, cy_isa_irq);
33873137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3388096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
338902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
339002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
339102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set cy_card */
339202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].base_addr = cy_isa_address;
339397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_card[j].ctl_addr.p9050 = NULL;
339402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].irq = (int)cy_isa_irq;
339502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].bus_index = 0;
339602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].first_line = cy_next_channel;
3397963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3398963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[j].nports = cy_isa_nchan;
33993137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_init_card(&cy_card[j])) {
34003137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			cy_card[j].base_addr = NULL;
34013137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			free_irq(cy_isa_irq, &cy_card[j]);
34023137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
34033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			continue;
34043137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
340502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		nboard++;
340602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3407217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3408217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			"%d channels starting from port %d\n",
340902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			j + 1, (unsigned long)cy_isa_address,
341002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
3411217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			cy_isa_irq, cy_isa_nchan, cy_next_channel);
3412217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
34136ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby		for (j = cy_next_channel;
34146ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby				j < cy_next_channel + cy_isa_nchan; j++)
34156ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby			tty_register_device(cy_serial_driver, j, NULL);
341602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_next_channel += cy_isa_nchan;
341702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
3418096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return nboard;
34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3420096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
342102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
342202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_detect_isa */
34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
342458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby#ifdef CONFIG_PCI
3425054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3426054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3427054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int a;
3428054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3429054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (a = 0; a < size && *str; a++, str++)
3430054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (*str & 0x80)
3431054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3432054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3433054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (; a < size; a++, str++)
3434054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (*str)
3435054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3436054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3437054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return 0;
3438054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3439054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3440f61e761e2128c7ca0d044651b18928991ab03be2David Woodhousestatic inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3441054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		unsigned int size)
3442054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3443054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (; size > 0; size--) {
3444054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(fpga, *data++);
3445054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(10);
3446054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3447054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3448054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3449054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic void __devinit plx_init(struct pci_dev *pdev, int irq,
3450054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		struct RUNTIME_9060 __iomem *addr)
34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
345202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Reset PLX */
3453054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
345402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(100L);
3455054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
345602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
345702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Reload Config. Registers from EEPROM */
3458054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
345902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(100L);
3460054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3461054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3462054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3463054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3464054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 * registers. This will remain here until we find a permanent fix.
3465054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 */
3466054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3467054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3468054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3469054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic int __devinit __cyz_load_fw(const struct firmware *fw,
3470054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		const char *name, const u32 mailbox, void __iomem *base,
3471054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		void __iomem *fpga)
3472054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3473f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const void *ptr = fw->data;
3474f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_header *h = ptr;
3475f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_config *c, *cs;
3476f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_block *b, *bs;
3477054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int a, tmp, len = fw->size;
3478054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define BAD_FW KERN_ERR "Bad firmware: "
3479054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (len < sizeof(*h)) {
3480054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3481054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3482054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3483054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3484054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cs = ptr + h->config_offset;
3485054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	bs = ptr + h->block_offset;
3486054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3487054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if ((void *)(cs + h->n_config) > ptr + len ||
3488054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			(void *)(bs + h->n_blocks) > ptr + len) {
3489054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "too short");
3490054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return  -EINVAL;
3491054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3492054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3493054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3494054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			cyc_isfwstr(h->date, sizeof(h->date))) {
3495054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "bad formatted header string\n");
3496054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3497054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3498054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3499054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (strncmp(name, h->name, sizeof(h->name))) {
3500054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3501054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3502054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3503054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3504054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	tmp = 0;
3505054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (c = cs; c < cs + h->n_config; c++) {
3506054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		for (a = 0; a < c->n_blocks; a++)
3507054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (c->block_list[a] > h->n_blocks) {
3508054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				printk(BAD_FW "bad block ref number in cfgs\n");
3509054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				return -EINVAL;
3510054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			}
3511054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3512054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			tmp++;
3513054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3514054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (!tmp) {
3515054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "nothing appropriate\n");
3516054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3517054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3518054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3519054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (b = bs; b < bs + h->n_blocks; b++)
3520054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (b->file_offset + b->size > len) {
3521054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			printk(BAD_FW "bad block data offset\n");
3522054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3523054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3524054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3525054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* everything is OK, let's seek'n'load it */
3526054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (c = cs; c < cs + h->n_config; c++)
3527054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (c->mailbox == mailbox && c->function == 0)
3528054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			break;
3529054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3530054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (a = 0; a < c->n_blocks; a++) {
3531054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		b = &bs[c->block_list[a]];
3532054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (b->type == ZBLOCK_FPGA) {
3533054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (fpga != NULL)
3534054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				cyz_fpga_copy(fpga, ptr + b->file_offset,
3535054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby						b->size);
3536054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		} else {
3537054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (base != NULL)
3538054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				memcpy_toio(base + b->ram_offset,
3539054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					       ptr + b->file_offset, b->size);
3540054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3541054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3542054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#undef BAD_FW
3543054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return 0;
3544054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3545054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3546054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3547054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3548054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3549054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	const struct firmware *fw;
3550054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3551054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct CUSTOM_REG __iomem *cust = base_addr;
3552054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct ZFW_CTRL __iomem *pt_zfwctrl;
3553c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby	void __iomem *tmp;
3554963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	u32 mailbox, status, nchan;
3555054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int i;
3556054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	int retval;
3557054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3558054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3559054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (retval) {
3560054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_err(&pdev->dev, "can't get firmware\n");
3561054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3562054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3563054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3564054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* Check whether the firmware is already loaded and running. If
3565054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   positive, skip this board */
35662693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3567054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		u32 cntval = readl(base_addr + 0x190);
3568054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3569054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(100);
3570054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (cntval != readl(base_addr + 0x190)) {
3571054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			/* FW counter is working, FW is running */
3572054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3573054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"Skipping board.\n");
3574054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = 0;
3575054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
3576054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3577054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3578054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3579054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* start boot */
3580054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3581054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			~0x00030800UL);
3582054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3583054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	mailbox = readl(&ctl_addr->mail_box_0);
3584054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
35852693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3586054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* stops CPU and set window to beginning of RAM */
3587054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3588054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&cust->cpu_stop, 0);
3589054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3590054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(100);
3591054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3592054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3593054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	plx_init(pdev, irq, ctl_addr);
3594054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3595054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (mailbox != 0) {
3596054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* load FPGA */
3597054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3598054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				base_addr);
3599054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (retval)
3600054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
36012693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!__cyz_fpga_loaded(ctl_addr)) {
3602054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "fw upload successful, but fw is "
3603054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"not loaded\n");
3604054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
3605054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3606054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3607054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3608054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* stops CPU and set window to beginning of RAM */
3609054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3610054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&cust->cpu_stop, 0);
3611054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3612054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	udelay(100);
3613054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3614054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* clear memory */
3615c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3616054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writeb(tmp, 255);
3617054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (mailbox != 0) {
3618054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* set window to last 512K of RAM */
3619054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
3620c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3621054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			cy_writeb(tmp, 255);
3622054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* set window to beginning of RAM */
3623054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3624054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3625054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3626054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3627054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	release_firmware(fw);
3628054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (retval)
3629054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3630054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3631054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* finish boot and start boards */
3632054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3633054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&cust->cpu_start, 0);
3634054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3635054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	i = 0;
3636054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3637054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		msleep(100);
3638054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (status != ZFIRM_ID) {
3639054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (status == ZFIRM_HLT) {
3640054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "you need an external power supply "
3641054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"for this number of ports. Firmware halted and "
3642054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"board reset.\n");
3643054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = -EIO;
3644054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err;
3645054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3646054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3647054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"some more time\n", status);
3648054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3649054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				i++ < 200)
3650054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			msleep(100);
3651054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (status != ZFIRM_ID) {
3652054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "Board not started in 20 seconds! "
3653054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"Giving up. (fid->signature = 0x%x)\n",
3654054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					status);
3655054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_info(&pdev->dev, "*** Warning ***: if you are "
3656054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"upgrading the FW, please power cycle the "
3657054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"system before loading the new FW to the "
3658054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"Cyclades-Z.\n");
3659054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
36602693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			if (__cyz_fpga_loaded(ctl_addr))
3661054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				plx_init(pdev, irq, ctl_addr);
3662054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3663054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = -EIO;
3664054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err;
3665054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3666054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3667054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				i / 10);
3668054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3669054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3670054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3671054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3672054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3673054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			base_addr + readl(&fid->zfwctrl_addr));
3674054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3675963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3676054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
3677963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3678054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3679963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	if (nchan == 0) {
3680054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3681054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			"check the connection between the Z host card and the "
3682054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			"serial expanders.\n");
3683054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
36842693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (__cyz_fpga_loaded(ctl_addr))
3685054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			plx_init(pdev, irq, ctl_addr);
3686054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3687054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_info(&pdev->dev, "Null number of ports detected. Board "
3688054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"reset.\n");
3689054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		retval = 0;
3690054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3691054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3692054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3693054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3694054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3695054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3696054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/*
3697054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   Early firmware failed to start looking for commands.
3698054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   This enables firmware interrupts for those commands.
3699054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 */
3700054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3701054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			(1 << 17));
3702054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3703054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			0x00030800UL);
3704054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3705963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	return nchan;
3706054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyerr_rel:
3707054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	release_firmware(fw);
3708054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyerr:
3709054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return retval;
37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slabystatic int __devinit cy_pci_probe(struct pci_dev *pdev,
371358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		const struct pci_device_id *ent)
37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
37153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	void __iomem *addr0 = NULL, *addr2 = NULL;
37163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	char *card_name = NULL;
3717101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby	u32 uninitialized_var(mailbox);
37183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	unsigned int device_id, nchan = 0, card_no, i;
37193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	unsigned char plx_ver;
37203137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	int retval, irq;
372102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
372258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	retval = pci_enable_device(pdev);
372358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	if (retval) {
372458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		dev_err(&pdev->dev, "cannot enable device\n");
37253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err;
372658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	}
37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
372858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	/* read PCI configuration area */
37293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	irq = pdev->irq;
373058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby#if defined(__alpha__)
37333137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
37343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
37353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"addresses on Alpha systems.\n");
37363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = -EIO;
37373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby#endif
37403137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
37413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
37423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"addresses\n");
37433137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = -EIO;
37443137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37463137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37473137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
37483137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
37493137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				"it...\n");
37503137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		pdev->resource[2].flags &= ~IORESOURCE_IO;
37513137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37523137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37533137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = pci_request_regions(pdev, "cyclades");
37543137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (retval) {
37553137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "failed to reserve resources\n");
37563137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37573137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37583137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37593137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = -EIO;
376058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
376158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
37623137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		card_name = "Cyclom-Y";
37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
376424e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
376524e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Yctl);
37663137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr0 == NULL) {
37673137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap ctl region\n");
37683137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_reg;
376958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
377024e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
377124e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Ywin);
37723137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr2 == NULL) {
37733137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap base region\n");
37743137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
377558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37773137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
37783137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (nchan == 0) {
3779217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3780217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"Serial-Modules\n");
3781c847d47cb7b2fa78b17c9e17ed3fbd010ee3d3caAndrew Morton			goto err_unmap;
378258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
378358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
37843137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		struct RUNTIME_9060 __iomem *ctl_addr;
3785217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
378624e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
378724e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Zctl);
37883137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr0 == NULL) {
37893137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap ctl region\n");
37903137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_reg;
37913137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
379258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
379358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		/* Disable interrupts on the PLX before resetting it */
379497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writew(&ctl_addr->intr_ctrl_stat,
379597e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
379658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
3797054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		plx_init(pdev, irq, addr0);
379802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3799101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		mailbox = readl(&ctl_addr->mail_box_0);
380058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
380124e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
380224e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
38033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr2 == NULL) {
38043137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap base region\n");
38053137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
380658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
380758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
380858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		if (mailbox == ZE_V1) {
38093137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			card_name = "Cyclades-Ze";
381058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		} else {
38113137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			card_name = "Cyclades-8Zo";
38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_PCI_DEBUG
38133137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			if (mailbox == ZO_V1) {
38143137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
38153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
38163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"id %lx, ver %lx\n", (ulong)(0xff &
38173137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					readl(&((struct CUSTOM_REG *)addr2)->
38183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby						fpga_id)), (ulong)(0xff &
38193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					readl(&((struct CUSTOM_REG *)addr2)->
38203137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby						fpga_version)));
38213137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
38223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			} else {
38233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
38243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"Cyclades-Z board.  FPGA not loaded\n");
38253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			}
38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
38273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			/* The following clears the firmware id word.  This
38283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			   ensures that the driver will not attempt to talk to
38293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			   the board until it has been properly initialized.
38303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			 */
38313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
38323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(addr2 + ID_ADDRESS, 0L);
383358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
3834ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby
3835ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby		retval = cyz_load_fw(pdev, addr2, addr0, irq);
3836963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		if (retval <= 0)
3837ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby			goto err_unmap;
3838963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		nchan = retval;
38393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38403137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if ((cy_next_channel + nchan) > NR_PORTS) {
38423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
38433137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"channels are available. Change NR_PORTS in "
38443137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"cyclades.c and recompile kernel.\n");
38453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_unmap;
38463137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38473137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	/* fill the next cy_card structure available */
38483137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	for (card_no = 0; card_no < NR_CARDS; card_no++) {
38493137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_card[card_no].base_addr == NULL)
38503137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
38513137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38523137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (card_no == NR_CARDS) {	/* no more cy_cards available */
38533137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
38543137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"more cards can be used. Change NR_CARDS in "
38553137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"cyclades.c and recompile kernel.\n");
38563137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_unmap;
38573137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38583137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38593137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
38603137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
38613137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		/* allocate IRQ */
38623137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = request_irq(irq, cyy_interrupt,
38633137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
38643137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (retval) {
38653137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "could not allocate IRQ\n");
38663137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
386758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
3868963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
38693137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	} else {
3870f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3871f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct ZFW_CTRL __iomem *zfw_ctrl;
3872f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3873f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3874f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3875101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		cy_card[card_no].hw_ver = mailbox;
3876101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		cy_card[card_no].num_chips = (unsigned int)-1;
3877f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
387802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CONFIG_CYZ_INTR
387958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		/* allocate IRQ only if board has an IRQ */
38803137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (irq != 0 && irq != 255) {
38813137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			retval = request_irq(irq, cyz_interrupt,
388258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby					IRQF_SHARED, "Cyclades-Z",
38833137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					&cy_card[card_no]);
388458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby			if (retval) {
3885217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				dev_err(&pdev->dev, "could not allocate IRQ\n");
38863137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				goto err_unmap;
388702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
388858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
388902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
38903137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
389102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
38923137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	/* set cy_card */
38933137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].base_addr = addr2;
389497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	cy_card[card_no].ctl_addr.p9050 = addr0;
38953137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].irq = irq;
38963137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].bus_index = 1;
38973137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].first_line = cy_next_channel;
3898963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cy_card[card_no].nports = nchan;
38993137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = cy_init_card(&cy_card[card_no]);
39003137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (retval)
39013137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_null;
390258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_set_drvdata(pdev, &cy_card[card_no]);
390458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39053137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
39063137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
39073137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		/* enable interrupts in the PCI interface */
39083137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
39093137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		switch (plx_ver) {
39103137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9050:
39113137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			cy_writeb(addr0 + 0x4c, 0x43);
39123137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
39133137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
39143137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9060:
39153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9080:
39163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		default:	/* Old boards, use PLX_9060 */
391797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		{
391897e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			struct RUNTIME_9060 __iomem *ctl_addr = addr0;
391997e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			plx_init(pdev, irq, ctl_addr);
392097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			cy_writew(&ctl_addr->intr_ctrl_stat,
392197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
39223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
39233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
392497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		}
392558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	}
392658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
39283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
39293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
39303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		tty_register_device(cy_serial_driver, i, &pdev->dev);
39313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_next_channel += nchan;
39323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
393358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	return 0;
39343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_null:
39353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].base_addr = NULL;
39363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	free_irq(irq, &cy_card[card_no]);
39373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_unmap:
393824e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby	iounmap(addr0);
39393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (addr2)
394024e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		iounmap(addr2);
39413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_reg:
39423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_release_regions(pdev);
39433137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_dis:
39443137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_disable_device(pdev);
39453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr:
39463137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	return retval;
394758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby}
394858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39496747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slabystatic void __devexit cy_pci_remove(struct pci_dev *pdev)
395058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby{
395138d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3952f3851e73ecdd070bc379677ed7aad958446f26e7Jiri Slaby	unsigned int i;
395338d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
395485c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby	/* non-Z with old PLX */
39552693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
3956c2ad4c75154d98c07d30493e4906e1cd0a9162a5Jiri Slaby			PLX_9050)
395797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
395885c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby	else
395985c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby#ifndef CONFIG_CYZ_INTR
39602693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(cinfo))
396185c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby#endif
396297e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
396397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
396497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			~0x0900);
396585c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby
396624e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby	iounmap(cinfo->base_addr);
396797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	if (cinfo->ctl_addr.p9050)
396897e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		iounmap(cinfo->ctl_addr.p9050);
396938d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	if (cinfo->irq
397038d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby#ifndef CONFIG_CYZ_INTR
39712693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		&& !cy_is_Z(cinfo)
397238d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby#endif /* CONFIG_CYZ_INTR */
397338d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby		)
397438d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby		free_irq(cinfo->irq, cinfo);
397538d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	pci_release_regions(pdev);
397638d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
397738d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	cinfo->base_addr = NULL;
39786ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby	for (i = cinfo->first_line; i < cinfo->first_line +
39796ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby			cinfo->nports; i++)
39806ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby		tty_unregister_device(cy_serial_driver, i);
3981dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	cinfo->nports = 0;
3982dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	kfree(cinfo->ports);
398338d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby}
398438d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
39856747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slabystatic struct pci_driver cy_pci_driver = {
39866747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.name = "cyclades",
39876747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.id_table = cy_pci_dev_id,
39886747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.probe = cy_pci_probe,
39896747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.remove = __devexit_p(cy_pci_remove)
39906747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby};
39916747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
39926747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby
3993444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic int cyclades_proc_show(struct seq_file *m, void *v)
39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
399502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
3996dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	unsigned int i, j;
399702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	__u32 cur_jifs = jiffies;
399802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3999444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
400002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			"IdleIn  Overruns  Ldisc\n");
400102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
400202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Output one line for each known port */
4003dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	for (i = 0; i < NR_CARDS; i++)
4004dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		for (j = 0; j < cy_card[i].nports; j++) {
4005dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			info = &cy_card[i].ports[j];
4006dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby
4007d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			if (info->port.count) {
4008d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				/* XXX is the ldisc num worth this? */
4009d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				struct tty_struct *tty;
4010d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				struct tty_ldisc *ld;
4011d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				int num = 0;
4012d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty = tty_port_tty_get(&info->port);
4013d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				if (tty) {
4014d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					ld = tty_ldisc_ref(tty);
4015d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					if (ld) {
4016d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby						num = ld->ops->num;
4017d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby						tty_ldisc_deref(ld);
4018d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					}
4019d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					tty_kref_put(tty);
4020d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				}
4021444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan				seq_printf(m, "%3d %8lu %10lu %8lu "
4022d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					"%10lu %8lu %9lu %6d\n", info->line,
4023dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.in_use) /
4024dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.xmit_bytes,
4025dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.xmit_idle)/
4026dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.recv_bytes,
4027dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.recv_idle)/
4028dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.overruns,
4029d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					num);
4030d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			} else
4031444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan				seq_printf(m, "%3d %8lu %10lu %8lu "
4032dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					"%10lu %8lu %9lu %6ld\n",
4033dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
403402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
4035444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	return 0;
4036444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan}
4037444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan
4038444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic int cyclades_proc_open(struct inode *inode, struct file *file)
4039444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan{
4040444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	return single_open(file, cyclades_proc_show, NULL);
40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4043444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic const struct file_operations cyclades_proc_fops = {
4044444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.owner		= THIS_MODULE,
4045444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.open		= cyclades_proc_open,
4046444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.read		= seq_read,
4047444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.llseek		= seq_lseek,
4048444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.release	= single_release,
4049444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan};
4050444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The serial driver boot-time initialization code!
40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Hardware I/O ports are mapped to character special devices on a
40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    first found, first allocated manner.  That is, this code searches
40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for Cyclom cards in the system.  As each is found, it is probed
40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    to discover how many chips (and thus how many ports) are present.
40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    These ports are mapped to the tty ports 32 and upward in monotonic
40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    fashion.  If an 8-port card is replaced with a 16-port card, the
40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    port mapping on a following card will shift.
40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This approach is different from what is used in the other serial
40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    device driver because the Cyclom is more properly a multiplexer,
40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    not just an aggregation of serial ports on one card.
40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    If there are more cards with more ports than have been
40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    statically allocated above, a warning is printed and the
40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    extra ports are ignored.
40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4069b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations cy_ops = {
407002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.open = cy_open,
407102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.close = cy_close,
407202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.write = cy_write,
407302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.put_char = cy_put_char,
407402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.flush_chars = cy_flush_chars,
407502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.write_room = cy_write_room,
407602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.chars_in_buffer = cy_chars_in_buffer,
407702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.flush_buffer = cy_flush_buffer,
407802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.ioctl = cy_ioctl,
407902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.throttle = cy_throttle,
408002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.unthrottle = cy_unthrottle,
408102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.set_termios = cy_set_termios,
408202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.stop = cy_stop,
408302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.start = cy_start,
408402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.hangup = cy_hangup,
408502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.break_ctl = cy_break,
408602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.wait_until_sent = cy_wait_until_sent,
408702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.tiocmget = cy_tiocmget,
408802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.tiocmset = cy_tiocmset,
40890587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	.get_icount = cy_get_icount,
4090444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.proc_fops = &cyclades_proc_fops,
40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
409302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int __init cy_init(void)
40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4095dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	unsigned int nboards;
40969dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	int retval = -ENOMEM;
409702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
409802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver = alloc_tty_driver(NR_PORTS);
409902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!cy_serial_driver)
41009dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		goto err;
4101217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
410264a14b51bed6427a2e6d68ed687027f065f5a156Michal Marek	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
410302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
410402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Initialize the tty_driver structure */
410502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
410602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->owner = THIS_MODULE;
410702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->driver_name = "cyclades";
410802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->name = "ttyC";
410902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->major = CYCLADES_MAJOR;
411002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->minor_start = 0;
411102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
411202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
411302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->init_termios = tty_std_termios;
411402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->init_termios.c_cflag =
411502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
41166ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
411702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	tty_set_operations(cy_serial_driver, &cy_ops);
411802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41199dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	retval = tty_register_driver(cy_serial_driver);
41209dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	if (retval) {
41219dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
41229dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		goto err_frtty;
41239dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	}
412402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
412502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* the code below is responsible to find the boards. Each different
412602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   type of board has its own detection routine. If a board is found,
412702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   the next cy_card structure available is set by the detection
412802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   routine. These functions are responsible for checking the
412902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   availability of cy_card and cy_port data structures and updating
413002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   the cy_next_channel. */
413102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
413202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* look for isa boards */
413314a55a6789d8409e58329310f9a18fc141deb4c2Jiri Slaby	nboards = cy_detect_isa();
413402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41356747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#ifdef CONFIG_PCI
413602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* look for pci boards */
41376747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	retval = pci_register_driver(&cy_pci_driver);
4138d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl	if (retval && !nboards) {
4139d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl		tty_unregister_driver(cy_serial_driver);
4140d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl		goto err_frtty;
4141d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl	}
41426747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
41439dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby
41449dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	return 0;
41459dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slabyerr_frtty:
41469dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	put_tty_driver(cy_serial_driver);
41479dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slabyerr:
41489dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	return retval;
414902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_init */
41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
415102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void __exit cy_cleanup_module(void)
41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4153dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	struct cyclades_card *card;
415465f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int i, e1;
41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
4157b70509066cba24067757f1422c899c43e433429dJiri Slaby	del_timer_sync(&cyz_timerlist);
41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_CYZ_INTR */
41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
416015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	e1 = tty_unregister_driver(cy_serial_driver);
416115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (e1)
4162217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_ERR "failed to unregister Cyclades serial "
4163217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"driver(%d)\n", e1);
41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41656747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#ifdef CONFIG_PCI
41666747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	pci_unregister_driver(&cy_pci_driver);
41676747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
41686747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby
416902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_CARDS; i++) {
4170dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		card = &cy_card[i];
4171dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		if (card->base_addr) {
417285c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby			/* clear interrupt */
4173dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4174dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			iounmap(card->base_addr);
417597e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			if (card->ctl_addr.p9050)
417697e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				iounmap(card->ctl_addr.p9050);
4177dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			if (card->irq
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
41792693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby				&& !cy_is_Z(card)
41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_CYZ_INTR */
418102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				)
4182dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby				free_irq(card->irq, card);
418365f76a82ec7a0374fad85211535330e203740475Jiri Slaby			for (e1 = card->first_line; e1 < card->first_line +
4184dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					card->nports; e1++)
41856ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby				tty_unregister_device(cy_serial_driver, e1);
4186dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			kfree(card->ports);
418702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
418802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
4189f2462bfe558559c9fbc4ef60812d5df30ccb01f6Jiri Slaby
4190f2462bfe558559c9fbc4ef60812d5df30ccb01f6Jiri Slaby	put_tty_driver(cy_serial_driver);
41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cy_cleanup_module */
41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(cy_init);
41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cy_cleanup_module);
41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
4197c8e1693a4f63e317966f3dfe8f815eda95e26610Jiri SlabyMODULE_VERSION(CY_VERSION);
41989f56fad741163fe2111cbbcfb7ff795ebdabdab1Scott James RemnantMODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4199e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("cyzfirm.bin");
4200