cyclades.c revision 8bab534b508230f33be5f7ba8492923754274a8d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	BLOCKMOVE
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	Z_WAKE
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	Z_EXT_CHARS_IN_BUFFER
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file contains the driver for the Cyclades async multiport
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial boards.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
12ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Much of the design and some of the code came from serial.c
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which was copyright (C) 1991, 1992  Linus Torvalds.  It was
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and then fixed as suggested by Michael K. Johnson 12/12/92.
18c8e1693a4f63e317966f3dfe8f815eda95e26610Jiri Slaby * Converted to pci probing and cleaned up by Jiri Slaby.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby#define CY_VERSION	"2.6"
23096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If you need to install more boards than NR_CARDS, change the constant
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   in the definition below. No other change is necessary to support up to
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   eight boards. Beyond that you'll have to extend cy_isa_addresses. */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#define NR_CARDS	4
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If the total number of ports is larger than NR_PORTS, change this
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   constant in the definition below. No other change is necessary to
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   support more boards/ports. */
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#define NR_PORTS	256
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZO_V1	0
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZO_V2	1
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZE_V1	2
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	SERIAL_PARANOIA_CHECK
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_OPEN
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_THROTTLE
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_OTHER
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_IO
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_COUNT
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_DTR
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_DEBUG_INTERRUPTS
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_16Y_HACK
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_ENABLE_MONITORING
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef	CY_PCI_DEBUG
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * Include section
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
6333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox#include <linux/tty_flip.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cyclades.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
76054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#include <linux/firmware.h>
779f56fad741163fe2111cbbcfb7ff795ebdabdab1Scott James Remnant#include <linux/device.h>
785a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox#include <linux/io.h>
8115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox#include <linux/uaccess.h>
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h>
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
88444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan#include <linux/seq_file.h>
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_send_xchar(struct tty_struct *tty, char ch);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SERIAL_XMIT_SIZE
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	SERIAL_XMIT_SIZE	(min(PAGE_SIZE, 4096))
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STD_COM_FLAGS (0)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby/* firmware stuff */
99054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define ZL_MAX_BLOCKS	16
100054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define DRIVER_VERSION	0x02010203
101054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define RAM_SIZE 0x80000
102054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
103054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyenum zblock_type {
104054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	ZBLOCK_PRG = 0,
105054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	ZBLOCK_FPGA = 1
106054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby};
107054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
108054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystruct zfile_header {
109054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char name[64];
110054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char date[32];
111054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char aux[32];
112054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 n_config;
113054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 config_offset;
114054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 n_blocks;
115054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 block_offset;
116054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 reserved[9];
117054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby} __attribute__ ((packed));
118054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
119054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystruct zfile_config {
120054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	char name[64];
121054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 mailbox;
122054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 function;
123054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 n_blocks;
124054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 block_list[ZL_MAX_BLOCKS];
125054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby} __attribute__ ((packed));
126054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
127054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystruct zfile_block {
128054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 type;
129054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 file_offset;
130054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 ram_offset;
131054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	u32 size;
132054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby} __attribute__ ((packed));
133054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *cy_serial_driver;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is the address lookup table. The driver will probe for
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Cyclom-Y/ISA boards at all addresses in here. If you want the
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   driver to probe addresses at a different address, add it to
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   this table.  If the driver is probing some other board and
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   causing problems, remove the offending address from this table.
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int cy_isa_addresses[] = {
14502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD0000,
14602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD2000,
14702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD4000,
14802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD6000,
14902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xD8000,
15002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xDA000,
15102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xDC000,
15202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0xDE000,
15302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0, 0, 0, 0, 0, 0, 0, 0
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
156fe971071a89c5c5184fc9f3482c7a8e997cf0520Tobias Klauser#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1583046d50ea58676759453faeefccf57fbc9b72a90Jiri Slabystatic long maddr[NR_CARDS];
1593046d50ea58676759453faeefccf57fbc9b72a90Jiri Slabystatic int irq[NR_CARDS];
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(maddr, long, NULL, 0);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is the per-card data structure containing address, irq, number of
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   channels, etc. This driver supports a maximum of NR_CARDS cards.
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cyclades_card cy_card[NR_CARDS];
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_next_channel;	/* next minor available */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is used to look up the divisor speeds and the timeouts
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We're normally limited to 15 distinct baud rates.  The extra
17677451e53e0a509a98eda272567869cfe96431ba9Alan Cox * are accessed via settings in info->port.flags.
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                               HI            VHI
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     20
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
182ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const int baud_table[] = {
18302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
18402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
18502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	230400, 0
18602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
18702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
188ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_co_25[] = {	/* 25 MHz clock option table */
18902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* value =>    00    01   02    03    04 */
19002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* divide by    8    32   128   512  2048 */
19102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
19202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
19302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
19402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
195ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_bpr_25[] = {	/* 25 MHz baud rate period table */
19602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
19702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
19802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
19902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
200ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_co_60[] = {	/* 60 MHz clock option table (CD1400 J) */
20102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* value =>    00    01   02    03    04 */
20202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* divide by    8    32   128   512  2048 */
20302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
20402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
20502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00
20602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
20702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
208ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_bpr_60[] = {	/* 60 MHz baud rate period table (CD1400 J) */
20902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
21002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
21102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x21
21202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
21302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
214ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char baud_cor3[] = {	/* receive threshold */
21502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
21602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
21702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x07
21802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The Cyclades driver implements HW flow control as any serial driver.
22215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * The cyclades_port structure member rflow and the vector rflow_thr
22315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * allows us to take advantage of a special feature in the CD1400 to avoid
22415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * data loss even when the system interrupt latency is too high. These flags
22515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * are to be used only with very special applications. Setting these flags
22615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * requires the use of a special cable (DTR and RTS reversed). In the new
22715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * CD1400-based boards (rev. 6.00 or later), there is no need for special
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cables.
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const char rflow_thr[] = {	/* rflow threshold */
23202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
23402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0a
23502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*  The Cyclom-Ye has placed the sequential chips in non-sequential
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  address order.  This look-up table overcomes that problem.
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
240f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slabystatic const unsigned int cy_chip_offset[] = { 0x0000,
24102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0400,
24202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0800,
24302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0C00,
24402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0200,
24502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0600,
24602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0A00,
24702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	0x0E00
24802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCI related definitions */
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
253ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slabystatic const struct pci_device_id cy_pci_dev_id[] = {
25415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* PCI < 1Mb */
25515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
25615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* PCI > 1Mb */
25715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
25815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 4Y PCI < 1Mb */
25915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
26015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 4Y PCI > 1Mb */
26115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
26215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 8Y PCI < 1Mb */
26315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
26415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* 8Y PCI > 1Mb */
26515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
26615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* Z PCI < 1Mb */
26715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
26815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	/* Z PCI > 1Mb */
26915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
270893de2dffb0923d9bdba4abd66afcec3cf9103baJiri Slaby	{ }			/* end of table */
27102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby};
272893de2dffb0923d9bdba4abd66afcec3cf9103baJiri SlabyMODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cy_start(struct tty_struct *);
276d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
2771a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielkastatic int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned detect_isa_irq(void __iomem *);
28002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyz_poll(unsigned long);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The Cyclades-Z polling cycle is defined by this variable */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long cyz_polling_cycle = CZ_DEF_POLL;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2888d06afab73a75f40ae2864e6c296356bab1ab473Ingo Molnarstatic DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#else				/* CONFIG_CYZ_INTR */
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyz_rx_restart(unsigned long);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list cyz_rx_full_timer[NR_PORTS];
29302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2953aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
2963aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby{
2973aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = port->card;
2983aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
2993aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
3003aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3023aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
3033aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby{
3043aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = port->card;
3053aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3063aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	return readb(port->u.cyy.base_addr + (reg << card->bus_index));
3073aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3083aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3092693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool cy_is_Z(struct cyclades_card *card)
3102693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3112693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return card->num_chips == (unsigned int)-1;
3122693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3132693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3142693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
3152693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3162693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return readl(&ctl_addr->init_ctrl) & (1 << 17);
3172693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3182693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3192693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool cyz_fpga_loaded(struct cyclades_card *card)
3202693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3212693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return __cyz_fpga_loaded(card->ctl_addr.p9060);
3222693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3232693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3242693f485c22d18474c077f12fd0f797ee8679b33Jiri Slabystatic inline bool cyz_is_loaded(struct cyclades_card *card)
3252693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby{
3262693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
3272693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
3282693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
3292693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			readl(&fw_id->signature) == ZFIRM_ID;
3302693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby}
3312693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby
33202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic inline int serial_paranoia_check(struct cyclades_port *info,
333ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby		const char *name, const char *routine)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SERIAL_PARANOIA_CHECK
33602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!info) {
337217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
338217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"in %s\n", name, routine);
33902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 1;
34002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
34102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
34202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->magic != CYCLADES_MAGIC) {
343217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_WARNING "cyc Warning: bad magic number for serial "
344217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"struct (%s) in %s\n", name, routine);
34502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 1;
34602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
34802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
349ebdb513596c0eb1dcb3bad8f53865964a2207ca9Jiri Slaby}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********* Start of block of Cyclom-Y specific code ********/
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine waits up to 1000 micro-seconds for the previous
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   command to the Cirrus chip to complete and then issues the
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   new command.  An error is returned if the previous command
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   didn't finish within the time limit.
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This function is only called from inside spinlock-protected code.
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3613aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3633aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	void __iomem *ccr = base_addr + (CyCCR << index);
364ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby	unsigned int i;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Check to see that the previous command has completed */
36702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < 100; i++) {
3683aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		if (readb(ccr) == 0)
36902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
37002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(10L);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* if the CCR never cleared, the previous command
37302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   didn't finish within the "reasonable time" */
37402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (i == 100)
375096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return -1;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Issue the new command */
3783aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cy_writeb(ccr, cmd);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
380096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
3813aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3823aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby
3833aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slabystatic inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
3843aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby{
3853aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
3863aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			port->card->bus_index);
3873aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ISA interrupt detection code */
39115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic unsigned detect_isa_irq(void __iomem *address)
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int irq;
39402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long irqs, flags;
39502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int save_xir, save_car;
39602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int index = 0;		/* IRQ probing is only for ISA */
39702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
39802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* forget possible initially masked and pending IRQ */
39902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	irq = probe_irq_off(probe_irq_on());
40002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
40102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Clear interrupts on the board first */
40202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (Cy_ClrIntr << index), 0);
40302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
40402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
40502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	irqs = probe_irq_on();
40602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Wait ... */
407f6e208c1119206e2382ef7df6e47aaee18eb7f10Jiri Slaby	msleep(5);
40802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
40902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Enable the Tx interrupts on the CD1400 */
41002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	local_irq_save(flags);
41102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), 0);
4123aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	__cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
41302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), 0);
41502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CySRER << index),
416db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		  readb(address + (CySRER << index)) | CyTxRdy);
41702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	local_irq_restore(flags);
41802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Wait ... */
420f6e208c1119206e2382ef7df6e47aaee18eb7f10Jiri Slaby	msleep(5);
42102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
42202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Check which interrupt is in use */
42302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	irq = probe_irq_off(irqs);
42402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
42502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Clean up */
426db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	save_xir = (u_char) readb(address + (CyTIR << index));
427db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	save_car = readb(address + (CyCAR << index));
42802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
42902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CySRER << index),
430db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		  readb(address + (CySRER << index)) & ~CyTxRdy);
43102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
43202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (CyCAR << index), (save_car));
43302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(address + (Cy_ClrIntr << index), 0);
43402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
43502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
43602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return (irq > 0) ? irq : 0;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
43802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
440ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabystatic void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
441ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		void __iomem *base_addr)
442e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby{
443e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	struct cyclades_port *info;
444e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	struct tty_struct *tty;
44565f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int len, index = cinfo->bus_index;
4463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	u8 ivr, save_xir, channel, save_car, data, char_count;
447e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
448e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_DEBUG_INTERRUPTS
449ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
450e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
451ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* determine the channel & change to that context */
45265f76a82ec7a0374fad85211535330e203740475Jiri Slaby	save_xir = readb(base_addr + (CyRIR << index));
45365f76a82ec7a0374fad85211535330e203740475Jiri Slaby	channel = save_xir & CyIRChannel;
454ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	info = &cinfo->ports[channel + chip * 4];
4553aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	save_car = cyy_readb(info, CyCAR);
4563aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_xir);
4573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
458ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
459d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty = tty_port_tty_get(&info->port);
460ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* if there is nowhere to put the data, discard it */
461d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (tty == NULL) {
4623aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		if (ivr == CyIVRRxEx) {	/* exception */
4633aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			data = cyy_readb(info, CyRDSR);
464ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {	/* normal character reception */
4653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			char_count = cyy_readb(info, CyRDCR);
466ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			while (char_count--)
4673aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				data = cyy_readb(info, CyRDSR);
468ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
469ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		goto end;
470ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
471ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* there is an open port for this data */
4723aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	if (ivr == CyIVRRxEx) {	/* exception */
4733aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		data = cyy_readb(info, CyRDSR);
474ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
475ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* For statistics only */
476ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (data & CyBREAK)
477ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.brk++;
478ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		else if (data & CyFRAME)
479ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.frame++;
480ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		else if (data & CyPARITY)
481ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.parity++;
482ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		else if (data & CyOVERRUN)
483ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.overrun++;
484ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
485ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (data & info->ignore_status_mask) {
486ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.rx++;
487d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty_kref_put(tty);
488ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			return;
489ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
490ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (tty_buffer_request_room(tty, 1)) {
491ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (data & info->read_status_mask) {
492ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (data & CyBREAK) {
493ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty,
4943aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
4953aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_BREAK);
496ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
49777451e53e0a509a98eda272567869cfe96431ba9Alan Cox					if (info->port.flags & ASYNC_SAK)
498ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby						do_SAK(tty);
499ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else if (data & CyFRAME) {
50015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox					tty_insert_flip_char(tty,
5013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
5023aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_FRAME);
503ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
504ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->idle_stats.frame_errs++;
505ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else if (data & CyPARITY) {
506ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					/* Pieces of seven... */
507ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty,
5083aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
5093aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_PARITY);
510ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
511ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->idle_stats.parity_errs++;
512ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else if (data & CyOVERRUN) {
513ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty, 0,
514ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby							TTY_OVERRUN);
515ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
516ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					/* If the flip buffer itself is
517ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					   overflowing, we still lose
518ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					   the next incoming character.
519ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					 */
520ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty,
5213aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						cyy_readb(info, CyRDSR),
5223aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby						TTY_FRAME);
52302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					info->icount.rx++;
52402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					info->idle_stats.overruns++;
525ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* These two conditions may imply */
526ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* a normal read should be done. */
527ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* } else if(data & CyTIMEOUT) { */
528ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* } else if(data & CySPECHAR) { */
529ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				} else {
530ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					tty_insert_flip_char(tty, 0,
531ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby							TTY_NORMAL);
532ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					info->icount.rx++;
53302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
534ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			} else {
535ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				tty_insert_flip_char(tty, 0, TTY_NORMAL);
536ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				info->icount.rx++;
537ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			}
538ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {
539ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			/* there was a software buffer overrun and nothing
540ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			 * could be done about it!!! */
541ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.buf_overrun++;
542ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->idle_stats.overruns++;
543ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
544ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	} else {	/* normal character reception */
545ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* load # chars available from the chip */
5463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		char_count = cyy_readb(info, CyRDCR);
547e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
548e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_ENABLE_MONITORING
549ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		++info->mon.int_count;
550ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->mon.char_count += char_count;
551ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (char_count > info->mon.char_max)
552ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->mon.char_max = char_count;
553ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->mon.char_last = char_count;
554e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
555ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		len = tty_buffer_request_room(tty, char_count);
556ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		while (len--) {
5573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			data = cyy_readb(info, CyRDSR);
558ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			tty_insert_flip_char(tty, data, TTY_NORMAL);
559ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->idle_stats.recv_bytes++;
560ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.rx++;
561e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_16Y_HACK
562ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			udelay(10L);
563e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
564e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
565ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->idle_stats.recv_idle = jiffies;
566e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	}
567ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	tty_schedule_flip(tty);
568d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_kref_put(tty);
569ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabyend:
570ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* end of service */
5713aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyRIR, save_xir & 0x3f);
5723aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_car);
573ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby}
574e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
57565f76a82ec7a0374fad85211535330e203740475Jiri Slabystatic void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
576ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		void __iomem *base_addr)
577ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby{
578ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	struct cyclades_port *info;
579d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	struct tty_struct *tty;
58065f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int char_count, index = cinfo->bus_index;
58165f76a82ec7a0374fad85211535330e203740475Jiri Slaby	u8 save_xir, channel, save_car, outch;
582ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
583ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* Since we only get here when the transmit buffer
584ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	   is empty, we know we can always stuff a dozen
585ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	   characters. */
586e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#ifdef CY_DEBUG_INTERRUPTS
587ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
588e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby#endif
589e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
590ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* determine the channel & change to that context */
59165f76a82ec7a0374fad85211535330e203740475Jiri Slaby	save_xir = readb(base_addr + (CyTIR << index));
59265f76a82ec7a0374fad85211535330e203740475Jiri Slaby	channel = save_xir & CyIRChannel;
593ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	save_car = readb(base_addr + (CyCAR << index));
594ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	cy_writeb(base_addr + (CyCAR << index), save_xir);
595ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
596ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	info = &cinfo->ports[channel + chip * 4];
597d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty = tty_port_tty_get(&info->port);
598d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (tty == NULL) {
5993aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
600ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		goto end;
601ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
60202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
603ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* load the on-chip space for outbound data */
604ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	char_count = info->xmit_fifo_size;
60502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
606ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (info->x_char) {	/* send special char */
607ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		outch = info->x_char;
6083aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTDR, outch);
609ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		char_count--;
610ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->icount.tx++;
611ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		info->x_char = 0;
612ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
61302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
614ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (info->breakon || info->breakoff) {
615ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (info->breakon) {
6163aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0);
6173aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0x81);
618ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->breakon = 0;
619ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			char_count -= 2;
620e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
621ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (info->breakoff) {
6223aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0);
6233aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, 0x83);
624ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->breakoff = 0;
625ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			char_count -= 2;
626e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
627ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
62802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
629ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	while (char_count-- > 0) {
630ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (!info->xmit_cnt) {
6313aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			if (cyy_readb(info, CySRER) & CyTxMpty) {
6323aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER,
6333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					cyy_readb(info, CySRER) & ~CyTxMpty);
634ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			} else {
6353aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER, CyTxMpty |
6363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					(cyy_readb(info, CySRER) & ~CyTxRdy));
63702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
638ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			goto done;
639ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
64077451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.xmit_buf == NULL) {
6413aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CySRER,
6423aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_readb(info, CySRER) & ~CyTxRdy);
643ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			goto done;
644ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
645d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		if (tty->stopped || tty->hw_stopped) {
6463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CySRER,
6473aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_readb(info, CySRER) & ~CyTxRdy);
648ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			goto done;
649ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		}
650ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* Because the Embedded Transmit Commands have been enabled,
651ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * we must check to see if the escape character, NULL, is being
652ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * sent. If it is, we must ensure that there is room for it to
653ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * be doubled in the output stream.  Therefore we no longer
654ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * advance the pointer when the character is fetched, but
655ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * rather wait until after the check for a NULL output
656ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * character. This is necessary because there may not be room
657ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 * for the two chars needed to send a NULL.)
658ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		 */
65977451e53e0a509a98eda272567869cfe96431ba9Alan Cox		outch = info->port.xmit_buf[info->xmit_tail];
660ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (outch) {
661ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->xmit_cnt--;
662ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->xmit_tail = (info->xmit_tail + 1) &
663ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					(SERIAL_XMIT_SIZE - 1);
6643aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_writeb(info, CyTDR, outch);
665ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.tx++;
666ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {
667ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (char_count > 1) {
66802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->xmit_cnt--;
66902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->xmit_tail = (info->xmit_tail + 1) &
670ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					(SERIAL_XMIT_SIZE - 1);
6713aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CyTDR, outch);
6723aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CyTDR, 0);
67302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->icount.tx++;
674ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				char_count--;
67502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
676e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
677e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	}
678e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
679ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabydone:
680d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_wakeup(tty);
681d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_kref_put(tty);
682ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabyend:
683ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* end of service */
6843aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyTIR, save_xir & 0x3f);
6853aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_car);
686ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby}
68702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
688ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabystatic void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
689ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		void __iomem *base_addr)
690ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby{
691ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	struct cyclades_port *info;
692d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	struct tty_struct *tty;
69365f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int index = cinfo->bus_index;
69465f76a82ec7a0374fad85211535330e203740475Jiri Slaby	u8 save_xir, channel, save_car, mdm_change, mdm_status;
695ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
696ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* determine the channel & change to that context */
69765f76a82ec7a0374fad85211535330e203740475Jiri Slaby	save_xir = readb(base_addr + (CyMIR << index));
69865f76a82ec7a0374fad85211535330e203740475Jiri Slaby	channel = save_xir & CyIRChannel;
699ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	info = &cinfo->ports[channel + chip * 4];
7003aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	save_car = cyy_readb(info, CyCAR);
7013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_xir);
702ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
7033aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	mdm_change = cyy_readb(info, CyMISR);
7043aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	mdm_status = cyy_readb(info, CyMSVR1);
705ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
706d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty = tty_port_tty_get(&info->port);
707d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (!tty)
708ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		goto end;
709ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
710ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (mdm_change & CyANY_DELTA) {
711ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		/* For statistics only */
712ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyDCD)
713ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.dcd++;
714ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyCTS)
715ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.cts++;
716ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyDSR)
717ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.dsr++;
718ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		if (mdm_change & CyRI)
719ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			info->icount.rng++;
720ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
721bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		wake_up_interruptible(&info->port.delta_msr_wait);
722ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
723ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby
72477451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
725174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby		if (mdm_status & CyDCD)
726174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby			wake_up_interruptible(&info->port.open_wait);
727174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby		else
728d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty_hangup(tty);
729ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
73077451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
731d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		if (tty->hw_stopped) {
732ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (mdm_status & CyCTS) {
733ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* cy_start isn't used
734ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				   because... !!! */
735d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty->hw_stopped = 0;
7363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER,
7373aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					cyy_readb(info, CySRER) | CyTxRdy);
738d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty_wakeup(tty);
73902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
740ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby		} else {
741ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby			if (!(mdm_status & CyCTS)) {
742ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				/* cy_stop isn't used
743ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				   because ... !!! */
744d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty->hw_stopped = 1;
7453aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				cyy_writeb(info, CySRER,
7463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby					cyy_readb(info, CySRER) & ~CyTxRdy);
74702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
748e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby		}
749e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby	}
750ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby/*	if (mdm_change & CyDSR) {
751ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}
752ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	if (mdm_change & CyRI) {
753ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	}*/
754d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_kref_put(tty);
755ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slabyend:
756ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby	/* end of service */
7573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyMIR, save_xir & 0x3f);
7583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, save_car);
759e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby}
760e941027f53648ac3384057032be1ac64da3e8cd0Jiri Slaby
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The real interrupt service routine is called
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   whenever the card wants its hand held--chars
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   received, out buffer empty, modem change, etc.
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
76502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic irqreturn_t cyy_interrupt(int irq, void *dev_id)
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
76702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int status;
768f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	struct cyclades_card *cinfo = dev_id;
76902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *base_addr, *card_base_addr;
77065f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int chip, too_many, had_work;
77102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int index;
77202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
773f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	if (unlikely(cinfo == NULL)) {
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
77515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
77615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox				irq);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
77802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return IRQ_NONE;	/* spurious interrupt */
77902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
78002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
78102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card_base_addr = cinfo->base_addr;
78202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	index = cinfo->bus_index;
78302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
784f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby	/* card was not initialized yet (e.g. DEBUG_SHIRQ) */
785f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby	if (unlikely(card_base_addr == NULL))
786f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby		return IRQ_HANDLED;
787f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683Jiri Slaby
78802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* This loop checks all chips in the card.  Make a note whenever
78902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   _any_ chip had some work to do, as this is considered an
79002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   indication that there will be more to do.  Only when no chip
79102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   has any work does this outermost loop exit.
79202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
79302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	do {
79402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		had_work = 0;
79502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (chip = 0; chip < cinfo->num_chips; chip++) {
79602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			base_addr = cinfo->base_addr +
79702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(cy_chip_offset[chip] << index);
79802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			too_many = 0;
799db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			while ((status = readb(base_addr +
80002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						(CySVRR << index))) != 0x00) {
80102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				had_work++;
80202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* The purpose of the following test is to ensure that
80302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   no chip can monopolize the driver.  This forces the
80402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   chips to be checked in a round-robin fashion (after
80502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   draining each of a bunch (1000) of characters).
80602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
807ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (1000 < too_many++)
80802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					break;
8091c0a387c1f9e48e480579d3b4e0f9c1a36c77751Jiri Slaby				spin_lock(&cinfo->card_lock);
810ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (status & CySRReceive) /* rx intr */
811ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					cyy_chip_rx(cinfo, chip, base_addr);
812ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (status & CySRTransmit) /* tx intr */
813ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					cyy_chip_tx(cinfo, chip, base_addr);
814ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby				if (status & CySRModem) /* modem intr */
815ce97a09767b59dcde3715ba4a9eebc71b0ce71b2Jiri Slaby					cyy_chip_modem(cinfo, chip, base_addr);
8161c0a387c1f9e48e480579d3b4e0f9c1a36c77751Jiri Slaby				spin_unlock(&cinfo->card_lock);
81702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
81802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
81902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} while (had_work);
82002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
82102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* clear interrupts */
82202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	spin_lock(&cinfo->card_lock);
82302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
82402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
82502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	spin_unlock(&cinfo->card_lock);
82602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return IRQ_HANDLED;
82702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyy_interrupt */
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8294d7682005ca88a37667c4af03908798e188b5224Jiri Slabystatic void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
8304d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		unsigned int clear)
8314d7682005ca88a37667c4af03908798e188b5224Jiri Slaby{
8324d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	struct cyclades_card *card = info->card;
8333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel = info->line - card->first_line;
8340d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	u32 rts, dtr, msvrr, msvrd;
8354d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
8364d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	channel &= 0x03;
8374d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
8380d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	if (info->rtsdtr_inv) {
8390d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrr = CyMSVR2;
8400d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrd = CyMSVR1;
8410d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rts = CyDTR;
8420d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		dtr = CyRTS;
8430d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	} else {
8440d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrr = CyMSVR1;
8450d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		msvrd = CyMSVR2;
8460d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rts = CyRTS;
8470d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		dtr = CyDTR;
8480d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby	}
8494d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (set & TIOCM_RTS) {
8503aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8513aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrr, rts);
8524d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8534d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (clear & TIOCM_RTS) {
8543aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8553aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrr, ~rts);
8564d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8574d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (set & TIOCM_DTR) {
8583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8593aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrd, dtr);
8604d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#ifdef CY_DEBUG_DTR
8614d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
8624d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
8633aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR1),
8643aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR2));
8654d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#endif
8664d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8674d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	if (clear & TIOCM_DTR) {
8683aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
8693aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, msvrd, ~dtr);
8704d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#ifdef CY_DEBUG_DTR
8714d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
8724d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
8733aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR1),
8743aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			cyy_readb(info, CyMSVR2));
8754d7682005ca88a37667c4af03908798e188b5224Jiri Slaby#endif
8764d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	}
8774d7682005ca88a37667c4af03908798e188b5224Jiri Slaby}
8784d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********* End of block of Cyclom-Y specific code **********/
88115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox/******** Start of block of Cyclades-Z specific code *******/
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
88502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabycyz_fetch_msg(struct cyclades_card *cinfo,
88615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		__u32 *channel, __u8 *cmd, __u32 *param)
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
888f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
88902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long loc_doorbell;
89002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
89197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
89202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (loc_doorbell) {
89302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		*cmd = (char)(0xff & loc_doorbell);
894db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		*channel = readl(&board_ctrl->fwcmd_channel);
895db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		*param = (__u32) readl(&board_ctrl->fwcmd_param);
89697e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
89702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 1;
89802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
89902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
90002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_fetch_msg */
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
90302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabycyz_issue_cmd(struct cyclades_card *cinfo,
9041a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka		__u32 channel, __u8 cmd, __u32 param)
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
906f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
9071a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u32 __iomem *pci_doorbell;
90865f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int index;
90902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
9102693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cyz_is_loaded(cinfo))
911096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return -1;
91215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
91302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	index = 0;
91497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
915db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	while ((readl(pci_doorbell) & 0xff) != 0) {
91615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (index++ == 1000)
917db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			return (int)(readl(pci_doorbell) & 0xff);
91802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(50L);
91902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
92002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writel(&board_ctrl->hcmd_channel, channel);
92102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writel(&board_ctrl->hcmd_param, param);
92202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writel(pci_doorbell, (long)cmd);
92302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
924096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
92502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_issue_cmd */
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
927f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slabystatic void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
929f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
930875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
93165f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int char_count;
93202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int len;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
934ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby	unsigned char *buf;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
93602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char data;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
938ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby	__u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
940db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
941db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_put = readl(&buf_ctrl->rx_put);
942db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_bufsize = readl(&buf_ctrl->rx_bufsize);
943db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
94402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (rx_put >= rx_get)
94502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = rx_put - rx_get;
94602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	else
94702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = rx_put - rx_get + rx_bufsize;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
94902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_count) {
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_ENABLE_MONITORING
95102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->mon.int_count++;
95202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->mon.char_count += char_count;
95302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (char_count > info->mon.char_max)
95402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->mon.char_max = char_count;
95502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->mon.char_last = char_count;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
957f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby		if (tty == NULL) {
95802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* flush received characters */
95902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			new_rx_get = (new_rx_get + char_count) &
96002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(rx_bufsize - 1);
96102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->rflush_count++;
96202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
96402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
96502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   for performance, but because of buffer boundaries, there
96602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   may be several steps to the operation */
967ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby			while (1) {
968ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				len = tty_prepare_flip_string(tty, &buf,
969ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby						char_count);
970ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				if (!len)
971ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby					break;
972ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby
973ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				len = min_t(unsigned int, min(len, char_count),
974ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby						rx_bufsize - new_rx_get);
975ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby
976ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				memcpy_fromio(buf, cinfo->base_addr +
977ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby						rx_bufaddr + new_rx_get, len);
978ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby
979ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				new_rx_get = (new_rx_get + len) &
98002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						(rx_bufsize - 1);
981ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				char_count -= len;
982ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				info->icount.rx += len;
983ce71b0ffd01b0917a74c03562aaa110a71a0ee29Jiri Slaby				info->idle_stats.recv_bytes += len;
98402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
98602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			len = tty_buffer_request_room(tty, char_count);
98702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			while (len--) {
988db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				data = readb(cinfo->base_addr + rx_bufaddr +
98902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						new_rx_get);
99015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox				new_rx_get = (new_rx_get + 1) &
99115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox							(rx_bufsize - 1);
99202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				tty_insert_flip_char(tty, data, TTY_NORMAL);
99302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->idle_stats.recv_bytes++;
99402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->icount.rx++;
99502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
99802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Recalculate the number of chars in the RX buffer and issue
99902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   a cmd in case it's higher than the RX high water mark */
1000db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			rx_put = readl(&buf_ctrl->rx_put);
100102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (rx_put >= rx_get)
100202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				char_count = rx_put - rx_get;
100302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
100402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				char_count = rx_put - rx_get + rx_bufsize;
100565f76a82ec7a0374fad85211535330e203740475Jiri Slaby			if (char_count >= readl(&buf_ctrl->rx_threshold) &&
1006ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby					!timer_pending(&cyz_rx_full_timer[
1007ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby							info->line]))
1008ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby				mod_timer(&cyz_rx_full_timer[info->line],
1009ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby						jiffies + 1);
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
101102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->idle_stats.recv_idle = jiffies;
101202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_schedule_flip(tty);
101302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
101402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Update rx_get */
101502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&buf_ctrl->rx_get, new_rx_get);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1019f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slabystatic void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1021f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1022875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
102365f76a82ec7a0374fad85211535330e203740475Jiri Slaby	u8 data;
102465f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int char_count;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
102602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int small_count;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1028ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby	__u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
103102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1033db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_get = readl(&buf_ctrl->tx_get);
1034db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_put = readl(&buf_ctrl->tx_put);
1035db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1036db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
103702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tx_put >= tx_get)
103802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = tx_get - tx_put - 1 + tx_bufsize;
103902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	else
104002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_count = tx_get - tx_put - 1;
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
104202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_count) {
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1044f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby		if (tty == NULL)
104502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			goto ztxdone;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
104702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->x_char) {	/* send special char */
104802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			data = info->x_char;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
105002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
105102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tx_put = (tx_put + 1) & (tx_bufsize - 1);
105202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->x_char = 0;
105302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count--;
105402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.tx++;
105502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BLOCKMOVE
105702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		while (0 < (small_count = min_t(unsigned int,
105802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				tx_bufsize - tx_put, min_t(unsigned int,
105902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(SERIAL_XMIT_SIZE - info->xmit_tail),
106002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					min_t(unsigned int, info->xmit_cnt,
106102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						char_count))))) {
106202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
106302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
106402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					tx_put),
106577451e53e0a509a98eda272567869cfe96431ba9Alan Cox					&info->port.xmit_buf[info->xmit_tail],
106602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					small_count);
106702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
106802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tx_put = (tx_put + small_count) & (tx_bufsize - 1);
106902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count -= small_count;
107002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.tx += small_count;
107102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_cnt -= small_count;
107202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_tail = (info->xmit_tail + small_count) &
107302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(SERIAL_XMIT_SIZE - 1);
107402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
107602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		while (info->xmit_cnt && char_count) {
107777451e53e0a509a98eda272567869cfe96431ba9Alan Cox			data = info->port.xmit_buf[info->xmit_tail];
107802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_cnt--;
107902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->xmit_tail = (info->xmit_tail + 1) &
108002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					(SERIAL_XMIT_SIZE - 1);
108102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
108202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
108302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tx_put = (tx_put + 1) & (tx_bufsize - 1);
108402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count--;
108502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.tx++;
108602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1088ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby		tty_wakeup(tty);
10897fa57a0cd98bdd163eeb5f15cbe234c3a0cf68a1Jiri Slabyztxdone:
109002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Update tx_put */
109102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&buf_ctrl->tx_put, tx_put);
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cyz_handle_cmd(struct cyclades_card *cinfo)
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1097f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
109802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct tty_struct *tty;
109902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
1100101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby	__u32 channel, param, fw_ver;
11011a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u8 cmd;
110202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int special_count;
110302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int delta_count;
110402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1105db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby	fw_ver = readl(&board_ctrl->fw_version);
110602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
110702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
110802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		special_count = 0;
110902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		delta_count = 0;
1110dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		info = &cinfo->ports[channel];
1111d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty = tty_port_tty_get(&info->port);
111215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (tty == NULL)
111302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
1114f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby
111502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cmd) {
111602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_PR_ERROR:
111702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_insert_flip_char(tty, 0, TTY_PARITY);
111802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rx++;
111902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			special_count++;
112002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
112102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_FR_ERROR:
112202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_insert_flip_char(tty, 0, TTY_FRAME);
112302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rx++;
112402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			special_count++;
112502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
112602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_RXBRK:
112702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_insert_flip_char(tty, 0, TTY_BREAK);
112802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rx++;
112902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			special_count++;
113002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
113102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MDCD:
113202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.dcd++;
113302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
113477451e53e0a509a98eda272567869cfe96431ba9Alan Cox			if (info->port.flags & ASYNC_CHECK_CD) {
1135f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				u32 dcd = fw_ver > 241 ? param :
1136f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby					readl(&info->u.cyz.ch_ctrl->rs_status);
1137174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby				if (dcd & C_RS_DCD)
113877451e53e0a509a98eda272567869cfe96431ba9Alan Cox					wake_up_interruptible(&info->port.open_wait);
1139174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby				else
1140d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					tty_hangup(tty);
114102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
114202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
114302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MCTS:
114402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.cts++;
114502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
114602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
114702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MRI:
114802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.rng++;
114902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
115002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
115102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_MDSR:
115202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->icount.dsr++;
115302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			delta_count++;
115402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_WAKE
115602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_IOCTLW:
1157ebafeeff0fea029099e9952f233e0794106897a6Jiri Slaby			complete(&info->shutdown_wait);
115802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
116102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_RXHIWM:
116202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_RXNNDT:
116302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_INTBACK2:
116402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Reception Interrupt */
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
1166217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1167217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"port %ld\n", info->card, channel);
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1169f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			cyz_handle_rx(info, tty);
117002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
117102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_TXBEMPTY:
117202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_TXLOWWM:
117302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_INTBACK:
117402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Transmission Interrupt */
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
1176217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1177217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"port %ld\n", info->card, channel);
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1179f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			cyz_handle_tx(info, tty);
118002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
118102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
118202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case C_CM_FATAL:
118302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* should do something with this !!! */
118402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
118502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		default:
118602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
118702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
118802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (delta_count)
1189bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox			wake_up_interruptible(&info->port.delta_msr_wait);
119002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (special_count)
119102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty_schedule_flip(tty);
1192d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty_kref_put(tty);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
119702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic irqreturn_t cyz_interrupt(int irq, void *dev_id)
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1199f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	struct cyclades_card *cinfo = dev_id;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12012693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (unlikely(!cyz_is_loaded(cinfo))) {
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_INTERRUPTS
1203217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1204217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"(IRQ%d).\n", irq);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
120602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return IRQ_NONE;
120702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Handle the interrupts */
121002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cyz_handle_cmd(cinfo);
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return IRQ_HANDLED;
121302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_interrupt */
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cyz_rx_restart(unsigned long arg)
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
121702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info = (struct cyclades_port *)arg;
1218875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card = info->card;
121902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int retval;
1220875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	__u32 channel = info->line - card->first_line;
122102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
122202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
12239fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
1224875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
122502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (retval != 0) {
1226217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
122702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->line, retval);
122802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
12299fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#else				/* CONFIG_CYZ_INTR */
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cyz_poll(unsigned long arg)
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
123602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
123702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
1238b70509066cba24067757f1422c899c43e433429dJiri Slaby	unsigned long expires = jiffies + HZ;
123965f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int port, card;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (card = 0; card < NR_CARDS; card++) {
124202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cinfo = &cy_card[card];
124302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
12442693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(cinfo))
124502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
12462693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(cinfo))
124702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
124802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Skip first polling cycle to avoid racing conditions with the FW */
125002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (!cinfo->intr_enabled) {
125102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cinfo->intr_enabled = 1;
125202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
125302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cyz_handle_cmd(cinfo);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (port = 0; port < cinfo->nports; port++) {
1258d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			struct tty_struct *tty;
1259d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby
1260dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			info = &cinfo->ports[port];
1261d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty = tty_port_tty_get(&info->port);
1262d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			/* OK to pass NULL to the handle functions below.
1263d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			   They need to drop the data in that case. */
1264d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby
126502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->throttle)
1266f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				cyz_handle_rx(info, tty);
1267f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			cyz_handle_tx(info, tty);
1268d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			tty_kref_put(tty);
126902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
127002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* poll every 'cyz_polling_cycle' period */
1271b70509066cba24067757f1422c899c43e433429dJiri Slaby		expires = jiffies + cyz_polling_cycle;
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1273b70509066cba24067757f1422c899c43e433429dJiri Slaby	mod_timer(&cyz_timerlist, expires);
127402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyz_poll */
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** End of block of Cyclades-Z specific code *********/
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***********************************************************/
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is called whenever a port becomes active;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   interrupts are enabled and DTR & RTS are turned on.
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1284d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1286875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
128702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
128802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int retval = 0;
1289cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	int channel;
129002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long page;
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
129202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
1293875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
129502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	page = get_zeroed_page(GFP_KERNEL);
129602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!page)
129702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENOMEM;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12999fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	if (info->port.flags & ASYNC_INITIALIZED)
130202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto errout;
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
130402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!info->type) {
1305d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		set_bit(TTY_IO_ERROR, &tty->flags);
130602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto errout;
130702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
130977451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (info->port.xmit_buf)
131002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		free_page(page);
131102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	else
131277451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.xmit_buf = (unsigned char *)page;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13149fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1316d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_set_line_char(info, tty);
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13182693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
131902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		channel &= 0x03;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13219fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13233aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13253aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR,
132602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(info->default_timeout ? info->default_timeout : 0x02));
132702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* 10ms rx timeout */
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13293aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13314d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
133402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
1335f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13372693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
133802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1341217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1342f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			"base_addr %p\n", card, channel, card->base_addr);
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
13449fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1346f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_WAKE
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
1349f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable,
135002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
135102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1353f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable,
135402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_IOCTLW | C_IN_MDCD);
135502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
1358f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable,
135902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
136002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			  C_IN_RXNNDT | C_IN_MDCD);
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1362f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
136302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
136402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_WAKE */
136502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1366875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
136702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
1368217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1369217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"%x\n", info->line, retval);
137002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
137202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Flush RX buffers before raising DTR and RTS */
1373875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
137402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
1375217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1376217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"%x\n", info->line, retval);
137702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
137902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set timeout !!! */
138002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set RTS and DTR !!! */
13814d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		tty_port_raise_dtr_rts(&info->port);
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
138302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* enable send, recv, modem !!! */
1384cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	}
138502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1386cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->port.flags |= ASYNC_INITIALIZED;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1388cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	clear_bit(TTY_IO_ERROR, &tty->flags);
1389cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1390cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->breakon = info->breakoff = 0;
1391cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1392cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->idle_stats.in_use =
1393cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->idle_stats.recv_idle =
1394cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	info->idle_stats.xmit_idle = jiffies;
1395cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby
1396cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1399217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc startup done\n");
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserrout:
14049fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
1405cc7fdf49d6f06efdf0cb7da8d7abe7eff663aa9bJiri Slaby	free_page(page);
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
140702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* startup */
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
140902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void start_xmit(struct cyclades_port *info)
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14113aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
141202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
14133aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel = info->line - card->first_line;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14152693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
14169fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
14173aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
14183aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
14199fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
142002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CYZ_INTR
142202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14249fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
1425875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
142602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
1427217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1428217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"%x\n", info->line, retval);
142902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
14309fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
143102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#else				/* CONFIG_CYZ_INTR */
143202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Don't have to do anything at this time */
143302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
143402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
143502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* start_xmit */
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine shuts down a serial port; interrupts are disabled,
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and DTR is dropped if the hangup on close termio flag is on.
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1441d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1443875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
144402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
144502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
144677451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!(info->port.flags & ASYNC_INITIALIZED))
144702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
144802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
144902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
14502693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
14519fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
145202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
145302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Clear delta_msr_wait queue to avoid mem leaks. */
1454bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		wake_up_interruptible(&info->port.delta_msr_wait);
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145677451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.xmit_buf) {
145702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			unsigned char *temp;
145877451e53e0a509a98eda272567869cfe96431ba9Alan Cox			temp = info->port.xmit_buf;
145977451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.xmit_buf = NULL;
146002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			free_page((unsigned long)temp);
146102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
14624d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (tty->termios->c_cflag & HUPCL)
14634d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
14644d7682005ca88a37667c4af03908798e188b5224Jiri Slaby
14653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
146602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* it may be appropriate to clear _XMIT at
146702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   some later date (after testing)!!! */
146802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1469d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		set_bit(TTY_IO_ERROR, &tty->flags);
147077451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_INITIALIZED;
14719fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
147202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
14740e7f4194a0ef70c1d0d40152fa480a63719f35d5Jiri Slaby		int channel = info->line - card->first_line;
1475217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
1476f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			"base_addr %p\n", card, channel, card->base_addr);
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14792693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
148002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return;
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14829fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148477451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.xmit_buf) {
148502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			unsigned char *temp;
148677451e53e0a509a98eda272567869cfe96431ba9Alan Cox			temp = info->port.xmit_buf;
148777451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.xmit_buf = NULL;
148802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			free_page((unsigned long)temp);
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
149002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
14914d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (tty->termios->c_cflag & HUPCL)
14924d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			tty_port_lower_dtr_rts(&info->port);
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1494d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		set_bit(TTY_IO_ERROR, &tty->flags);
149577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_INITIALIZED;
149602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
14979fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
149802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1501217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc shutdown done\n");
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
150302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* shutdown */
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_open() and friends
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called whenever a serial port is opened.  It
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * performs the serial-specific initialization for the tty structure.
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
151502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_open(struct tty_struct *tty, struct file *filp)
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
151702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
151865f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int i, line;
151965f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int retval;
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	line = tty->index;
152215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (tty->index < 0 || NR_PORTS <= line)
152302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
152415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
1525dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	for (i = 0; i < NR_CARDS; i++)
1526dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		if (line < cy_card[i].first_line + cy_card[i].nports &&
1527dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby				line >= cy_card[i].first_line)
1528dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			break;
1529dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	if (i >= NR_CARDS)
1530dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		return -ENODEV;
1531dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	info = &cy_card[i].ports[line - cy_card[i].first_line];
153215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->line < 0)
153302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* If the card's firmware hasn't been loaded,
153602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   treat it as absent from the system.  This
153702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   will make the user pay attention.
153802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
15392693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(info->card)) {
1540875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		struct cyclades_card *cinfo = info->card;
154102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
154202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
15432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(cinfo)) {
15442693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
1545101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby					readl(&firm_id->signature) ==
1546101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby					ZFIRM_HLT) {
1547217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1548217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"need an external power supply for "
1549217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"this number of ports.\nFirmware "
1550217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"halted.\n");
155102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			} else {
1552217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1553217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"yet loaded\n");
155402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
155502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
155602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
155702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CONFIG_CYZ_INTR
155802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else {
155902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* In case this Z board is operating in interrupt mode, its
156002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   interrupts should be enabled as soon as the first open
156102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   happens to one of its ports. */
156202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!cinfo->intr_enabled) {
156397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				u16 intr;
156402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
156502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* Enable interrupts on the PLX chip */
156697e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				intr = readw(&cinfo->ctl_addr.p9060->
156797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby						intr_ctrl_stat) | 0x0900;
156897e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				cy_writew(&cinfo->ctl_addr.p9060->
156997e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby						intr_ctrl_stat, intr);
157002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* Enable interrupts on the FW */
157102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				retval = cyz_issue_cmd(cinfo, 0,
157202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						C_CM_IRQ_ENBL, 0L);
157302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (retval != 0) {
1574217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					printk(KERN_ERR "cyc:IRQ enable retval "
1575217191910c0286e0b3c7e3011630273695253da3Jiri Slaby						"was %x\n", retval);
157602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
157702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cinfo->intr_enabled = 1;
157802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
158002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
158102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Make sure this Z port really exists in hardware */
158202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->line > (cinfo->first_line + cinfo->nports - 1))
158302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
1586217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
158802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	tty->driver_data = info;
158915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_open"))
159002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
159115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1593217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
159477451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.count);
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
159677451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.count++;
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_COUNT
1598217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
159977451e53e0a509a98eda272567869cfe96431ba9Alan Cox		current->pid, info->port.count);
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
160202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
160302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * If the port is the middle of closing, bail out now
160402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
160577451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1606be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann		wait_event_interruptible_tty(info->port.close_wait,
160777451e53e0a509a98eda272567869cfe96431ba9Alan Cox				!(info->port.flags & ASYNC_CLOSING));
160877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
160902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
161202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Start up serial port
161302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
1614d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	retval = cy_startup(info, tty);
161515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (retval)
161602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return retval;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1618f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	retval = tty_port_block_til_ready(&info->port, tty, filp);
161902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (retval) {
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1621217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1622217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			"with %d\n", retval);
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
162402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return retval;
162502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
162702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->throttle = 0;
1628d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_port_tty_set(&info->port, tty);
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
163002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CY_DEBUG_OPEN
1631217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open done\n");
163202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif
163302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
163402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_open */
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_wait_until_sent() --- wait until the transmitter is empty
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
163902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_wait_until_sent(struct tty_struct *tty, int timeout)
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1641875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
1642cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
164302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long orig_jiffies;
164402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int char_time;
164502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
164602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
164702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
164802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
164902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_fifo_size == 0)
165002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;		/* Just in case.... */
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
165202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	orig_jiffies = jiffies;
165302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
165402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Set the check interval to be 1/5 of the estimated time to
165502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * send a single character, and make it at least 1.  The check
165602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * interval should also be less than the timeout.
165702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 *
165802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Note: we have to use pretty tight timings here to satisfy
165902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * the NIST-PCTS.
166002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
166102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
166202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char_time = char_time / 5;
166302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_time <= 0)
166402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_time = 1;
166502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (timeout < 0)
166602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		timeout = 0;
166702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (timeout)
166802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_time = min(char_time, timeout);
166902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
167002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * If the transmitter hasn't cleared in twice the approximate
167102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * amount of time to send the entire FIFO, it probably won't
167202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * ever clear.  This assumes the UART isn't doing flow
167302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * control, which is currently the case.  Hence, if it ever
167402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * takes longer than info->timeout, this is probably due to a
167502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * UART bug of some kind.  So, we clamp the timeout parameter at
167602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * 2*info->timeout.
167702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
167802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!timeout || timeout > 2 * info->timeout)
167902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		timeout = 2 * info->timeout;
16808bab534b508230f33be5f7ba8492923754274a8dJiri Slaby
168102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
16822693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
16833aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		while (cyy_readb(info, CySRER) & CyTxRdy) {
168402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (msleep_interruptible(jiffies_to_msecs(char_time)))
168502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
168602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (timeout && time_after(jiffies, orig_jiffies +
168702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					timeout))
168802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
168902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
169102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Run one more char cycle */
169202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	msleep_interruptible(jiffies_to_msecs(char_time * 5));
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1695978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Coxstatic void cy_flush_buffer(struct tty_struct *tty)
1696978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox{
1697978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct cyclades_port *info = tty->driver_data;
1698978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct cyclades_card *card;
1699978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	int channel, retval;
1700978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	unsigned long flags;
1701978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1702978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox#ifdef CY_DEBUG_IO
1703978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1704978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox#endif
1705978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1706978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1707978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		return;
1708978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1709978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	card = info->card;
1710978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	channel = info->line - card->first_line;
1711978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1712978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_lock_irqsave(&card->card_lock, flags);
1713978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1714978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_unlock_irqrestore(&card->card_lock, flags);
1715978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
17162693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1717978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox					   buffers as well */
1718978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		spin_lock_irqsave(&card->card_lock, flags);
1719978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1720978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		if (retval != 0) {
1721978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox			printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1722978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox				"was %x\n", info->line, retval);
1723978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		}
1724978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		spin_unlock_irqrestore(&card->card_lock, flags);
1725978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	}
1726978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	tty_wakeup(tty);
1727978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox}				/* cy_flush_buffer */
1728978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1729978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1730e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Coxstatic void cy_do_close(struct tty_port *port)
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1732e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	struct cyclades_port *info = container_of(port, struct cyclades_port,
1733e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox								port);
17349fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	struct cyclades_card *card;
173502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
17363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17389fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	card = info->card;
17393aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	channel = info->line - card->first_line;
17409fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
174102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
17422693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
174302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Stop accepting input */
17443aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
17453aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
174677451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.flags & ASYNC_INITIALIZED) {
174715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			/* Waiting for on-board buffers to be empty before
174815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			   closing the port */
17499fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
1750e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox			cy_wait_until_sent(port->tty, info->timeout);
17519fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
175202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
175302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
175402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef Z_WAKE
175515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		/* Waiting for on-board buffers to be empty before closing
175615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		   the port */
1757f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
175802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
175902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1760f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
17619fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
176202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
1763217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_DEBUG "cyc:cy_close retval on "
1764217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"ttyC%d was %x\n", info->line, retval);
176502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
17669fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
17672c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby			wait_for_completion_interruptible(&info->shutdown_wait);
17689fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
176902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
177102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
17729fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
1773e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	cy_shutdown(info, port->tty);
1774e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox}
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1776e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox/*
1777e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox * This routine is called when a particular tty device is closed.
1778e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox */
1779e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Coxstatic void cy_close(struct tty_struct *tty, struct file *filp)
1780e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox{
1781e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	struct cyclades_port *info = tty->driver_data;
1782e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1783e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox		return;
1784e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	tty_port_close(&info->port, tty, filp);
178502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_close */
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine gets called when tty_write has put something into
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the write_queue.  The characters may come from user space or
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kernel space.
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will return the number of characters actually
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accepted for writing.
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is not already transmitting stuff, start it off by
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabling interrupts.  The interrupt service routine will then
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that the characters are sent.
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is already active, there is no need to kick it.
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
180002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1802cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
180302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
180402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int c, ret = 0;
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1807217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_write"))
181102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181377451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!info->port.xmit_buf)
181402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18169fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
181702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	while (1) {
18181a4e2351e7fcf2d10bb5524b0ace7797ffad4d98Harvey Harrison		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
18191a4e2351e7fcf2d10bb5524b0ace7797ffad4d98Harvey Harrison		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
182002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
182102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (c <= 0)
182202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
182302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
182477451e53e0a509a98eda272567869cfe96431ba9Alan Cox		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
182502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->xmit_head = (info->xmit_head + c) &
182602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(SERIAL_XMIT_SIZE - 1);
182702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->xmit_cnt += c;
182802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		buf += c;
182902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		count -= c;
183002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret += c;
183102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
18329fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
183302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
183402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->idle_stats.xmit_bytes += ret;
183502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->idle_stats.xmit_idle = jiffies;
183602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
183715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
183802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		start_xmit(info);
183915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
184002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret;
184102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_write */
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the kernel to write a single
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * character to the tty device.  If the kernel uses this routine,
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it must call the flush_chars() routine (if defined) when it is
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * done stuffing characters into the driver.  If there is no room
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the queue, the character is ignored.
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
185076b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Coxstatic int cy_put_char(struct tty_struct *tty, unsigned char ch)
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1852cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
185302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1856217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
186076b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
186277451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!info->port.xmit_buf)
186376b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18659fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
186690cc301859ea8840634324a7f5b9680312377667Jiri Slaby	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
18679fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&info->card->card_lock, flags);
186876b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
186902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
187177451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.xmit_buf[info->xmit_head++] = ch;
187202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
187302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->xmit_cnt++;
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->idle_stats.xmit_bytes++;
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->idle_stats.xmit_idle = jiffies;
18769fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
187776b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox	return 1;
187802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_put_char */
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the kernel after it has written a
188215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * series of characters to the tty device using put_char().
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
188402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_flush_chars(struct tty_struct *tty)
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1886cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
188702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1889217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
189302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
189677451e53e0a509a98eda272567869cfe96431ba9Alan Cox			!info->port.xmit_buf)
189702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	start_xmit(info);
190002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_flush_chars */
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine returns the numbers of characters the tty driver
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will accept for queuing to be written.  This number is subject
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to change as output buffers get emptied, or if the output flow
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control is activated.
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
190802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_write_room(struct tty_struct *tty)
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1910cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
191102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int ret;
191202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1914217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_write_room"))
191802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
191902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
192002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (ret < 0)
192102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret = 0;
192202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret;
192302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_write_room */
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_chars_in_buffer(struct tty_struct *tty)
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1927cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
193002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
193102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_EXT_CHARS_IN_BUFFER
1933f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	if (!cy_is_Z(info->card)) {
193402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_EXT_CHARS_IN_BUFFER */
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1936217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1937217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			info->line, info->xmit_cnt);
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
193902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return info->xmit_cnt;
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_EXT_CHARS_IN_BUFFER
194102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
1942f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
194302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int char_count;
1944ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby		__u32 tx_put, tx_get, tx_bufsize;
194502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1946db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_get = readl(&buf_ctrl->tx_get);
1947db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_put = readl(&buf_ctrl->tx_put);
1948db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
194902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (tx_put >= tx_get)
195002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count = tx_put - tx_get;
195102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
195202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count = tx_put - tx_get + tx_bufsize;
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1954217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1955217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			info->line, info->xmit_cnt + char_count);
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1957096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return info->xmit_cnt + char_count;
195802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
195902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_EXT_CHARS_IN_BUFFER */
196002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_chars_in_buffer */
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_ioctl() and friends
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19681a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielkastatic void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
197002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int co, co_val, bpr;
19711a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
197202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			25000000);
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (baud == 0) {
197502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->tbpr = info->tco = info->rbpr = info->rco = 0;
197602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
197702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* determine which prescaler to use */
198002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
198102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_clock / co_val / baud > 63)
198202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
198302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
198602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (bpr > 255)
198702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		bpr = 255;
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->tbpr = info->rbpr = bpr;
199002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->tco = info->rco = co;
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine finds or computes the various line characteristics.
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It used to be called config_setup
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1997d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1999875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
200002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
20013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
200202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned cflag, iflag;
200302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int baud, baud_rate = 0;
200402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int i;
200502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2006d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (!tty->termios) /* XXX can this happen at all? */
200702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
200815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
200915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->line == -1)
201002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
201115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
2012d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cflag = tty->termios->c_cflag;
2013d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	iflag = tty->termios->c_iflag;
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
201602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Set up the tty->alt_speed kludge
201702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
2018d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2019d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 57600;
2020d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2021d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 115200;
2022d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2023d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 230400;
2024d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2025d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 460800;
202602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
202702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
2028875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
202902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
20302693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
203146fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		u32 cflags;
203246fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby
203302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* baud rate */
2034d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		baud = tty_get_baud_rate(tty);
203577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
203602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
203702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->custom_divisor)
203802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud / info->custom_divisor;
203902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
204002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud;
204102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud > CD1400_MAX_SPEED) {
204202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			baud = CD1400_MAX_SPEED;
204302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
204402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* find the baud index */
204502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (i = 0; i < 20; i++) {
204615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (baud == baud_table[i])
204702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
204802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
204915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (i == 20)
205002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			i = 19;	/* CD1400_MAX_SPEED */
205102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
205277451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
205302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
205402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cyy_baud_calc(info, baud_rate);
205502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
205602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->chip_rev >= CD1400_REV_J) {
205702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* It is a CD1400 rev. J or later */
205802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tbpr = baud_bpr_60[i];	/* Tx BPR */
205902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tco = baud_co_60[i];	/* Tx CO */
206002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rbpr = baud_bpr_60[i];	/* Rx BPR */
206102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rco = baud_co_60[i];	/* Rx CO */
206202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			} else {
206302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tbpr = baud_bpr_25[i];	/* Tx BPR */
206402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tco = baud_co_25[i];	/* Tx CO */
206502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rbpr = baud_bpr_25[i];	/* Rx BPR */
206602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rco = baud_co_25[i];	/* Rx CO */
206702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
206802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
206902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud_table[i] == 134) {
207002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* get it right for 134.5 baud */
207102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
207202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					2;
207377451e53e0a509a98eda272567869cfe96431ba9Alan Cox		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
207402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
207502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
207602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_rate) + 2;
207702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud_table[i]) {
207802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
207902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_table[i]) + 2;
208002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* this needs to be propagated into the card info */
208102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
208202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = 0;
208302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
208402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* By tradition (is it a standard?) a baud rate of zero
208502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   implies the line should be/has been closed.  A bit
208602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   later in this routine such a test is performed. */
208702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
208802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* byte size and parity */
208902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor5 = 0;
209002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor4 = 0;
209102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* receive threshold */
209202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 = (info->default_threshold ?
209302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->default_threshold : baud_cor3[i]);
209402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor2 = CyETC;
209502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cflag & CSIZE) {
209602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS5:
209702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_5_BITS;
209802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
209902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS6:
210002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_6_BITS;
210102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
210202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS7:
210302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_7_BITS;
210402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
210502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS8:
210602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_8_BITS;
210702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
210802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
210915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (cflag & CSTOPB)
211002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 |= Cy_2_STOP;
211115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
211202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & PARENB) {
211315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (cflag & PARODD)
211402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->cor1 |= CyPARITY_O;
211515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			else
211602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->cor1 |= CyPARITY_E;
211715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		} else
211802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 |= CyPARITY_NONE;
211902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
212002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CTS flow control flag */
212102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CRTSCTS) {
212277451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CTS_FLOW;
212302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor2 |= CyCtsAE;
212402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
212577451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CTS_FLOW;
212602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor2 &= ~CyCtsAE;
212702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
212802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CLOCAL)
212977451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CHECK_CD;
213002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
213177451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CHECK_CD;
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 /***********************************************
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    The hardware option, CyRtsAO, presents RTS when
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    the chip has characters to send.  Since most modems
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    use RTS as reverse (inbound) flow control, this
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    option is not used.  If inbound flow control is
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    necessary, DTR can be programmed to provide the
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    appropriate signals for use with a non-standard
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cable.  Contact Marcio Saito for details.
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 ***********************************************/
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
214302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		channel &= 0x03;
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21459fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
21463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
214702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
214802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* tx and rx baud rate */
214902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21503aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTCOR, info->tco);
21513aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTBPR, info->tbpr);
21523aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRCOR, info->rco);
21533aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRBPR, info->rbpr);
215402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
215502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set line characteristics  according configuration */
215602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySCHR1, START_CHAR(tty));
21583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
21593aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR1, info->cor1);
21603aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR2, info->cor2);
21613aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR3, info->cor3);
21623aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR4, info->cor4);
21633aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR5, info->cor5);
216402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
21663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				CyCOR3ch);
216702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
216815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		/* !!! Is this needed? */
21693aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
21703aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR,
217102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(info->default_timeout ? info->default_timeout : 0x02));
217202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* 10ms rx timeout */
217302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
217446fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cflags = CyCTS;
217546fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		if (!C_CLOCAL(tty))
217646fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cflags |= CyDSR | CyRI | CyDCD;
217746fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* without modem intr */
217846fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
217946fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* act on 1->0 modem transitions */
218046fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		if ((cflag & CRTSCTS) && info->rflow)
218146fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
218246fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		else
218346fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cyy_writeb(info, CyMCOR1, cflags);
218446fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* act on 0->1 modem transitions */
218546fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cyy_writeb(info, CyMCOR2, cflags);
218602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21874d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (i == 0)	/* baud rate is zero, turn off line */
21884d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_DTR);
21894d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		else
21904d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, TIOCM_DTR, 0);
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2192d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		clear_bit(TTY_IO_ERROR, &tty->flags);
21939fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2196f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
21971a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka		__u32 sw_flow;
219802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22002693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
220102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return;
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
220302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* baud rate */
2204d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		baud = tty_get_baud_rate(tty);
220577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
220602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
220702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->custom_divisor)
220802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud / info->custom_divisor;
220902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
221002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud;
221102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud > CYZ_MAX_SPEED) {
221202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			baud = CYZ_MAX_SPEED;
221302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
221402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&ch_ctrl->comm_baud, baud);
221502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
221602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud == 134) {
221702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* get it right for 134.5 baud */
221802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
221902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					2;
222077451e53e0a509a98eda272567869cfe96431ba9Alan Cox		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
222102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
222202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
222302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_rate) + 2;
222402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud) {
222502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
222602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud) + 2;
222702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* this needs to be propagated into the card info */
222802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
222902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = 0;
223002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* byte size and parity */
223302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cflag & CSIZE) {
223402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS5:
223502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
223602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
223702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS6:
223802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
223902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
224002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS7:
224102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
224202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
224302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS8:
224402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
224502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
224602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
224702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CSTOPB) {
224802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l,
2249db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
225002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
225102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l,
2252db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
225302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
225402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & PARENB) {
225515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (cflag & PARODD)
225602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
225715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			else
225802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
225915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		} else
226002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
226202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CTS flow control flag */
226302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CRTSCTS) {
226402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->hw_flow,
2265db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
226602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
2267db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2268db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby					~(C_RS_CTS | C_RS_RTS));
226902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
227002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* As the HW flow control is done in firmware, the driver
227102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   doesn't need to care about it */
227277451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_CTS_FLOW;
227302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
227402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* XON/XOFF/XANY flow control flags */
227502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		sw_flow = 0;
227602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (iflag & IXON) {
227702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			sw_flow |= C_FL_OXX;
227802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (iflag & IXANY)
227902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				sw_flow |= C_FL_OIXANY;
228002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
228102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&ch_ctrl->sw_flow, sw_flow);
228202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2283875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
228402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2285217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2286217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
228702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
228802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
228902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CD sensitivity */
229015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (cflag & CLOCAL)
229177451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CHECK_CD;
229215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		else
229377451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CHECK_CD;
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud == 0) {	/* baud rate is zero, turn off line */
229602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->rs_control,
2297db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
2299217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
230102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
230202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->rs_control,
2303db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
2305217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
230702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
230915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
231002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2311217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2312217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
231302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2315d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		clear_bit(TTY_IO_ERROR, &tty->flags);
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
231702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_line_char */
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23196c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slabystatic int cy_get_serial_info(struct cyclades_port *info,
232015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		struct serial_struct __user *retinfo)
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2322875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
23236c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct serial_struct tmp = {
23246c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.type = info->type,
23256c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.line = info->line,
23266c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.port = (info->card - cy_card) * 0x100 + info->line -
23276c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			cinfo->first_line,
23286c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.irq = cinfo->irq,
23296c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.flags = info->port.flags,
23306c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.close_delay = info->port.close_delay,
23316c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.closing_wait = info->port.closing_wait,
23326c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.baud_base = info->baud,
23336c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.custom_divisor = info->custom_divisor,
23346c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.hub6 = 0,		/*!!! */
23356c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	};
233602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
23376c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby}
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2340d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabycy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
234115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		struct serial_struct __user *new_info)
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
234302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct serial_struct new_serial;
234425c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	int ret;
234502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
234602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
234702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -EFAULT;
234802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
234925c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	mutex_lock(&info->port.mutex);
235002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!capable(CAP_SYS_ADMIN)) {
235144b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		if (new_serial.close_delay != info->port.close_delay ||
235202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				new_serial.baud_base != info->baud ||
235302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(new_serial.flags & ASYNC_FLAGS &
235402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					~ASYNC_USR_MASK) !=
235577451e53e0a509a98eda272567869cfe96431ba9Alan Cox				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
235625c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		{
235725c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox			mutex_unlock(&info->port.mutex);
235802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -EPERM;
235925c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		}
236077451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
236102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(new_serial.flags & ASYNC_USR_MASK);
236202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->baud = new_serial.baud_base;
236302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->custom_divisor = new_serial.custom_divisor;
236402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto check_and_exit;
236502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
236602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
236702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
236802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * OK, past this point, all the error checking has been done.
236902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * At this point, we start making changes.....
237002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
237102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
237202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->baud = new_serial.baud_base;
237302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->custom_divisor = new_serial.custom_divisor;
237477451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
237502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(new_serial.flags & ASYNC_FLAGS);
237644b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	info->port.close_delay = new_serial.close_delay * HZ / 100;
237744b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_and_exit:
238077451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (info->port.flags & ASYNC_INITIALIZED) {
2381d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		cy_set_line_char(info, tty);
238225c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		ret = 0;
238302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
238425c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		ret = cy_startup(info, tty);
238502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
238625c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	mutex_unlock(&info->port.mutex);
238725c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	return ret;
238802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_serial_info */
23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_lsr_info - get line status register info
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Purpose: Let user call ioctl() to get info when the UART physically
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    is emptied.  On bus types like RS485, the transmitter must
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    release the bus after transmitting. This must be done when
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    the transmit shift register is empty, not be done when the
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    transmit holding register is empty.  This functionality
23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    allows an RS485 driver to be written in user space.
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
240015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24023aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
240302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned int result;
240402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
24053aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	u8 status;
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24072693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24089fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24093aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
24109fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
241102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		result = (status ? 0 : TIOCSER_TEMT);
241202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
241302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Not supported yet */
241402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -EINVAL;
241502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
241602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return put_user(result, (unsigned long __user *)value);
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int cy_tiocmget(struct tty_struct *tty)
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2421cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2422875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
24233aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int result;
242402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2425bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison	if (serial_paranoia_check(info, tty->name, __func__))
242602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
24290d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24302693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24310d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		unsigned long flags;
24323aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		int channel = info->line - card->first_line;
24333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 status;
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24359fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24363aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
24373aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status = cyy_readb(info, CyMSVR1);
24383aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status |= cyy_readb(info, CyMSVR2);
24399fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
244002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
244102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->rtsdtr_inv) {
244202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			result = ((status & CyRTS) ? TIOCM_DTR : 0) |
244302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				((status & CyDTR) ? TIOCM_RTS : 0);
244402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
244502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			result = ((status & CyRTS) ? TIOCM_RTS : 0) |
244602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				((status & CyDTR) ? TIOCM_DTR : 0);
244702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
244802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
244902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyRI) ? TIOCM_RNG : 0) |
245002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyDSR) ? TIOCM_DSR : 0) |
245102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyCTS) ? TIOCM_CTS : 0);
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
24530d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		u32 lstatus;
24540d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24550d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (!cyz_is_loaded(card)) {
24560d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			result = -ENODEV;
24570d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			goto end;
245802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24600d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
24610d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
24620d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
24630d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
24640d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
24650d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
24660d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
246702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
24680d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slabyend:
246902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return result;
247002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_tiomget */
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
247320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxcy_tiocmset(struct tty_struct *tty,
247402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		unsigned int set, unsigned int clear)
24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2476cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2477875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
247802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
247902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2480bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison	if (serial_paranoia_check(info, tty->name, __func__))
248102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
248202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
248302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
24842693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24854d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24864d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		cyy_change_rts_dtr(info, set, clear);
24874d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
248802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
24890d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
24900d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		int retval, channel = info->line - card->first_line;
24910d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		u32 rs;
24920d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24930d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (!cyz_is_loaded(card))
24940d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			return -ENODEV;
24950d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24960d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24970d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rs = readl(&ch_ctrl->rs_control);
24980d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (set & TIOCM_RTS)
24990d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs |= C_RS_RTS;
25000d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (clear & TIOCM_RTS)
25010d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs &= ~C_RS_RTS;
25020d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (set & TIOCM_DTR) {
25030d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs |= C_RS_DTR;
25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
25050d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
25070d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		}
25080d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (clear & TIOCM_DTR) {
25090d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs &= ~C_RS_DTR;
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
25110d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			printk(KERN_DEBUG "cyc:set_modem_info clearing "
25120d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby				"Z DTR\n");
25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
251402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
25150d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		cy_writel(&ch_ctrl->rs_control, rs);
25169fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
25170d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
251802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2519217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2520217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
252102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
252302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
25240d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby}
25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_break() --- routine which turns the break handling on or off
25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
25299e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int cy_break(struct tty_struct *tty, int break_state)
25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2531cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
25329fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	struct cyclades_card *card;
253302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
25349e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	int retval = 0;
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_break"))
25379e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox		return -EINVAL;
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25399fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	card = info->card;
25409fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby
25419fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
25422693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
254302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Let the transmit ISR take care of this (since it
254402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   requires stuffing characters into the output stream).
254502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
254602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (break_state == -1) {
254702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->breakon) {
254802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->breakon = 1;
254902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (!info->xmit_cnt) {
25509fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_unlock_irqrestore(&card->card_lock, flags);
255102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					start_xmit(info);
25529fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_lock_irqsave(&card->card_lock, flags);
255302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
255402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
255502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
255602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->breakoff) {
255702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->breakoff = 1;
255802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (!info->xmit_cnt) {
25599fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_unlock_irqrestore(&card->card_lock, flags);
256002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					start_xmit(info);
25619fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_lock_irqsave(&card->card_lock, flags);
256202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
256302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
256602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (break_state == -1) {
25679fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card,
25689fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby				info->line - card->first_line,
256902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				C_CM_SET_BREAK, 0L);
257002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
2571217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:cy_break (set) retval on "
2572217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"ttyC%d was %x\n", info->line, retval);
257302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
257402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
25759fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card,
25769fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby				info->line - card->first_line,
257702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				C_CM_CLR_BREAK, 0L);
257802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
2579217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2580217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"on ttyC%d was %x\n", info->line,
2581217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					retval);
258202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25859fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
25869e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	return retval;
258702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_break */
25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
258902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int set_threshold(struct cyclades_port *info, unsigned long value)
25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25913aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
259202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25942693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
259502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 &= ~CyREC_FIFO;
259602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 |= value & CyREC_FIFO;
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25989fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
25993aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR3, info->cor3);
26003aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
26019fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
260202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
260302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
260402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_threshold */
26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_threshold(struct cyclades_port *info,
260715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox						unsigned long __user *value)
26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26093aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26112693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26123aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
261302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return put_user(tmp, value);
261402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2615f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	return 0;
261602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* get_threshold */
26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int set_timeout(struct cyclades_port *info, unsigned long value)
26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26203aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
262102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26232693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26249fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
26253aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR, value & 0xff);
26269fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
262702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
262802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
262902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_timeout */
26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
263115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_timeout(struct cyclades_port *info,
263215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox						unsigned long __user *value)
26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26343aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26362693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26373aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 tmp = cyy_readb(info, CyRTPR);
263802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return put_user(tmp, value);
263902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2640f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	return 0;
264102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* get_timeout */
26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26436c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slabystatic int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
26446c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		struct cyclades_icount *cprev)
26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26466c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct cyclades_icount cnow;
26476c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	unsigned long flags;
26486c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	int ret;
26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26506c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
26516c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	cnow = info->icount;	/* atomic copy */
26526c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
26536c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26546c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
26556c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
26566c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
26576c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
26586c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26596c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	*cprev = cnow;
26606c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26616c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	return ret;
26626c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby}
26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine allows the tty driver to implement device-
26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific ioctl's.  If the ioctl number passed in cmd is
26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not recognized by the driver, it should return ENOIOCTLCMD.
26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
26706caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxcy_ioctl(struct tty_struct *tty,
267102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 unsigned int cmd, unsigned long arg)
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2673cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
26746c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct cyclades_icount cnow;	/* kernel counter temps */
267502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int ret_val = 0;
267602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
267702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __user *argp = (void __user *)arg;
267802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
267902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
268002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2683217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2684217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		info->line, cmd, arg);
26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	switch (cmd) {
268802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETMON:
26896c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
26906c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			ret_val = -EFAULT;
26916c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			break;
26926c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		}
26936c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		memset(&info->mon, 0, sizeof(info->mon));
269402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
269502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETTHRESH:
269602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_threshold(info, argp);
269702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
269802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETTHRESH:
269902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = set_threshold(info, arg);
270002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETDEFTHRESH:
27026c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = put_user(info->default_threshold,
27036c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				(unsigned long __user *)argp);
270402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETDEFTHRESH:
27066c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		info->default_threshold = arg & 0x0f;
270702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETTIMEOUT:
270902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_timeout(info, argp);
271002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETTIMEOUT:
271202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = set_timeout(info, arg);
271302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETDEFTIMEOUT:
27156c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = put_user(info->default_timeout,
27166c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				(unsigned long __user *)argp);
271702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETDEFTIMEOUT:
27196c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		info->default_timeout = arg & 0xff;
272002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETRFLOW:
272202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->rflow = (int)arg;
272302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETRFLOW:
272502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->rflow;
272602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETRTSDTR_INV:
272802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->rtsdtr_inv = (int)arg;
272902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETRTSDTR_INV:
273102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->rtsdtr_inv;
273202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETCD1400VER:
273402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->chip_rev;
273502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYZSETPOLLCYCLE:
273802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cyz_polling_cycle = (arg * HZ) / 1000;
273902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYZGETPOLLCYCLE:
274102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = (cyz_polling_cycle * 1000) / HZ;
274202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
274302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETWAIT:
274544b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.closing_wait = (unsigned short)arg * HZ / 100;
274602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETWAIT:
274844b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		ret_val = info->port.closing_wait / (HZ / 100);
274902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCGSERIAL:
27516c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = cy_get_serial_info(info, argp);
275202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCSSERIAL:
2754d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		ret_val = cy_set_serial_info(info, tty, argp);
275502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCSERGETLSR:	/* Get line status register */
275702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_lsr_info(info, argp);
275802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
276002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
276102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * - mask passed in arg for lines of interest
276202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
276302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Caller should use TIOCGICOUNT to see which one it was
276402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCMIWAIT:
27669fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&info->card->card_lock, flags);
276702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* note the counters on entry */
27682c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		cnow = info->icount;
27699fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&info->card->card_lock, flags);
2770bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
27716c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				cy_cflags_changed(info, arg, &cnow));
27722c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		break;
27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
277402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
277502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
277602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Return: write counters to the user passed counter struct
277702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * NB: both 1->0 and 0->1 transitions are counted except for
277802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 *     RI where only 0->1 is counted.
277902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
278002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	default:
278102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = -ENOIOCTLCMD;
278202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2785217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
278702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret_val;
278802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_ioctl */
27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27900587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int cy_get_icount(struct tty_struct *tty,
27910587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox				struct serial_icounter_struct *sic)
27920587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox{
27930587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	struct cyclades_port *info = tty->driver_data;
27940587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	struct cyclades_icount cnow;	/* Used to snapshot */
27950587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	unsigned long flags;
27960587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
27970587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	spin_lock_irqsave(&info->card->card_lock, flags);
27980587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	cnow = info->icount;
27990587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	spin_unlock_irqrestore(&info->card->card_lock, flags);
28000587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
28010587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->cts = cnow.cts;
28020587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->dsr = cnow.dsr;
28030587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->rng = cnow.rng;
28040587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->dcd = cnow.dcd;
28050587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->rx = cnow.rx;
28060587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->tx = cnow.tx;
28070587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->frame = cnow.frame;
28080587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->overrun = cnow.overrun;
28090587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->parity = cnow.parity;
28100587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->brk = cnow.brk;
28110587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->buf_overrun = cnow.buf_overrun;
28120587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	return 0;
28130587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox}
28140587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine allows the tty driver to be notified when
28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's termios settings have changed.  Note that a
28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well-designed tty driver should be prepared to accept the case
28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where old == NULL, and try to do something rational.
28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
282102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2823cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2826217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2829d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_set_line_char(info, tty);
283002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
283102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if ((old_termios->c_cflag & CRTSCTS) &&
283202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			!(tty->termios->c_cflag & CRTSCTS)) {
283302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		tty->hw_stopped = 0;
283402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_start(tty);
283502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
283702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
283802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * No need to wake up processes in open wait, since they
283902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * sample the CLOCAL flag once, and don't recheck it.
284002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * XXX  It's not clear whether the current behavior is correct
284102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * or not.  Hence, this may change.....
284202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
284302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!(old_termios->c_cflag & CLOCAL) &&
284402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	    (tty->termios->c_cflag & CLOCAL))
284577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		wake_up_interruptible(&info->port.open_wait);
28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
284702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_set_termios */
28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This function is used to send a high-priority XON/XOFF character to
28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the device.
28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
285202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_send_xchar(struct tty_struct *tty, char ch)
28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2854cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2855875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
2856875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	int channel;
28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
286102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->x_char = ch;
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch)
286402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_start(tty);
28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card = info->card;
2867875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28692693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(card)) {
287002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (ch == STOP_CHAR(tty))
2871875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
287202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else if (ch == START_CHAR(tty))
2873875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine is called by the upper-layer tty layer to signal
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   that incoming characters should be throttled because the input
28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   buffers are close to full.
28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
288102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_throttle(struct tty_struct *tty)
28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2883cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2884875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
288502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_THROTTLE
288802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char buf[64];
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2890217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
289102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty->ldisc.chars_in_buffer(tty), info->line);
28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
289502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
289602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
289702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
289802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
289902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (I_IXOFF(tty)) {
29002693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card))
290102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_send_xchar(tty, STOP_CHAR(tty));
290202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
290302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 1;
290402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
290602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tty->termios->c_cflag & CRTSCTS) {
29072693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card)) {
29089fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
29094d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
29109fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
291102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
291202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 1;
291302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
291402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
291502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_throttle */
29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine notifies the tty driver that it should signal
29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that characters can now be sent to the tty without fear of
29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * overrunning the input buffers of the line disciplines.
29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
292202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_unthrottle(struct tty_struct *tty)
29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2924cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2925875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
292602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_THROTTLE
292902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char buf[64];
293002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2931217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
293215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
293515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
293602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
293802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (I_IXOFF(tty)) {
293902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->x_char)
294002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->x_char = 0;
294102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
294202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_send_xchar(tty, START_CHAR(tty));
29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
294502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tty->termios->c_cflag & CRTSCTS) {
294602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		card = info->card;
29472693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card)) {
29489fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
29494d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
29509fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
295102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
295202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 0;
295302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
295402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
295502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_unthrottle */
29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* cy_start and cy_stop provide software output flow control as a
29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   function of XON/XOFF, software CTS, and other such stuff.
29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
296002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_stop(struct tty_struct *tty)
29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
296202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
2963cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
29643aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
296502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2968217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
297102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_stop"))
297202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2974875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	cinfo = info->card;
297502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	channel = info->line - cinfo->first_line;
29762693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo)) {
29779fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&cinfo->card_lock, flags);
29783aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
29793aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
29809fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&cinfo->card_lock, flags);
298102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
298202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_stop */
29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
298402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_start(struct tty_struct *tty)
29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
298602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
2987cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
29883aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
298902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2992217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
299502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_start"))
299602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2998875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	cinfo = info->card;
299902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	channel = info->line - cinfo->first_line;
30002693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo)) {
30019fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&cinfo->card_lock, flags);
30023aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
30033aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
30049fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&cinfo->card_lock, flags);
300502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
300602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_start */
30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
301102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_hangup(struct tty_struct *tty)
30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3013cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
301402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
3016217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
302002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
302202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_flush_buffer(tty);
3023d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_shutdown(info, tty);
3024174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby	tty_port_hangup(&info->port);
302502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_hangup */
30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3027f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic int cyy_carrier_raised(struct tty_port *port)
3028f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3029f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3030f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3031f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3032f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	unsigned long flags;
3033f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	int channel = info->line - cinfo->first_line;
3034f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	u32 cd;
3035f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3036f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_lock_irqsave(&cinfo->card_lock, flags);
30373aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, channel & 0x03);
30383aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cd = cyy_readb(info, CyMSVR1) & CyDCD;
3039f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_unlock_irqrestore(&cinfo->card_lock, flags);
3040f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3041f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	return cd;
3042f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3043f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3044f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic void cyy_dtr_rts(struct tty_port *port, int raise)
3045f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3046f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3047f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3048f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3049f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	unsigned long flags;
3050f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3051f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_lock_irqsave(&cinfo->card_lock, flags);
30524d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
30534d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
3054f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_unlock_irqrestore(&cinfo->card_lock, flags);
3055f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3056f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3057f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic int cyz_carrier_raised(struct tty_port *port)
3058f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3059f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3060f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3061f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3062f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
3063f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3064f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3065f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic void cyz_dtr_rts(struct tty_port *port, int raise)
3066f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3067f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3068f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3069f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3070f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
3071f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	int ret, channel = info->line - cinfo->first_line;
3072f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	u32 rs;
3073f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3074f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	rs = readl(&ch_ctrl->rs_control);
3075f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	if (raise)
3076f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		rs |= C_RS_RTS | C_RS_DTR;
3077f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	else
3078f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		rs &= ~(C_RS_RTS | C_RS_DTR);
3079f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	cy_writel(&ch_ctrl->rs_control, rs);
3080f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3081f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	if (ret != 0)
3082f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3083f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby				__func__, info->line, ret);
3084f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby#ifdef CY_DEBUG_DTR
3085f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3086f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby#endif
3087f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3088f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3089f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic const struct tty_port_operations cyy_port_ops = {
3090f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.carrier_raised = cyy_carrier_raised,
3091f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.dtr_rts = cyy_dtr_rts,
3092e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	.shutdown = cy_do_close,
3093f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby};
3094f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3095f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic const struct tty_port_operations cyz_port_ops = {
3096f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.carrier_raised = cyz_carrier_raised,
3097f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.dtr_rts = cyz_dtr_rts,
3098e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	.shutdown = cy_do_close,
3099f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby};
3100f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_init() and friends
31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_init() is called at boot-time to initialize the serial driver.
31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3109dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slabystatic int __devinit cy_init_card(struct cyclades_card *cinfo)
31100809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby{
31110809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby	struct cyclades_port *info;
3112f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	unsigned int channel, port;
31130809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby
31143046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby	spin_lock_init(&cinfo->card_lock);
3115963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cinfo->intr_enabled = 0;
31163046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
3117963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3118963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby			GFP_KERNEL);
3119dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	if (cinfo->ports == NULL) {
3120dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3121dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		return -ENOMEM;
3122dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	}
3123dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby
3124f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3125f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			channel++, port++) {
3126f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		info = &cinfo->ports[channel];
312744b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		tty_port_init(&info->port);
31283046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		info->magic = CYCLADES_MAGIC;
3129875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		info->card = cinfo;
31303046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		info->line = port;
31313046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
313244b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.closing_wait = CLOSING_WAIT_DELAY;
313344b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.close_delay = 5 * HZ / 10;
313477451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags = STD_COM_FLAGS;
31352c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		init_completion(&info->shutdown_wait);
31363046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31372693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (cy_is_Z(cinfo)) {
3138f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3139f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			struct ZFW_CTRL *zfw_ctrl;
3140f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3141f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			info->port.ops = &cyz_port_ops;
31420809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->type = PORT_STARTECH;
3143f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3144f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			zfw_ctrl = cinfo->base_addr +
3145f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
3146f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3147f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3148f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3149101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby			if (cinfo->hw_ver == ZO_V1)
31500809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->xmit_fifo_size = CYZ_FIFO_SIZE;
31510809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			else
31523046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
31530809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby#ifdef CONFIG_CYZ_INTR
31543991428d9efc7185312196f82cc36e9df4a2ddb0Jiri Slaby			setup_timer(&cyz_rx_full_timer[port],
31553991428d9efc7185312196f82cc36e9df4a2ddb0Jiri Slaby				cyz_rx_restart, (unsigned long)info);
31560809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby#endif
31573046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		} else {
3158f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			unsigned short chip_number;
3159963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby			int index = cinfo->bus_index;
3160f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3161f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			info->port.ops = &cyy_port_ops;
31620809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->type = PORT_CIRRUS;
31630809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
31643046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
31650809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->cor2 = CyETC;
31660809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->cor3 = 0x08;	/* _very_ small rcv threshold */
31673046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
3168f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			chip_number = channel / CyPORTS_PER_CHIP;
31693aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			info->u.cyy.base_addr = cinfo->base_addr +
31703aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				(cy_chip_offset[chip_number] << index);
31713aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			info->chip_rev = cyy_readb(info, CyGFRCR);
317215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
317315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (info->chip_rev >= CD1400_REV_J) {
31740809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				/* It is a CD1400 rev. J or later */
31750809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tbpr = baud_bpr_60[13];	/* Tx BPR */
31760809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tco = baud_co_60[13];	/* Tx CO */
31770809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rbpr = baud_bpr_60[13];	/* Rx BPR */
31780809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rco = baud_co_60[13];	/* Rx CO */
31790809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rtsdtr_inv = 1;
31800809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			} else {
31810809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tbpr = baud_bpr_25[13];	/* Tx BPR */
31820809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tco = baud_co_25[13];	/* Tx CO */
31830809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rbpr = baud_bpr_25[13];	/* Rx BPR */
31840809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rco = baud_co_25[13];	/* Rx CO */
31850809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rtsdtr_inv = 0;
31860809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			}
31873046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby			info->read_status_mask = CyTIMEOUT | CySPECHAR |
31883046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
31890809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby		}
31903046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31910809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby	}
31923046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31933046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#ifndef CONFIG_CYZ_INTR
31942693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
31953046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		mod_timer(&cyz_timerlist, jiffies + 1);
31963046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#ifdef CY_PCI_DEBUG
31973046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
31983046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#endif
31993046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby	}
32003046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#endif
3201dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	return 0;
32020809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby}
32030809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby
32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize chips on Cyclom-Y card -- return number of valid
32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   chips (which is number of ports/4) */
320631b4f0a118a7ade8444059ec898af8f07de206e9Jiri Slabystatic unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
320731b4f0a118a7ade8444059ec898af8f07de206e9Jiri Slaby		int index)
32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
320902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned int chip_number;
321002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *base_addr;
321102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
321202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
321302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_HwReset is 0x1400 */
321402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
321502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
321602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(500L);
321702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
321815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
321915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox							chip_number++) {
322002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		base_addr =
322102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		    true_base_addr + (cy_chip_offset[chip_number] << index);
322202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		mdelay(1);
3223db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyCCR << index)) != 0x00) {
322402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*************
322502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
322602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			chip_number, (unsigned long)base_addr);
322702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			*************/
322802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
322902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
323002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
323102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyGFRCR << index), 0);
323202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(10L);
323302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
323402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* The Cyclom-16Y does not decode address bit 9 and therefore
323502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   cannot distinguish between references to chip 0 and a non-
323602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   existent chip 4.  If the preceding clearing of the supposed
323702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   chip 4 GFRCR register appears at chip 0, there is no chip 4
323802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   and this must be a Cyclom-16Y, not a Cyclom-32Ye.
323902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
3240db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (chip_number == 4 && readb(true_base_addr +
324102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(cy_chip_offset[0] << index) +
324202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(CyGFRCR << index)) == 0) {
324302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
324402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
324502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
324602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
324702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		mdelay(1);
324802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3249db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
325002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*
325102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   printk(" chip #%d at %#6lx is not responding ",
325202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   chip_number, (unsigned long)base_addr);
325302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   printk("(GFRCR stayed 0)\n",
325402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
325502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
325602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
3257db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
325802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				0x40) {
325902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*
326002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			printk(" chip #%d at %#6lx is not valid (GFRCR == "
326102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					"%#2x)\n",
326202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					chip_number, (unsigned long)base_addr,
326302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					base_addr[CyGFRCR<<index]);
326402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
326502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
326602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
326702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
3268db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
326902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* It is a CD1400 rev. J or later */
327002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Impossible to reach 5ms with this chip.
327102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   Changed to 2ms instead (f = 500 Hz). */
327202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
327302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
327402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* f = 200 Hz */
327502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
327602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
327802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
327902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
328002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   chip_number, (unsigned long)base_addr,
3281db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		   readb(base_addr+(CyGFRCR<<index)));
328202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
328302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
328402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return chip_number;
328502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyy_init_card */
32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sets global variables and return the number of ISA boards found.
32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
329302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int __init cy_detect_isa(void)
32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
329602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned short cy_isa_irq, nboard;
329702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *cy_isa_address;
329802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned short i, j, cy_isa_nchan;
329902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int isparam = 0;
33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
330102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	nboard = 0;
33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for module parameters */
330402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_CARDS; i++) {
330502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (maddr[i] || i) {
330602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			isparam = 1;
330702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_addresses[i] = maddr[i];
330802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
330902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (!maddr[i])
331002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* scan the address table probing for Cyclom-Y/ISA boards */
331402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_ISA_ADDRS; i++) {
331502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		unsigned int isa_address = cy_isa_addresses[i];
331615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (isa_address == 0x0000)
3317096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* probe for CD1400... */
3320cd989b3a8c30148c872c7677c7a0415584f1658cAlan Cox		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
33213137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_isa_address == NULL) {
33223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
33233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"address\n");
33243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			continue;
33253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
332602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_isa_nchan = CyPORTS_PER_CHIP *
332702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cyy_init_card(cy_isa_address, 0);
332802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_isa_nchan == 0) {
33293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
333002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
333102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
33322090436357c20afad377a61c789f502c36d637deBartlomiej Zolnierkiewicz
3333196b3167efd13a02cdd34acc1a12316b9f45f41dRoel Kluin		if (isparam && i < NR_CARDS && irq[i])
333402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_irq = irq[i];
33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
333602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* find out the board's irq by probing */
333702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_irq = detect_isa_irq(cy_isa_address);
333802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_isa_irq == 0) {
3339217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3340217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"IRQ could not be detected.\n",
334102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
334302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
334402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
334502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
334602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
3347217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3348217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"more channels are available. Change NR_PORTS "
3349217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"in cyclades.c and recompile kernel.\n",
335002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33513137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3352096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
335302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
335402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* fill the next cy_card structure available */
335502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (j = 0; j < NR_CARDS; j++) {
3356f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby			if (cy_card[j].base_addr == NULL)
335702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
335802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
335902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (j == NR_CARDS) {	/* no more cy_cards available */
3360217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3361217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"more cards can be used. Change NR_CARDS in "
3362217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"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
336802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* allocate IRQ */
336902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (request_irq(cy_isa_irq, cyy_interrupt,
337002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
3371217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3372217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"could not allocate IRQ#%d.\n",
3373217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				(unsigned long)cy_isa_address, cy_isa_irq);
33743137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3375096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
337602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
337702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
337802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set cy_card */
337902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].base_addr = cy_isa_address;
338097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_card[j].ctl_addr.p9050 = NULL;
338102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].irq = (int)cy_isa_irq;
338202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].bus_index = 0;
338302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].first_line = cy_next_channel;
3384963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3385963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[j].nports = cy_isa_nchan;
33863137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_init_card(&cy_card[j])) {
33873137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			cy_card[j].base_addr = NULL;
33883137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			free_irq(cy_isa_irq, &cy_card[j]);
33893137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
33903137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			continue;
33913137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
339202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		nboard++;
339302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3394217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3395217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			"%d channels starting from port %d\n",
339602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			j + 1, (unsigned long)cy_isa_address,
339702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
3398217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			cy_isa_irq, cy_isa_nchan, cy_next_channel);
3399217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
34006ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby		for (j = cy_next_channel;
34016ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby				j < cy_next_channel + cy_isa_nchan; j++)
34026ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby			tty_register_device(cy_serial_driver, j, NULL);
340302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_next_channel += cy_isa_nchan;
340402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
3405096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return nboard;
34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3407096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
340802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
340902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_detect_isa */
34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby#ifdef CONFIG_PCI
3412054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3413054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3414054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int a;
3415054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3416054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (a = 0; a < size && *str; a++, str++)
3417054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (*str & 0x80)
3418054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3419054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3420054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (; a < size; a++, str++)
3421054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (*str)
3422054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3423054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3424054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return 0;
3425054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3426054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3427f61e761e2128c7ca0d044651b18928991ab03be2David Woodhousestatic inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3428054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		unsigned int size)
3429054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3430054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (; size > 0; size--) {
3431054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(fpga, *data++);
3432054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(10);
3433054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3434054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3435054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3436054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic void __devinit plx_init(struct pci_dev *pdev, int irq,
3437054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		struct RUNTIME_9060 __iomem *addr)
34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
343902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Reset PLX */
3440054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
344102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(100L);
3442054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
344302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
344402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Reload Config. Registers from EEPROM */
3445054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
344602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(100L);
3447054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3448054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3449054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3450054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3451054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 * registers. This will remain here until we find a permanent fix.
3452054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 */
3453054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3454054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3455054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3456054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic int __devinit __cyz_load_fw(const struct firmware *fw,
3457054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		const char *name, const u32 mailbox, void __iomem *base,
3458054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		void __iomem *fpga)
3459054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3460f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const void *ptr = fw->data;
3461f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_header *h = ptr;
3462f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_config *c, *cs;
3463f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_block *b, *bs;
3464054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int a, tmp, len = fw->size;
3465054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define BAD_FW KERN_ERR "Bad firmware: "
3466054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (len < sizeof(*h)) {
3467054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3468054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3469054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3470054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3471054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cs = ptr + h->config_offset;
3472054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	bs = ptr + h->block_offset;
3473054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3474054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if ((void *)(cs + h->n_config) > ptr + len ||
3475054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			(void *)(bs + h->n_blocks) > ptr + len) {
3476054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "too short");
3477054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return  -EINVAL;
3478054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3479054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3480054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3481054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			cyc_isfwstr(h->date, sizeof(h->date))) {
3482054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "bad formatted header string\n");
3483054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3484054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3485054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3486054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (strncmp(name, h->name, sizeof(h->name))) {
3487054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3488054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3489054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3490054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3491054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	tmp = 0;
3492054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (c = cs; c < cs + h->n_config; c++) {
3493054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		for (a = 0; a < c->n_blocks; a++)
3494054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (c->block_list[a] > h->n_blocks) {
3495054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				printk(BAD_FW "bad block ref number in cfgs\n");
3496054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				return -EINVAL;
3497054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			}
3498054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3499054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			tmp++;
3500054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3501054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (!tmp) {
3502054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "nothing appropriate\n");
3503054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3504054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3505054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3506054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (b = bs; b < bs + h->n_blocks; b++)
3507054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (b->file_offset + b->size > len) {
3508054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			printk(BAD_FW "bad block data offset\n");
3509054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3510054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3511054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3512054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* everything is OK, let's seek'n'load it */
3513054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (c = cs; c < cs + h->n_config; c++)
3514054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (c->mailbox == mailbox && c->function == 0)
3515054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			break;
3516054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3517054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (a = 0; a < c->n_blocks; a++) {
3518054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		b = &bs[c->block_list[a]];
3519054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (b->type == ZBLOCK_FPGA) {
3520054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (fpga != NULL)
3521054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				cyz_fpga_copy(fpga, ptr + b->file_offset,
3522054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby						b->size);
3523054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		} else {
3524054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (base != NULL)
3525054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				memcpy_toio(base + b->ram_offset,
3526054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					       ptr + b->file_offset, b->size);
3527054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3528054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3529054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#undef BAD_FW
3530054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return 0;
3531054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3532054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3533054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3534054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3535054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3536054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	const struct firmware *fw;
3537054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3538054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct CUSTOM_REG __iomem *cust = base_addr;
3539054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct ZFW_CTRL __iomem *pt_zfwctrl;
3540c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby	void __iomem *tmp;
3541963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	u32 mailbox, status, nchan;
3542054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int i;
3543054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	int retval;
3544054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3545054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3546054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (retval) {
3547054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_err(&pdev->dev, "can't get firmware\n");
3548054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3549054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3550054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3551054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* Check whether the firmware is already loaded and running. If
3552054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   positive, skip this board */
35532693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3554054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		u32 cntval = readl(base_addr + 0x190);
3555054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3556054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(100);
3557054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (cntval != readl(base_addr + 0x190)) {
3558054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			/* FW counter is working, FW is running */
3559054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3560054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"Skipping board.\n");
3561054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = 0;
3562054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
3563054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3564054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3565054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3566054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* start boot */
3567054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3568054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			~0x00030800UL);
3569054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3570054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	mailbox = readl(&ctl_addr->mail_box_0);
3571054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
35722693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3573054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* stops CPU and set window to beginning of RAM */
3574054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3575054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&cust->cpu_stop, 0);
3576054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3577054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(100);
3578054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3579054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3580054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	plx_init(pdev, irq, ctl_addr);
3581054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3582054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (mailbox != 0) {
3583054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* load FPGA */
3584054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3585054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				base_addr);
3586054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (retval)
3587054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
35882693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!__cyz_fpga_loaded(ctl_addr)) {
3589054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "fw upload successful, but fw is "
3590054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"not loaded\n");
3591054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
3592054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3593054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3594054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3595054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* stops CPU and set window to beginning of RAM */
3596054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3597054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&cust->cpu_stop, 0);
3598054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3599054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	udelay(100);
3600054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3601054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* clear memory */
3602c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3603054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writeb(tmp, 255);
3604054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (mailbox != 0) {
3605054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* set window to last 512K of RAM */
3606054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
3607c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3608054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			cy_writeb(tmp, 255);
3609054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* set window to beginning of RAM */
3610054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3611054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3612054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3613054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3614054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	release_firmware(fw);
3615054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (retval)
3616054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3617054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3618054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* finish boot and start boards */
3619054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3620054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&cust->cpu_start, 0);
3621054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3622054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	i = 0;
3623054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3624054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		msleep(100);
3625054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (status != ZFIRM_ID) {
3626054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (status == ZFIRM_HLT) {
3627054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "you need an external power supply "
3628054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"for this number of ports. Firmware halted and "
3629054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"board reset.\n");
3630054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = -EIO;
3631054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err;
3632054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3633054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3634054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"some more time\n", status);
3635054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3636054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				i++ < 200)
3637054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			msleep(100);
3638054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (status != ZFIRM_ID) {
3639054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "Board not started in 20 seconds! "
3640054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"Giving up. (fid->signature = 0x%x)\n",
3641054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					status);
3642054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_info(&pdev->dev, "*** Warning ***: if you are "
3643054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"upgrading the FW, please power cycle the "
3644054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"system before loading the new FW to the "
3645054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"Cyclades-Z.\n");
3646054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
36472693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			if (__cyz_fpga_loaded(ctl_addr))
3648054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				plx_init(pdev, irq, ctl_addr);
3649054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3650054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = -EIO;
3651054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err;
3652054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3653054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3654054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				i / 10);
3655054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3656054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3657054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3658054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3659054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3660054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			base_addr + readl(&fid->zfwctrl_addr));
3661054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3662963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3663054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
3664963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3665054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3666963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	if (nchan == 0) {
3667054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3668054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			"check the connection between the Z host card and the "
3669054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			"serial expanders.\n");
3670054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
36712693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (__cyz_fpga_loaded(ctl_addr))
3672054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			plx_init(pdev, irq, ctl_addr);
3673054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3674054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_info(&pdev->dev, "Null number of ports detected. Board "
3675054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"reset.\n");
3676054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		retval = 0;
3677054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3678054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3679054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3680054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3681054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3682054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3683054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/*
3684054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   Early firmware failed to start looking for commands.
3685054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   This enables firmware interrupts for those commands.
3686054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 */
3687054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3688054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			(1 << 17));
3689054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3690054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			0x00030800UL);
3691054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3692963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	return nchan;
3693054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyerr_rel:
3694054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	release_firmware(fw);
3695054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyerr:
3696054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return retval;
36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
369958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slabystatic int __devinit cy_pci_probe(struct pci_dev *pdev,
370058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		const struct pci_device_id *ent)
37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
37023137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	void __iomem *addr0 = NULL, *addr2 = NULL;
37033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	char *card_name = NULL;
3704101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby	u32 uninitialized_var(mailbox);
37053137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	unsigned int device_id, nchan = 0, card_no, i;
37063137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	unsigned char plx_ver;
37073137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	int retval, irq;
370802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
370958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	retval = pci_enable_device(pdev);
371058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	if (retval) {
371158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		dev_err(&pdev->dev, "cannot enable device\n");
37123137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err;
371358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	}
37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	/* read PCI configuration area */
37163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	irq = pdev->irq;
371758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby#if defined(__alpha__)
37203137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
37213137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
37223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"addresses on Alpha systems.\n");
37233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = -EIO;
37243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37263137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby#endif
37273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
37283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
37293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"addresses\n");
37303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = -EIO;
37313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37333137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
37353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
37363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				"it...\n");
37373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		pdev->resource[2].flags &= ~IORESOURCE_IO;
37383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37403137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = pci_request_regions(pdev, "cyclades");
37413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (retval) {
37423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "failed to reserve resources\n");
37433137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37443137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37463137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = -EIO;
374758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
374858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
37493137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		card_name = "Cyclom-Y";
37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
375124e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
375224e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Yctl);
37533137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr0 == NULL) {
37543137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap ctl region\n");
37553137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_reg;
375658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
375724e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
375824e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Ywin);
37593137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr2 == NULL) {
37603137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap base region\n");
37613137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
376258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37643137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
37653137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (nchan == 0) {
3766217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3767217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"Serial-Modules\n");
3768c847d47cb7b2fa78b17c9e17ed3fbd010ee3d3caAndrew Morton			goto err_unmap;
376958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
377058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
37713137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		struct RUNTIME_9060 __iomem *ctl_addr;
3772217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
377324e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
377424e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Zctl);
37753137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr0 == NULL) {
37763137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap ctl region\n");
37773137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_reg;
37783137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
377958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
378058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		/* Disable interrupts on the PLX before resetting it */
378197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writew(&ctl_addr->intr_ctrl_stat,
378297e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
378358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
3784054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		plx_init(pdev, irq, addr0);
378502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3786101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		mailbox = readl(&ctl_addr->mail_box_0);
378758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
378824e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
378924e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
37903137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr2 == NULL) {
37913137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap base region\n");
37923137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
379358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
379458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
379558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		if (mailbox == ZE_V1) {
37963137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			card_name = "Cyclades-Ze";
379758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		} else {
37983137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			card_name = "Cyclades-8Zo";
37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_PCI_DEBUG
38003137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			if (mailbox == ZO_V1) {
38013137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
38023137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
38033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"id %lx, ver %lx\n", (ulong)(0xff &
38043137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					readl(&((struct CUSTOM_REG *)addr2)->
38053137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby						fpga_id)), (ulong)(0xff &
38063137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					readl(&((struct CUSTOM_REG *)addr2)->
38073137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby						fpga_version)));
38083137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
38093137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			} else {
38103137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
38113137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"Cyclades-Z board.  FPGA not loaded\n");
38123137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			}
38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
38143137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			/* The following clears the firmware id word.  This
38153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			   ensures that the driver will not attempt to talk to
38163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			   the board until it has been properly initialized.
38173137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			 */
38183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
38193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(addr2 + ID_ADDRESS, 0L);
382058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
3821ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby
3822ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby		retval = cyz_load_fw(pdev, addr2, addr0, irq);
3823963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		if (retval <= 0)
3824ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby			goto err_unmap;
3825963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		nchan = retval;
38263137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if ((cy_next_channel + nchan) > NR_PORTS) {
38293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
38303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"channels are available. Change NR_PORTS in "
38313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"cyclades.c and recompile kernel.\n");
38323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_unmap;
38333137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	/* fill the next cy_card structure available */
38353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	for (card_no = 0; card_no < NR_CARDS; card_no++) {
38363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_card[card_no].base_addr == NULL)
38373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
38383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (card_no == NR_CARDS) {	/* no more cy_cards available */
38403137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
38413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"more cards can be used. Change NR_CARDS in "
38423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"cyclades.c and recompile kernel.\n");
38433137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_unmap;
38443137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38463137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
38473137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
38483137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		/* allocate IRQ */
38493137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = request_irq(irq, cyy_interrupt,
38503137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
38513137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (retval) {
38523137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "could not allocate IRQ\n");
38533137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
385458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
3855963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
38563137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	} else {
3857f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3858f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct ZFW_CTRL __iomem *zfw_ctrl;
3859f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3860f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3861f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3862101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		cy_card[card_no].hw_ver = mailbox;
3863101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		cy_card[card_no].num_chips = (unsigned int)-1;
3864f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
386502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CONFIG_CYZ_INTR
386658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		/* allocate IRQ only if board has an IRQ */
38673137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (irq != 0 && irq != 255) {
38683137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			retval = request_irq(irq, cyz_interrupt,
386958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby					IRQF_SHARED, "Cyclades-Z",
38703137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					&cy_card[card_no]);
387158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby			if (retval) {
3872217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				dev_err(&pdev->dev, "could not allocate IRQ\n");
38733137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				goto err_unmap;
387402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
387558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
387602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
38773137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
387802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
38793137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	/* set cy_card */
38803137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].base_addr = addr2;
388197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	cy_card[card_no].ctl_addr.p9050 = addr0;
38823137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].irq = irq;
38833137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].bus_index = 1;
38843137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].first_line = cy_next_channel;
3885963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cy_card[card_no].nports = nchan;
38863137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = cy_init_card(&cy_card[card_no]);
38873137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (retval)
38883137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_null;
388958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
38903137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_set_drvdata(pdev, &cy_card[card_no]);
389158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
38923137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
38933137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
38943137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		/* enable interrupts in the PCI interface */
38953137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
38963137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		switch (plx_ver) {
38973137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9050:
38983137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			cy_writeb(addr0 + 0x4c, 0x43);
38993137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
39003137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
39013137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9060:
39023137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9080:
39033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		default:	/* Old boards, use PLX_9060 */
390497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		{
390597e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			struct RUNTIME_9060 __iomem *ctl_addr = addr0;
390697e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			plx_init(pdev, irq, ctl_addr);
390797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			cy_writew(&ctl_addr->intr_ctrl_stat,
390897e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
39093137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
39103137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
391197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		}
391258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	}
391358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39143137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
39153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
39163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
39173137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		tty_register_device(cy_serial_driver, i, &pdev->dev);
39183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_next_channel += nchan;
39193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
392058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	return 0;
39213137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_null:
39223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].base_addr = NULL;
39233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	free_irq(irq, &cy_card[card_no]);
39243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_unmap:
392524e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby	iounmap(addr0);
39263137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (addr2)
392724e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		iounmap(addr2);
39283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_reg:
39293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_release_regions(pdev);
39303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_dis:
39313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_disable_device(pdev);
39323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr:
39333137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	return retval;
393458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby}
393558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39366747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slabystatic void __devexit cy_pci_remove(struct pci_dev *pdev)
393758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby{
393838d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3939f3851e73ecdd070bc379677ed7aad958446f26e7Jiri Slaby	unsigned int i;
394038d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
394185c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby	/* non-Z with old PLX */
39422693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
3943c2ad4c75154d98c07d30493e4906e1cd0a9162a5Jiri Slaby			PLX_9050)
394497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
394585c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby	else
394685c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby#ifndef CONFIG_CYZ_INTR
39472693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(cinfo))
394885c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby#endif
394997e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
395097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
395197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			~0x0900);
395285c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby
395324e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby	iounmap(cinfo->base_addr);
395497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	if (cinfo->ctl_addr.p9050)
395597e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		iounmap(cinfo->ctl_addr.p9050);
395638d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	if (cinfo->irq
395738d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby#ifndef CONFIG_CYZ_INTR
39582693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		&& !cy_is_Z(cinfo)
395938d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby#endif /* CONFIG_CYZ_INTR */
396038d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby		)
396138d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby		free_irq(cinfo->irq, cinfo);
396238d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	pci_release_regions(pdev);
396338d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
396438d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	cinfo->base_addr = NULL;
39656ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby	for (i = cinfo->first_line; i < cinfo->first_line +
39666ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby			cinfo->nports; i++)
39676ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby		tty_unregister_device(cy_serial_driver, i);
3968dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	cinfo->nports = 0;
3969dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	kfree(cinfo->ports);
397038d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby}
397138d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
39726747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slabystatic struct pci_driver cy_pci_driver = {
39736747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.name = "cyclades",
39746747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.id_table = cy_pci_dev_id,
39756747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.probe = cy_pci_probe,
39766747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.remove = __devexit_p(cy_pci_remove)
39776747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby};
39786747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
39796747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby
3980444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic int cyclades_proc_show(struct seq_file *m, void *v)
39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
398202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
3983dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	unsigned int i, j;
398402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	__u32 cur_jifs = jiffies;
398502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3986444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
398702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			"IdleIn  Overruns  Ldisc\n");
398802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
398902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Output one line for each known port */
3990dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	for (i = 0; i < NR_CARDS; i++)
3991dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		for (j = 0; j < cy_card[i].nports; j++) {
3992dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			info = &cy_card[i].ports[j];
3993dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby
3994d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			if (info->port.count) {
3995d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				/* XXX is the ldisc num worth this? */
3996d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				struct tty_struct *tty;
3997d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				struct tty_ldisc *ld;
3998d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				int num = 0;
3999d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty = tty_port_tty_get(&info->port);
4000d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				if (tty) {
4001d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					ld = tty_ldisc_ref(tty);
4002d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					if (ld) {
4003d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby						num = ld->ops->num;
4004d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby						tty_ldisc_deref(ld);
4005d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					}
4006d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					tty_kref_put(tty);
4007d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				}
4008444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan				seq_printf(m, "%3d %8lu %10lu %8lu "
4009d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					"%10lu %8lu %9lu %6d\n", info->line,
4010dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.in_use) /
4011dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.xmit_bytes,
4012dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.xmit_idle)/
4013dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.recv_bytes,
4014dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.recv_idle)/
4015dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.overruns,
4016d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					num);
4017d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			} else
4018444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan				seq_printf(m, "%3d %8lu %10lu %8lu "
4019dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					"%10lu %8lu %9lu %6ld\n",
4020dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
402102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
4022444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	return 0;
4023444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan}
4024444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan
4025444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic int cyclades_proc_open(struct inode *inode, struct file *file)
4026444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan{
4027444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	return single_open(file, cyclades_proc_show, NULL);
40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4030444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic const struct file_operations cyclades_proc_fops = {
4031444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.owner		= THIS_MODULE,
4032444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.open		= cyclades_proc_open,
4033444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.read		= seq_read,
4034444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.llseek		= seq_lseek,
4035444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.release	= single_release,
4036444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan};
4037444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan
40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The serial driver boot-time initialization code!
40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Hardware I/O ports are mapped to character special devices on a
40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    first found, first allocated manner.  That is, this code searches
40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for Cyclom cards in the system.  As each is found, it is probed
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    to discover how many chips (and thus how many ports) are present.
40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    These ports are mapped to the tty ports 32 and upward in monotonic
40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    fashion.  If an 8-port card is replaced with a 16-port card, the
40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    port mapping on a following card will shift.
40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This approach is different from what is used in the other serial
40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    device driver because the Cyclom is more properly a multiplexer,
40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    not just an aggregation of serial ports on one card.
40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    If there are more cards with more ports than have been
40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    statically allocated above, a warning is printed and the
40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    extra ports are ignored.
40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4056b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations cy_ops = {
405702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.open = cy_open,
405802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.close = cy_close,
405902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.write = cy_write,
406002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.put_char = cy_put_char,
406102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.flush_chars = cy_flush_chars,
406202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.write_room = cy_write_room,
406302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.chars_in_buffer = cy_chars_in_buffer,
406402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.flush_buffer = cy_flush_buffer,
406502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.ioctl = cy_ioctl,
406602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.throttle = cy_throttle,
406702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.unthrottle = cy_unthrottle,
406802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.set_termios = cy_set_termios,
406902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.stop = cy_stop,
407002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.start = cy_start,
407102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.hangup = cy_hangup,
407202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.break_ctl = cy_break,
407302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.wait_until_sent = cy_wait_until_sent,
407402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.tiocmget = cy_tiocmget,
407502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.tiocmset = cy_tiocmset,
40760587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	.get_icount = cy_get_icount,
4077444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.proc_fops = &cyclades_proc_fops,
40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
408002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int __init cy_init(void)
40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4082dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	unsigned int nboards;
40839dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	int retval = -ENOMEM;
408402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
408502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver = alloc_tty_driver(NR_PORTS);
408602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!cy_serial_driver)
40879dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		goto err;
4088217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
408964a14b51bed6427a2e6d68ed687027f065f5a156Michal Marek	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
409002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
409102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Initialize the tty_driver structure */
409202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
409302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->owner = THIS_MODULE;
409402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->driver_name = "cyclades";
409502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->name = "ttyC";
409602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->major = CYCLADES_MAJOR;
409702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->minor_start = 0;
409802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
409902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
410002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->init_termios = tty_std_termios;
410102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->init_termios.c_cflag =
410202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
41036ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
410402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	tty_set_operations(cy_serial_driver, &cy_ops);
410502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41069dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	retval = tty_register_driver(cy_serial_driver);
41079dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	if (retval) {
41089dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
41099dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		goto err_frtty;
41109dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	}
411102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
411202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* the code below is responsible to find the boards. Each different
411302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   type of board has its own detection routine. If a board is found,
411402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   the next cy_card structure available is set by the detection
411502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   routine. These functions are responsible for checking the
411602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   availability of cy_card and cy_port data structures and updating
411702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   the cy_next_channel. */
411802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
411902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* look for isa boards */
412014a55a6789d8409e58329310f9a18fc141deb4c2Jiri Slaby	nboards = cy_detect_isa();
412102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41226747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#ifdef CONFIG_PCI
412302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* look for pci boards */
41246747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	retval = pci_register_driver(&cy_pci_driver);
4125d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl	if (retval && !nboards) {
4126d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl		tty_unregister_driver(cy_serial_driver);
4127d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl		goto err_frtty;
4128d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl	}
41296747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
41309dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby
41319dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	return 0;
41329dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slabyerr_frtty:
41339dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	put_tty_driver(cy_serial_driver);
41349dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slabyerr:
41359dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	return retval;
413602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_init */
41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
413802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void __exit cy_cleanup_module(void)
41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4140dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	struct cyclades_card *card;
414165f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int i, e1;
41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
4144b70509066cba24067757f1422c899c43e433429dJiri Slaby	del_timer_sync(&cyz_timerlist);
41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_CYZ_INTR */
41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
414715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	e1 = tty_unregister_driver(cy_serial_driver);
414815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (e1)
4149217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_ERR "failed to unregister Cyclades serial "
4150217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"driver(%d)\n", e1);
41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41526747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#ifdef CONFIG_PCI
41536747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	pci_unregister_driver(&cy_pci_driver);
41546747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
41556747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby
415602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_CARDS; i++) {
4157dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		card = &cy_card[i];
4158dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		if (card->base_addr) {
415985c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby			/* clear interrupt */
4160dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4161dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			iounmap(card->base_addr);
416297e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			if (card->ctl_addr.p9050)
416397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				iounmap(card->ctl_addr.p9050);
4164dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			if (card->irq
41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
41662693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby				&& !cy_is_Z(card)
41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_CYZ_INTR */
416802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				)
4169dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby				free_irq(card->irq, card);
417065f76a82ec7a0374fad85211535330e203740475Jiri Slaby			for (e1 = card->first_line; e1 < card->first_line +
4171dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					card->nports; e1++)
41726ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby				tty_unregister_device(cy_serial_driver, e1);
4173dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			kfree(card->ports);
417402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
417502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
4176f2462bfe558559c9fbc4ef60812d5df30ccb01f6Jiri Slaby
4177f2462bfe558559c9fbc4ef60812d5df30ccb01f6Jiri Slaby	put_tty_driver(cy_serial_driver);
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cy_cleanup_module */
41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(cy_init);
41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cy_cleanup_module);
41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
4184c8e1693a4f63e317966f3dfe8f815eda95e26610Jiri SlabyMODULE_VERSION(CY_VERSION);
41859f56fad741163fe2111cbbcfb7ff795ebdabdab1Scott James RemnantMODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4186e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("cyzfirm.bin");
4187