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;
1518410235fd4d20b8feaf8930a0575d23acc088aa87Jiri Slaby	unsigned int i, line = tty->index;
151965f76a82ec7a0374fad85211535330e203740475Jiri Slaby	int retval;
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	for (i = 0; i < NR_CARDS; i++)
1522dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		if (line < cy_card[i].first_line + cy_card[i].nports &&
1523dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby				line >= cy_card[i].first_line)
1524dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			break;
1525dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	if (i >= NR_CARDS)
1526dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		return -ENODEV;
1527dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	info = &cy_card[i].ports[line - cy_card[i].first_line];
152815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->line < 0)
152902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* If the card's firmware hasn't been loaded,
153202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   treat it as absent from the system.  This
153302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   will make the user pay attention.
153402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
15352693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(info->card)) {
1536875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		struct cyclades_card *cinfo = info->card;
153702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
153802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
15392693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(cinfo)) {
15402693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
1541101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby					readl(&firm_id->signature) ==
1542101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby					ZFIRM_HLT) {
1543217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1544217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"need an external power supply for "
1545217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"this number of ports.\nFirmware "
1546217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"halted.\n");
154702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			} else {
1548217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1549217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"yet loaded\n");
155002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
155102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
155202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
155302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CONFIG_CYZ_INTR
155402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else {
155502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* In case this Z board is operating in interrupt mode, its
155602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   interrupts should be enabled as soon as the first open
155702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   happens to one of its ports. */
155802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!cinfo->intr_enabled) {
155997e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				u16 intr;
156002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
156102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* Enable interrupts on the PLX chip */
156297e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				intr = readw(&cinfo->ctl_addr.p9060->
156397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby						intr_ctrl_stat) | 0x0900;
156497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				cy_writew(&cinfo->ctl_addr.p9060->
156597e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby						intr_ctrl_stat, intr);
156602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* Enable interrupts on the FW */
156702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				retval = cyz_issue_cmd(cinfo, 0,
156802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby						C_CM_IRQ_ENBL, 0L);
156902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (retval != 0) {
1570217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					printk(KERN_ERR "cyc:IRQ enable retval "
1571217191910c0286e0b3c7e3011630273695253da3Jiri Slaby						"was %x\n", retval);
157202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
157302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cinfo->intr_enabled = 1;
157402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
157602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
157702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Make sure this Z port really exists in hardware */
157802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->line > (cinfo->first_line + cinfo->nports - 1))
157902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -ENODEV;
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
1582217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
158402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	tty->driver_data = info;
158515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_open"))
158602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
158715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1589217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
159077451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.count);
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
159277451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.count++;
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_COUNT
1594217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
159577451e53e0a509a98eda272567869cfe96431ba9Alan Cox		current->pid, info->port.count);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
159902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * If the port is the middle of closing, bail out now
160002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
160177451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1602be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann		wait_event_interruptible_tty(info->port.close_wait,
160377451e53e0a509a98eda272567869cfe96431ba9Alan Cox				!(info->port.flags & ASYNC_CLOSING));
160477451e53e0a509a98eda272567869cfe96431ba9Alan Cox		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
160502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
160702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
160802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Start up serial port
160902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
1610d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	retval = cy_startup(info, tty);
161115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (retval)
161202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return retval;
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1614f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	retval = tty_port_block_til_ready(&info->port, tty, filp);
161502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (retval) {
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OPEN
1617217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1618217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			"with %d\n", retval);
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
162002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return retval;
162102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
162302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->throttle = 0;
1624d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	tty_port_tty_set(&info->port, tty);
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
162602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CY_DEBUG_OPEN
1627217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_open done\n");
162802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif
162902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
163002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_open */
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_wait_until_sent() --- wait until the transmitter is empty
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
163502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_wait_until_sent(struct tty_struct *tty, int timeout)
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1637875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
1638cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
163902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long orig_jiffies;
164002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int char_time;
164102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
164202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
164302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
164402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
164502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_fifo_size == 0)
164602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;		/* Just in case.... */
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	orig_jiffies = jiffies;
164902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
165002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Set the check interval to be 1/5 of the estimated time to
165102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * send a single character, and make it at least 1.  The check
165202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * interval should also be less than the timeout.
165302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 *
165402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Note: we have to use pretty tight timings here to satisfy
165502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * the NIST-PCTS.
165602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
165702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
165802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char_time = char_time / 5;
165902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (char_time <= 0)
166002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_time = 1;
166102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (timeout < 0)
166202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		timeout = 0;
166302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (timeout)
166402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		char_time = min(char_time, timeout);
166502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
166602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * If the transmitter hasn't cleared in twice the approximate
166702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * amount of time to send the entire FIFO, it probably won't
166802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * ever clear.  This assumes the UART isn't doing flow
166902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * control, which is currently the case.  Hence, if it ever
167002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * takes longer than info->timeout, this is probably due to a
167102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * UART bug of some kind.  So, we clamp the timeout parameter at
167202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * 2*info->timeout.
167302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
167402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!timeout || timeout > 2 * info->timeout)
167502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		timeout = 2 * info->timeout;
16768bab534b508230f33be5f7ba8492923754274a8dJiri Slaby
167702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
16782693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
16793aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		while (cyy_readb(info, CySRER) & CyTxRdy) {
168002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (msleep_interruptible(jiffies_to_msecs(char_time)))
168102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
168202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (timeout && time_after(jiffies, orig_jiffies +
168302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					timeout))
168402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
168502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
168702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Run one more char cycle */
168802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	msleep_interruptible(jiffies_to_msecs(char_time * 5));
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Coxstatic void cy_flush_buffer(struct tty_struct *tty)
1692978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox{
1693978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct cyclades_port *info = tty->driver_data;
1694978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct cyclades_card *card;
1695978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	int channel, retval;
1696978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	unsigned long flags;
1697978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1698978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox#ifdef CY_DEBUG_IO
1699978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1700978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox#endif
1701978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1702978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1703978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		return;
1704978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1705978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	card = info->card;
1706978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	channel = info->line - card->first_line;
1707978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1708978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_lock_irqsave(&card->card_lock, flags);
1709978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1710978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_unlock_irqrestore(&card->card_lock, flags);
1711978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
17122693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1713978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox					   buffers as well */
1714978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		spin_lock_irqsave(&card->card_lock, flags);
1715978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1716978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		if (retval != 0) {
1717978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox			printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1718978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox				"was %x\n", info->line, retval);
1719978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		}
1720978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		spin_unlock_irqrestore(&card->card_lock, flags);
1721978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	}
1722978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	tty_wakeup(tty);
1723978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox}				/* cy_flush_buffer */
1724978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1725978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
1726e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Coxstatic void cy_do_close(struct tty_port *port)
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1728e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	struct cyclades_port *info = container_of(port, struct cyclades_port,
1729e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox								port);
17309fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	struct cyclades_card *card;
173102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
17323aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17349fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	card = info->card;
17353aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	channel = info->line - card->first_line;
17369fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
173702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
17382693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
173902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Stop accepting input */
17403aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
17413aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
174277451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (info->port.flags & ASYNC_INITIALIZED) {
174315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			/* Waiting for on-board buffers to be empty before
174415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			   closing the port */
17459fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
1746e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox			cy_wait_until_sent(port->tty, info->timeout);
17479fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
174802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
174902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
175002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef Z_WAKE
175115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		/* Waiting for on-board buffers to be empty before closing
175215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		   the port */
1753f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
175402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
175502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1756f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
17579fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
175802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
1759217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_DEBUG "cyc:cy_close retval on "
1760217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"ttyC%d was %x\n", info->line, retval);
176102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
17629fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
17632c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby			wait_for_completion_interruptible(&info->shutdown_wait);
17649fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
176502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
176702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
17689fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
1769e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	cy_shutdown(info, port->tty);
1770e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox}
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1772e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox/*
1773e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox * This routine is called when a particular tty device is closed.
1774e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox */
1775e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Coxstatic void cy_close(struct tty_struct *tty, struct file *filp)
1776e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox{
1777e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	struct cyclades_port *info = tty->driver_data;
1778e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1779e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox		return;
1780e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	tty_port_close(&info->port, tty, filp);
178102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_close */
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine gets called when tty_write has put something into
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the write_queue.  The characters may come from user space or
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kernel space.
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will return the number of characters actually
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accepted for writing.
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is not already transmitting stuff, start it off by
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabling interrupts.  The interrupt service routine will then
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that the characters are sent.
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is already active, there is no need to kick it.
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
179602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1798cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
179902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
180002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int c, ret = 0;
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1803217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
180615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_write"))
180702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
180977451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!info->port.xmit_buf)
181002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18129fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
181302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	while (1) {
18141a4e2351e7fcf2d10bb5524b0ace7797ffad4d98Harvey Harrison		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
18151a4e2351e7fcf2d10bb5524b0ace7797ffad4d98Harvey Harrison		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
181602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
181702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (c <= 0)
181802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
181902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
182077451e53e0a509a98eda272567869cfe96431ba9Alan Cox		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
182102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->xmit_head = (info->xmit_head + c) &
182202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(SERIAL_XMIT_SIZE - 1);
182302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->xmit_cnt += c;
182402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		buf += c;
182502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		count -= c;
182602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret += c;
182702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
18289fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
182902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
183002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->idle_stats.xmit_bytes += ret;
183102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->idle_stats.xmit_idle = jiffies;
183202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
183315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
183402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		start_xmit(info);
183515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
183602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret;
183702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_write */
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the kernel to write a single
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * character to the tty device.  If the kernel uses this routine,
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it must call the flush_chars() routine (if defined) when it is
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * done stuffing characters into the driver.  If there is no room
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the queue, the character is ignored.
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
184676b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Coxstatic int cy_put_char(struct tty_struct *tty, unsigned char ch)
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1848cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
184902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1852217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
185676b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185877451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (!info->port.xmit_buf)
185976b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18619fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
186290cc301859ea8840634324a7f5b9680312377667Jiri Slaby	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
18639fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&info->card->card_lock, flags);
186476b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox		return 0;
186502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
186777451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.xmit_buf[info->xmit_head++] = ch;
186802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
186902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->xmit_cnt++;
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->idle_stats.xmit_bytes++;
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->idle_stats.xmit_idle = jiffies;
18729fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
187376b25a5509bbafdbfc7d7d6b41a3c64947d59360Alan Cox	return 1;
187402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_put_char */
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the kernel after it has written a
187815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox * series of characters to the tty device using put_char().
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
188002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_flush_chars(struct tty_struct *tty)
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1882cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
188302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1885217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
188902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
189277451e53e0a509a98eda272567869cfe96431ba9Alan Cox			!info->port.xmit_buf)
189302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	start_xmit(info);
189602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_flush_chars */
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine returns the numbers of characters the tty driver
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will accept for queuing to be written.  This number is subject
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to change as output buffers get emptied, or if the output flow
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control is activated.
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
190402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_write_room(struct tty_struct *tty)
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1906cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
190702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int ret;
190802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1910217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_write_room"))
191402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
191502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
191602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (ret < 0)
191702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret = 0;
191802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret;
191902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_write_room */
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int cy_chars_in_buffer(struct tty_struct *tty)
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1923cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
192602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return 0;
192702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_EXT_CHARS_IN_BUFFER
1929f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	if (!cy_is_Z(info->card)) {
193002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_EXT_CHARS_IN_BUFFER */
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1932217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1933217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			info->line, info->xmit_cnt);
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
193502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return info->xmit_cnt;
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef Z_EXT_CHARS_IN_BUFFER
193702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
1938f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
193902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int char_count;
1940ad39c3004971173baeca80173e77022ee03eb9a1Jiri Slaby		__u32 tx_put, tx_get, tx_bufsize;
194102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
1942db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_get = readl(&buf_ctrl->tx_get);
1943db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_put = readl(&buf_ctrl->tx_put);
1944db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
194502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (tx_put >= tx_get)
194602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count = tx_put - tx_get;
194702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
194802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			char_count = tx_put - tx_get + tx_bufsize;
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_IO
1950217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1951217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			info->line, info->xmit_cnt + char_count);
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1953096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby		return info->xmit_cnt + char_count;
195402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
195502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* Z_EXT_CHARS_IN_BUFFER */
195602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_chars_in_buffer */
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_ioctl() and friends
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19641a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielkastatic void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
196602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int co, co_val, bpr;
19671a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
196802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			25000000);
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (baud == 0) {
197102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->tbpr = info->tco = info->rbpr = info->rco = 0;
197202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
197302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* determine which prescaler to use */
197602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
197702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_clock / co_val / baud > 63)
197802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
197902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
198202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (bpr > 255)
198302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		bpr = 255;
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->tbpr = info->rbpr = bpr;
198602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->tco = info->rco = co;
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine finds or computes the various line characteristics.
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It used to be called config_setup
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1993d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabystatic void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1995875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
199602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
19973aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
199802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned cflag, iflag;
199902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int baud, baud_rate = 0;
200002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int i;
200102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2002d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if (!tty->termios) /* XXX can this happen at all? */
200302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
200415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
200515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (info->line == -1)
200602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
200715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
2008d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cflag = tty->termios->c_cflag;
2009d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	iflag = tty->termios->c_iflag;
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
201202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * Set up the tty->alt_speed kludge
201302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
2014d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2015d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 57600;
2016d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2017d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 115200;
2018d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2019d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 230400;
2020d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2021d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		tty->alt_speed = 460800;
202202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
202302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
2024875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
202502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
20262693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
202746fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		u32 cflags;
202846fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby
202902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* baud rate */
2030d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		baud = tty_get_baud_rate(tty);
203177451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
203202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
203302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->custom_divisor)
203402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud / info->custom_divisor;
203502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
203602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud;
203702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud > CD1400_MAX_SPEED) {
203802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			baud = CD1400_MAX_SPEED;
203902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
204002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* find the baud index */
204102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (i = 0; i < 20; i++) {
204215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (baud == baud_table[i])
204302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
204402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
204515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (i == 20)
204602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			i = 19;	/* CD1400_MAX_SPEED */
204702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
204877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
204902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
205002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cyy_baud_calc(info, baud_rate);
205102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
205202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->chip_rev >= CD1400_REV_J) {
205302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				/* It is a CD1400 rev. J or later */
205402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tbpr = baud_bpr_60[i];	/* Tx BPR */
205502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tco = baud_co_60[i];	/* Tx CO */
205602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rbpr = baud_bpr_60[i];	/* Rx BPR */
205702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rco = baud_co_60[i];	/* Rx CO */
205802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			} else {
205902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tbpr = baud_bpr_25[i];	/* Tx BPR */
206002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->tco = baud_co_25[i];	/* Tx CO */
206102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rbpr = baud_bpr_25[i];	/* Rx BPR */
206202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->rco = baud_co_25[i];	/* Rx CO */
206302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
206402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
206502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud_table[i] == 134) {
206602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* get it right for 134.5 baud */
206702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
206802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					2;
206977451e53e0a509a98eda272567869cfe96431ba9Alan Cox		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
207002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
207102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
207202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_rate) + 2;
207302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud_table[i]) {
207402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
207502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_table[i]) + 2;
207602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* this needs to be propagated into the card info */
207702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
207802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = 0;
207902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
208002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* By tradition (is it a standard?) a baud rate of zero
208102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   implies the line should be/has been closed.  A bit
208202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   later in this routine such a test is performed. */
208302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
208402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* byte size and parity */
208502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor5 = 0;
208602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor4 = 0;
208702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* receive threshold */
208802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 = (info->default_threshold ?
208902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->default_threshold : baud_cor3[i]);
209002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor2 = CyETC;
209102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cflag & CSIZE) {
209202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS5:
209302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_5_BITS;
209402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
209502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS6:
209602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_6_BITS;
209702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
209802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS7:
209902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_7_BITS;
210002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
210102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS8:
210202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 = Cy_8_BITS;
210302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
210402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
210515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (cflag & CSTOPB)
210602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 |= Cy_2_STOP;
210715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
210802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & PARENB) {
210915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (cflag & PARODD)
211002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->cor1 |= CyPARITY_O;
211115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			else
211202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->cor1 |= CyPARITY_E;
211315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		} else
211402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor1 |= CyPARITY_NONE;
211502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
211602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CTS flow control flag */
211702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CRTSCTS) {
211877451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CTS_FLOW;
211902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor2 |= CyCtsAE;
212002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
212177451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CTS_FLOW;
212202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->cor2 &= ~CyCtsAE;
212302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
212402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CLOCAL)
212577451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CHECK_CD;
212602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
212777451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CHECK_CD;
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 /***********************************************
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    The hardware option, CyRtsAO, presents RTS when
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    the chip has characters to send.  Since most modems
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    use RTS as reverse (inbound) flow control, this
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    option is not used.  If inbound flow control is
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    necessary, DTR can be programmed to provide the
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    appropriate signals for use with a non-standard
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cable.  Contact Marcio Saito for details.
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 ***********************************************/
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
213902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		channel &= 0x03;
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21419fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
21423aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
214302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
214402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* tx and rx baud rate */
214502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21463aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTCOR, info->tco);
21473aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyTBPR, info->tbpr);
21483aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRCOR, info->rco);
21493aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRBPR, info->rbpr);
215002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
215102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set line characteristics  according configuration */
215202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21533aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySCHR1, START_CHAR(tty));
21543aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
21553aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR1, info->cor1);
21563aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR2, info->cor2);
21573aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR3, info->cor3);
21583aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR4, info->cor4);
21593aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR5, info->cor5);
216002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21613aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
21623aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				CyCOR3ch);
216302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
216415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		/* !!! Is this needed? */
21653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel);
21663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR,
216702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(info->default_timeout ? info->default_timeout : 0x02));
216802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* 10ms rx timeout */
216902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
217046fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cflags = CyCTS;
217146fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		if (!C_CLOCAL(tty))
217246fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cflags |= CyDSR | CyRI | CyDCD;
217346fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* without modem intr */
217446fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
217546fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* act on 1->0 modem transitions */
217646fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		if ((cflag & CRTSCTS) && info->rflow)
217746fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
217846fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		else
217946fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby			cyy_writeb(info, CyMCOR1, cflags);
218046fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		/* act on 0->1 modem transitions */
218146fb782522092f772c6ce2b129f201ca6e1e15a2Jiri Slaby		cyy_writeb(info, CyMCOR2, cflags);
218202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
21834d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		if (i == 0)	/* baud rate is zero, turn off line */
21844d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_DTR);
21854d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		else
21864d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, TIOCM_DTR, 0);
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2188d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		clear_bit(TTY_IO_ERROR, &tty->flags);
21899fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2192f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
21931a86b5e34e4d09e3246a983c53929ce38af52275Klaus Kudielka		__u32 sw_flow;
219402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		int retval;
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21962693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cyz_is_loaded(card))
219702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return;
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
219902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* baud rate */
2200d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		baud = tty_get_baud_rate(tty);
220177451e53e0a509a98eda272567869cfe96431ba9Alan Cox		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
220202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
220302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (info->custom_divisor)
220402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud / info->custom_divisor;
220502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			else
220602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				baud_rate = info->baud;
220702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud > CYZ_MAX_SPEED) {
220802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			baud = CYZ_MAX_SPEED;
220902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
221002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&ch_ctrl->comm_baud, baud);
221102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
221202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud == 134) {
221302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* get it right for 134.5 baud */
221402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
221502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					2;
221677451e53e0a509a98eda272567869cfe96431ba9Alan Cox		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
221702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				ASYNC_SPD_CUST) {
221802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
221902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud_rate) + 2;
222002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else if (baud) {
222102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = (info->xmit_fifo_size * HZ * 15 /
222202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					baud) + 2;
222302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* this needs to be propagated into the card info */
222402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
222502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->timeout = 0;
222602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
222802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* byte size and parity */
222902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		switch (cflag & CSIZE) {
223002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS5:
223102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
223202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
223302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS6:
223402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
223502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
223602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS7:
223702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
223802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
223902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		case CS8:
224002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
224102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
224202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
224302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CSTOPB) {
224402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l,
2245db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
224602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
224702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_data_l,
2248db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
224902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
225002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & PARENB) {
225115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (cflag & PARODD)
225202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
225315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			else
225402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
225515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		} else
225602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
225802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CTS flow control flag */
225902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cflag & CRTSCTS) {
226002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->hw_flow,
2261db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
226202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
2263db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2264db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby					~(C_RS_CTS | C_RS_RTS));
226502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
226602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* As the HW flow control is done in firmware, the driver
226702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   doesn't need to care about it */
226877451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags &= ~ASYNC_CTS_FLOW;
226902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
227002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* XON/XOFF/XANY flow control flags */
227102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		sw_flow = 0;
227202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (iflag & IXON) {
227302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			sw_flow |= C_FL_OXX;
227402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (iflag & IXANY)
227502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				sw_flow |= C_FL_OIXANY;
227602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
227702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writel(&ch_ctrl->sw_flow, sw_flow);
227802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2279875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
228002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2281217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2282217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
228302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
228402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
228502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* CD sensitivity */
228615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (cflag & CLOCAL)
228777451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags &= ~ASYNC_CHECK_CD;
228815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		else
228977451e53e0a509a98eda272567869cfe96431ba9Alan Cox			info->port.flags |= ASYNC_CHECK_CD;
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (baud == 0) {	/* baud rate is zero, turn off line */
229202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->rs_control,
2293db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
2295217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
229702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
229802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writel(&ch_ctrl->rs_control,
2299db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
2301217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
230302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
230515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
230602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2307217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2308217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
230902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		clear_bit(TTY_IO_ERROR, &tty->flags);
23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
231302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_line_char */
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23156c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slabystatic int cy_get_serial_info(struct cyclades_port *info,
231615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		struct serial_struct __user *retinfo)
23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2318875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *cinfo = info->card;
23196c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct serial_struct tmp = {
23206c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.type = info->type,
23216c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.line = info->line,
23226c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.port = (info->card - cy_card) * 0x100 + info->line -
23236c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			cinfo->first_line,
23246c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.irq = cinfo->irq,
23256c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.flags = info->port.flags,
23266c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.close_delay = info->port.close_delay,
23276c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.closing_wait = info->port.closing_wait,
23286c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.baud_base = info->baud,
23296c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.custom_divisor = info->custom_divisor,
23306c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		.hub6 = 0,		/*!!! */
23316c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	};
233202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
23336c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby}
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2336d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slabycy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
233715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		struct serial_struct __user *new_info)
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
233902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct serial_struct new_serial;
234025c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	int ret;
234102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
234202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
234302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -EFAULT;
234402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
234525c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	mutex_lock(&info->port.mutex);
234602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!capable(CAP_SYS_ADMIN)) {
234744b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		if (new_serial.close_delay != info->port.close_delay ||
234802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				new_serial.baud_base != info->baud ||
234902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(new_serial.flags & ASYNC_FLAGS &
235002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					~ASYNC_USR_MASK) !=
235177451e53e0a509a98eda272567869cfe96431ba9Alan Cox				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
235225c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		{
235325c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox			mutex_unlock(&info->port.mutex);
235402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return -EPERM;
235525c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		}
235677451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
235702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(new_serial.flags & ASYNC_USR_MASK);
235802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->baud = new_serial.baud_base;
235902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->custom_divisor = new_serial.custom_divisor;
236002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		goto check_and_exit;
236102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
236202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
236302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
236402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * OK, past this point, all the error checking has been done.
236502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * At this point, we start making changes.....
236602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
236702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
236802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->baud = new_serial.baud_base;
236902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->custom_divisor = new_serial.custom_divisor;
237077451e53e0a509a98eda272567869cfe96431ba9Alan Cox	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
237102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(new_serial.flags & ASYNC_FLAGS);
237244b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	info->port.close_delay = new_serial.close_delay * HZ / 100;
237344b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_and_exit:
237677451e53e0a509a98eda272567869cfe96431ba9Alan Cox	if (info->port.flags & ASYNC_INITIALIZED) {
2377d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		cy_set_line_char(info, tty);
237825c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		ret = 0;
237902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
238025c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox		ret = cy_startup(info, tty);
238102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
238225c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	mutex_unlock(&info->port.mutex);
238325c3cdf80c73156e910a322aba468ddaca0b91aeAlan Cox	return ret;
238402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_serial_info */
23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_lsr_info - get line status register info
23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Purpose: Let user call ioctl() to get info when the UART physically
23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    is emptied.  On bus types like RS485, the transmitter must
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    release the bus after transmitting. This must be done when
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    the transmit shift register is empty, not be done when the
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    transmit holding register is empty.  This functionality
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    allows an RS485 driver to be written in user space.
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
239615ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23983aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
239902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned int result;
240002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
24013aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	u8 status;
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24032693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24049fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24053aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
24069fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
240702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		result = (status ? 0 : TIOCSER_TEMT);
240802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
240902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Not supported yet */
241002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -EINVAL;
241102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2412dbca36eab48ee48dfc60b8f41ffad54160ebdd09Dan Carpenter	return put_user(result, value);
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241560b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int cy_tiocmget(struct tty_struct *tty)
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2417cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2418875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
24193aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int result;
242002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2421bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison	if (serial_paranoia_check(info, tty->name, __func__))
242202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
24250d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24262693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24270d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		unsigned long flags;
24283aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		int channel = info->line - card->first_line;
24293aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 status;
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24319fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24323aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
24333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status = cyy_readb(info, CyMSVR1);
24343aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		status |= cyy_readb(info, CyMSVR2);
24359fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
243602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
243702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->rtsdtr_inv) {
243802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			result = ((status & CyRTS) ? TIOCM_DTR : 0) |
243902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				((status & CyDTR) ? TIOCM_RTS : 0);
244002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
244102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			result = ((status & CyRTS) ? TIOCM_RTS : 0) |
244202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				((status & CyDTR) ? TIOCM_DTR : 0);
244302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
244402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
244502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyRI) ? TIOCM_RNG : 0) |
244602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyDSR) ? TIOCM_DSR : 0) |
244702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			((status & CyCTS) ? TIOCM_CTS : 0);
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
24490d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		u32 lstatus;
24500d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24510d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (!cyz_is_loaded(card)) {
24520d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			result = -ENODEV;
24530d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			goto end;
245402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24560d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
24570d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
24580d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
24590d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
24600d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
24610d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
24620d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
246302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
24640d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slabyend:
246502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return result;
246602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_tiomget */
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
246920b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxcy_tiocmset(struct tty_struct *tty,
247002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		unsigned int set, unsigned int clear)
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2472cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2473875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
247402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
247502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2476bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison	if (serial_paranoia_check(info, tty->name, __func__))
247702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
247802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
247902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
24802693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
24814d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24824d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		cyy_change_rts_dtr(info, set, clear);
24834d7682005ca88a37667c4af03908798e188b5224Jiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
248402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	} else {
24850d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
24860d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		int retval, channel = info->line - card->first_line;
24870d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		u32 rs;
24880d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24890d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (!cyz_is_loaded(card))
24900d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			return -ENODEV;
24910d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby
24920d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
24930d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		rs = readl(&ch_ctrl->rs_control);
24940d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (set & TIOCM_RTS)
24950d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs |= C_RS_RTS;
24960d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (clear & TIOCM_RTS)
24970d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs &= ~C_RS_RTS;
24980d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (set & TIOCM_DTR) {
24990d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs |= C_RS_DTR;
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
25010d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
25030d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		}
25040d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		if (clear & TIOCM_DTR) {
25050d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			rs &= ~C_RS_DTR;
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_DTR
25070d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby			printk(KERN_DEBUG "cyc:set_modem_info clearing "
25080d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby				"Z DTR\n");
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
251002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
25110d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		cy_writel(&ch_ctrl->rs_control, rs);
25129fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
25130d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
251402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (retval != 0) {
2515217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2516217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"was %x\n", info->line, retval);
251702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
251902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
25200d3487294e4e175eb6371c8df8ef44b45964e0f6Jiri Slaby}
25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_break() --- routine which turns the break handling on or off
25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
25259e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int cy_break(struct tty_struct *tty, int break_state)
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2527cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
25289fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	struct cyclades_card *card;
252902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
25309e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	int retval = 0;
25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_break"))
25339e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox		return -EINVAL;
25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25359fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	card = info->card;
25369fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby
25379fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_lock_irqsave(&card->card_lock, flags);
25382693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
253902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* Let the transmit ISR take care of this (since it
254002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   requires stuffing characters into the output stream).
254102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
254202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (break_state == -1) {
254302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->breakon) {
254402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->breakon = 1;
254502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (!info->xmit_cnt) {
25469fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_unlock_irqrestore(&card->card_lock, flags);
254702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					start_xmit(info);
25489fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_lock_irqsave(&card->card_lock, flags);
254902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
255002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
255102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
255202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (!info->breakoff) {
255302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				info->breakoff = 1;
255402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				if (!info->xmit_cnt) {
25559fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_unlock_irqrestore(&card->card_lock, flags);
255602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					start_xmit(info);
25579fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby					spin_lock_irqsave(&card->card_lock, flags);
255802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				}
255902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
256202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (break_state == -1) {
25639fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card,
25649fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby				info->line - card->first_line,
256502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				C_CM_SET_BREAK, 0L);
256602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
2567217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_ERR "cyc:cy_break (set) retval on "
2568217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"ttyC%d was %x\n", info->line, retval);
256902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
257002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
25719fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			retval = cyz_issue_cmd(card,
25729fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby				info->line - card->first_line,
257302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				C_CM_CLR_BREAK, 0L);
257402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			if (retval != 0) {
2575217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2576217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"on ttyC%d was %x\n", info->line,
2577217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					retval);
257802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25819fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby	spin_unlock_irqrestore(&card->card_lock, flags);
25829e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	return retval;
258302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_break */
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
258502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int set_threshold(struct cyclades_port *info, unsigned long value)
25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25873aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
258802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25902693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
259102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 &= ~CyREC_FIFO;
259202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->cor3 |= value & CyREC_FIFO;
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25949fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
25953aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCOR3, info->cor3);
25963aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
25979fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
259802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
259902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
260002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_threshold */
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_threshold(struct cyclades_port *info,
260315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox						unsigned long __user *value)
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26053aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26072693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26083aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
260902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return put_user(tmp, value);
261002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2611f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	return 0;
261202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* get_threshold */
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int set_timeout(struct cyclades_port *info, unsigned long value)
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26163aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
261702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26192693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26209fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&card->card_lock, flags);
26213aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyRTPR, value & 0xff);
26229fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&card->card_lock, flags);
262302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
262402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return 0;
262502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* set_timeout */
26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262715ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Coxstatic int get_timeout(struct cyclades_port *info,
262815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox						unsigned long __user *value)
26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26303aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	struct cyclades_card *card = info->card;
26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26322693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(card)) {
26333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		u8 tmp = cyy_readb(info, CyRTPR);
263402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return put_user(tmp, value);
263502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
2636f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby	return 0;
263702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* get_timeout */
26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26396c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slabystatic int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
26406c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		struct cyclades_icount *cprev)
26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26426c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct cyclades_icount cnow;
26436c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	unsigned long flags;
26446c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	int ret;
26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26466c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	spin_lock_irqsave(&info->card->card_lock, flags);
26476c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	cnow = info->icount;	/* atomic copy */
26486c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	spin_unlock_irqrestore(&info->card->card_lock, flags);
26496c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26506c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
26516c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
26526c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
26536c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
26546c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26556c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	*cprev = cnow;
26566c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby
26576c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	return ret;
26586c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby}
26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine allows the tty driver to implement device-
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific ioctl's.  If the ioctl number passed in cmd is
26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not recognized by the driver, it should return ENOIOCTLCMD.
26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
26666caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxcy_ioctl(struct tty_struct *tty,
266702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 unsigned int cmd, unsigned long arg)
26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2669cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
26706c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby	struct cyclades_icount cnow;	/* kernel counter temps */
267102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int ret_val = 0;
267202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
267302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __user *argp = (void __user *)arg;
267402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
267502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
267602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return -ENODEV;
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2679217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2680217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		info->line, cmd, arg);
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	switch (cmd) {
268402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETMON:
26856c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
26866c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			ret_val = -EFAULT;
26876c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby			break;
26886c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		}
26896c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		memset(&info->mon, 0, sizeof(info->mon));
269002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
269102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETTHRESH:
269202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_threshold(info, argp);
269302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
269402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETTHRESH:
269502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = set_threshold(info, arg);
269602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
269702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETDEFTHRESH:
26986c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = put_user(info->default_threshold,
26996c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				(unsigned long __user *)argp);
270002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETDEFTHRESH:
27026c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		info->default_threshold = arg & 0x0f;
270302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETTIMEOUT:
270502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_timeout(info, argp);
270602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
270702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETTIMEOUT:
270802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = set_timeout(info, arg);
270902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYGETDEFTIMEOUT:
27116c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = put_user(info->default_timeout,
27126c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				(unsigned long __user *)argp);
271302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
271402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case CYSETDEFTIMEOUT:
27156c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		info->default_timeout = arg & 0xff;
271602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETRFLOW:
271802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->rflow = (int)arg;
271902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETRFLOW:
272102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->rflow;
272202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETRTSDTR_INV:
272402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		info->rtsdtr_inv = (int)arg;
272502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETRTSDTR_INV:
272702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->rtsdtr_inv;
272802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETCD1400VER:
273002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = info->chip_rev;
273102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYZSETPOLLCYCLE:
273402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cyz_polling_cycle = (arg * HZ) / 1000;
273502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYZGETPOLLCYCLE:
273702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = (cyz_polling_cycle * 1000) / HZ;
273802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
273902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYSETWAIT:
274144b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.closing_wait = (unsigned short)arg * HZ / 100;
274202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CYGETWAIT:
274444b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		ret_val = info->port.closing_wait / (HZ / 100);
274502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
274602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCGSERIAL:
27476c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby		ret_val = cy_get_serial_info(info, argp);
274802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
274902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCSSERIAL:
2750d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby		ret_val = cy_set_serial_info(info, tty, argp);
275102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	case TIOCSERGETLSR:	/* Get line status register */
275302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = get_lsr_info(info, argp);
275402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		break;
275502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
275602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
275702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * - mask passed in arg for lines of interest
275802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
275902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Caller should use TIOCGICOUNT to see which one it was
276002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCMIWAIT:
27629fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&info->card->card_lock, flags);
276302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* note the counters on entry */
27642c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		cnow = info->icount;
27659fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&info->card->card_lock, flags);
2766bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
27676c28181cf8b7d5af5f20a7bd102452033e14d946Jiri Slaby				cy_cflags_changed(info, arg, &cnow));
27682c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		break;
27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
277002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
277102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
277202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * Return: write counters to the user passed counter struct
277302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 * NB: both 1->0 and 0->1 transitions are counted except for
277402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 *     RI where only 0->1 is counted.
277502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
277602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	default:
277702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		ret_val = -ENOIOCTLCMD;
277802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2781217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
278302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return ret_val;
278402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_ioctl */
27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27860587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int cy_get_icount(struct tty_struct *tty,
27870587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox				struct serial_icounter_struct *sic)
27880587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox{
27890587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	struct cyclades_port *info = tty->driver_data;
27900587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	struct cyclades_icount cnow;	/* Used to snapshot */
27910587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	unsigned long flags;
27920587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
27930587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	spin_lock_irqsave(&info->card->card_lock, flags);
27940587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	cnow = info->icount;
27950587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	spin_unlock_irqrestore(&info->card->card_lock, flags);
27960587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
27970587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->cts = cnow.cts;
27980587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->dsr = cnow.dsr;
27990587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->rng = cnow.rng;
28000587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->dcd = cnow.dcd;
28010587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->rx = cnow.rx;
28020587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->tx = cnow.tx;
28030587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->frame = cnow.frame;
28040587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->overrun = cnow.overrun;
28050587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->parity = cnow.parity;
28060587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->brk = cnow.brk;
28070587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	sic->buf_overrun = cnow.buf_overrun;
28080587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	return 0;
28090587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox}
28100587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox
28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine allows the tty driver to be notified when
28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's termios settings have changed.  Note that a
28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well-designed tty driver should be prepared to accept the case
28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where old == NULL, and try to do something rational.
28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2819cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2822217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2825d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_set_line_char(info, tty);
282602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
282702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if ((old_termios->c_cflag & CRTSCTS) &&
282802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			!(tty->termios->c_cflag & CRTSCTS)) {
282902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		tty->hw_stopped = 0;
283002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_start(tty);
283102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
283302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/*
283402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * No need to wake up processes in open wait, since they
283502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * sample the CLOCAL flag once, and don't recheck it.
283602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * XXX  It's not clear whether the current behavior is correct
283702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 * or not.  Hence, this may change.....
283802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	 */
283902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!(old_termios->c_cflag & CLOCAL) &&
284002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	    (tty->termios->c_cflag & CLOCAL))
284177451e53e0a509a98eda272567869cfe96431ba9Alan Cox		wake_up_interruptible(&info->port.open_wait);
28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
284302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_set_termios */
28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This function is used to send a high-priority XON/XOFF character to
28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the device.
28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
284802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_send_xchar(struct tty_struct *tty, char ch)
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2850cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2851875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
2852875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	int channel;
28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	info->x_char = ch;
28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch)
286002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_start(tty);
28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card = info->card;
2863875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	channel = info->line - card->first_line;
28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28652693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(card)) {
286602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (ch == STOP_CHAR(tty))
2867875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
286802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else if (ch == START_CHAR(tty))
2869875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine is called by the upper-layer tty layer to signal
28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   that incoming characters should be throttled because the input
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   buffers are close to full.
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
287702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_throttle(struct tty_struct *tty)
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2879cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2880875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
288102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_THROTTLE
288402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char buf[64];
28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2886217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
288702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			tty->ldisc.chars_in_buffer(tty), info->line);
28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289015ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
289102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
289202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
289302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	card = info->card;
289402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
289502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (I_IXOFF(tty)) {
28962693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card))
289702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_send_xchar(tty, STOP_CHAR(tty));
289802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
289902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 1;
290002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
290202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tty->termios->c_cflag & CRTSCTS) {
29032693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card)) {
29049fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
29054d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
29069fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
290702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
290802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 1;
290902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
291002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
291102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_throttle */
29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine notifies the tty driver that it should signal
29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that characters can now be sent to the tty without fear of
29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * overrunning the input buffers of the line disciplines.
29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_unthrottle(struct tty_struct *tty)
29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2920cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
2921875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	struct cyclades_card *card;
292202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_THROTTLE
292502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	char buf[64];
292602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
2927217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
292815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
293115ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
293202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
293402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (I_IXOFF(tty)) {
293502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (info->x_char)
293602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->x_char = 0;
293702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		else
293802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_send_xchar(tty, START_CHAR(tty));
29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
294102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (tty->termios->c_cflag & CRTSCTS) {
294202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		card = info->card;
29432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(card)) {
29449fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_lock_irqsave(&card->card_lock, flags);
29454d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
29469fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby			spin_unlock_irqrestore(&card->card_lock, flags);
294702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
294802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			info->throttle = 0;
294902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
295002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
295102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_unthrottle */
29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* cy_start and cy_stop provide software output flow control as a
29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   function of XON/XOFF, software CTS, and other such stuff.
29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
295602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_stop(struct tty_struct *tty)
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
295802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
2959cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
29603aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
296102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2964217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
296702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_stop"))
296802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2970875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	cinfo = info->card;
297102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	channel = info->line - cinfo->first_line;
29722693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo)) {
29739fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&cinfo->card_lock, flags);
29743aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
29753aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
29769fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&cinfo->card_lock, flags);
297702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
297802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_stop */
29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
298002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_start(struct tty_struct *tty)
29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
298202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_card *cinfo;
2983cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
29843aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	int channel;
298502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned long flags;
29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
2988217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
299102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_start"))
299202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2994875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby	cinfo = info->card;
299502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	channel = info->line - cinfo->first_line;
29962693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo)) {
29979fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_lock_irqsave(&cinfo->card_lock, flags);
29983aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CyCAR, channel & 0x03);
29993aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
30009fa1b3b185a802fa0b3f764ad468efd64e1b582eJiri Slaby		spin_unlock_irqrestore(&cinfo->card_lock, flags);
300102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
300202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_start */
30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
300702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void cy_hangup(struct tty_struct *tty)
30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3009cab9bdd14dd7d8091b0aac7877ae9f29724eb741Jiri Slaby	struct cyclades_port *info = tty->driver_data;
301002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_DEBUG_OTHER
3012217191910c0286e0b3c7e3011630273695253da3Jiri Slaby	printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
301602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		return;
30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_flush_buffer(tty);
3019d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby	cy_shutdown(info, tty);
3020174e6fe01e7881caaa350b5e98e4c6189b6cb593Jiri Slaby	tty_port_hangup(&info->port);
302102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_hangup */
30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3023f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic int cyy_carrier_raised(struct tty_port *port)
3024f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3025f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3026f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3027f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3028f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	unsigned long flags;
3029f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	int channel = info->line - cinfo->first_line;
3030f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	u32 cd;
3031f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3032f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_lock_irqsave(&cinfo->card_lock, flags);
30333aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cyy_writeb(info, CyCAR, channel & 0x03);
30343aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby	cd = cyy_readb(info, CyMSVR1) & CyDCD;
3035f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_unlock_irqrestore(&cinfo->card_lock, flags);
3036f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3037f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	return cd;
3038f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3039f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3040f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic void cyy_dtr_rts(struct tty_port *port, int raise)
3041f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3042f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3043f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3044f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3045f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	unsigned long flags;
3046f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3047f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_lock_irqsave(&cinfo->card_lock, flags);
30484d7682005ca88a37667c4af03908798e188b5224Jiri Slaby	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
30494d7682005ca88a37667c4af03908798e188b5224Jiri Slaby			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
3050f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	spin_unlock_irqrestore(&cinfo->card_lock, flags);
3051f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3052f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3053f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic int cyz_carrier_raised(struct tty_port *port)
3054f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3055f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3056f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3057f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3058f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
3059f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3060f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3061f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic void cyz_dtr_rts(struct tty_port *port, int raise)
3062f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby{
3063f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_port *info = container_of(port, struct cyclades_port,
3064f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			port);
3065f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	struct cyclades_card *cinfo = info->card;
3066f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
3067f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	int ret, channel = info->line - cinfo->first_line;
3068f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	u32 rs;
3069f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3070f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	rs = readl(&ch_ctrl->rs_control);
3071f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	if (raise)
3072f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		rs |= C_RS_RTS | C_RS_DTR;
3073f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	else
3074f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		rs &= ~(C_RS_RTS | C_RS_DTR);
3075f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	cy_writel(&ch_ctrl->rs_control, rs);
3076f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3077f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	if (ret != 0)
3078f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby		printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3079f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby				__func__, info->line, ret);
3080f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby#ifdef CY_DEBUG_DTR
3081f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3082f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby#endif
3083f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby}
3084f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3085f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic const struct tty_port_operations cyy_port_ops = {
3086f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.carrier_raised = cyy_carrier_raised,
3087f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.dtr_rts = cyy_dtr_rts,
3088e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	.shutdown = cy_do_close,
3089f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby};
3090f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
3091f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slabystatic const struct tty_port_operations cyz_port_ops = {
3092f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.carrier_raised = cyz_carrier_raised,
3093f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby	.dtr_rts = cyz_dtr_rts,
3094e936ffd5cb2b4c7ee04925c9b92b616c01f1e022Alan Cox	.shutdown = cy_do_close,
3095f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby};
3096f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby
30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_init() and friends
31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_init() is called at boot-time to initialize the serial driver.
31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3105dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slabystatic int __devinit cy_init_card(struct cyclades_card *cinfo)
31060809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby{
31070809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby	struct cyclades_port *info;
3108f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	unsigned int channel, port;
31090809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby
31103046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby	spin_lock_init(&cinfo->card_lock);
3111963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cinfo->intr_enabled = 0;
31123046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
3113963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3114963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby			GFP_KERNEL);
3115dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	if (cinfo->ports == NULL) {
3116dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3117dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		return -ENOMEM;
3118dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	}
3119dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby
3120f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3121f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			channel++, port++) {
3122f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		info = &cinfo->ports[channel];
312344b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		tty_port_init(&info->port);
31243046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		info->magic = CYCLADES_MAGIC;
3125875b206b5f4971cc990a12e891f5519f0f6772a9Jiri Slaby		info->card = cinfo;
31263046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		info->line = port;
31273046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
312844b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.closing_wait = CLOSING_WAIT_DELAY;
312944b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.close_delay = 5 * HZ / 10;
313077451e53e0a509a98eda272567869cfe96431ba9Alan Cox		info->port.flags = STD_COM_FLAGS;
31312c7fea992104b5ca2b510d585a27b3ba018b795fJiri Slaby		init_completion(&info->shutdown_wait);
31323046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31332693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (cy_is_Z(cinfo)) {
3134f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3135f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			struct ZFW_CTRL *zfw_ctrl;
3136f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3137f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			info->port.ops = &cyz_port_ops;
31380809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->type = PORT_STARTECH;
3139f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3140f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			zfw_ctrl = cinfo->base_addr +
3141f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
3142f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3143f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3144f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3145101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby			if (cinfo->hw_ver == ZO_V1)
31460809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->xmit_fifo_size = CYZ_FIFO_SIZE;
31470809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			else
31483046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
31490809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby#ifdef CONFIG_CYZ_INTR
31503991428d9efc7185312196f82cc36e9df4a2ddb0Jiri Slaby			setup_timer(&cyz_rx_full_timer[port],
31513991428d9efc7185312196f82cc36e9df4a2ddb0Jiri Slaby				cyz_rx_restart, (unsigned long)info);
31520809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby#endif
31533046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		} else {
3154f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			unsigned short chip_number;
3155963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby			int index = cinfo->bus_index;
3156f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3157f0737579424dd2c4e68bdd54c718455a3f42c7b5Jiri Slaby			info->port.ops = &cyy_port_ops;
31580809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->type = PORT_CIRRUS;
31590809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
31603046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
31610809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->cor2 = CyETC;
31620809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			info->cor3 = 0x08;	/* _very_ small rcv threshold */
31633046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
3164f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby			chip_number = channel / CyPORTS_PER_CHIP;
31653aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			info->u.cyy.base_addr = cinfo->base_addr +
31663aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby				(cy_chip_offset[chip_number] << index);
31673aeea5b92210083c7cffd4f08a0bb141d3f2d574Jiri Slaby			info->chip_rev = cyy_readb(info, CyGFRCR);
316815ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox
316915ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox			if (info->chip_rev >= CD1400_REV_J) {
31700809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				/* It is a CD1400 rev. J or later */
31710809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tbpr = baud_bpr_60[13];	/* Tx BPR */
31720809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tco = baud_co_60[13];	/* Tx CO */
31730809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rbpr = baud_bpr_60[13];	/* Rx BPR */
31740809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rco = baud_co_60[13];	/* Rx CO */
31750809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rtsdtr_inv = 1;
31760809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			} else {
31770809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tbpr = baud_bpr_25[13];	/* Tx BPR */
31780809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->tco = baud_co_25[13];	/* Tx CO */
31790809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rbpr = baud_bpr_25[13];	/* Rx BPR */
31800809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rco = baud_co_25[13];	/* Rx CO */
31810809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby				info->rtsdtr_inv = 0;
31820809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby			}
31833046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby			info->read_status_mask = CyTIMEOUT | CySPECHAR |
31843046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
31850809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby		}
31863046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31870809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby	}
31883046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby
31893046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#ifndef CONFIG_CYZ_INTR
31902693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
31913046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		mod_timer(&cyz_timerlist, jiffies + 1);
31923046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#ifdef CY_PCI_DEBUG
31933046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
31943046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#endif
31953046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby	}
31963046d50ea58676759453faeefccf57fbc9b72a90Jiri Slaby#endif
3197dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	return 0;
31980809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby}
31990809e2671d804f6caa8b3bd5e4de4b52f649cf73Jiri Slaby
32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize chips on Cyclom-Y card -- return number of valid
32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   chips (which is number of ports/4) */
320231b4f0a118a7ade8444059ec898af8f07de206e9Jiri Slabystatic unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
320331b4f0a118a7ade8444059ec898af8f07de206e9Jiri Slaby		int index)
32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
320502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned int chip_number;
320602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *base_addr;
320702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
320802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
320902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_HwReset is 0x1400 */
321002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
321102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Cy_ClrIntr is 0x1800 */
321202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(500L);
321302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
321415ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
321515ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox							chip_number++) {
321602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		base_addr =
321702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		    true_base_addr + (cy_chip_offset[chip_number] << index);
321802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		mdelay(1);
3219db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyCCR << index)) != 0x00) {
322002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*************
322102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
322202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			chip_number, (unsigned long)base_addr);
322302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			*************/
322402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
322502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
322602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
322702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyGFRCR << index), 0);
322802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		udelay(10L);
322902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
323002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* The Cyclom-16Y does not decode address bit 9 and therefore
323102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   cannot distinguish between references to chip 0 and a non-
323202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   existent chip 4.  If the preceding clearing of the supposed
323302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   chip 4 GFRCR register appears at chip 0, there is no chip 4
323402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   and this must be a Cyclom-16Y, not a Cyclom-32Ye.
323502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
3236db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (chip_number == 4 && readb(true_base_addr +
323702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(cy_chip_offset[0] << index) +
323802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(CyGFRCR << index)) == 0) {
323902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
324002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
324102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
324202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
324302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		mdelay(1);
324402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3245db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
324602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*
324702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   printk(" chip #%d at %#6lx is not responding ",
324802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   chip_number, (unsigned long)base_addr);
324902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   printk("(GFRCR stayed 0)\n",
325002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
325102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
325202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
3253db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
325402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				0x40) {
325502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/*
325602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			printk(" chip #%d at %#6lx is not valid (GFRCR == "
325702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					"%#2x)\n",
325802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					chip_number, (unsigned long)base_addr,
325902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby					base_addr[CyGFRCR<<index]);
326002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			 */
326102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			return chip_number;
326202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
326302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
3264db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
326502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* It is a CD1400 rev. J or later */
326602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* Impossible to reach 5ms with this chip.
326702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			   Changed to 2ms instead (f = 500 Hz). */
326802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
326902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		} else {
327002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* f = 200 Hz */
327102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
327202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
327402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/*
327502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
327602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		   chip_number, (unsigned long)base_addr,
3277db05c3b1ddaa06e658548f3d99e31a188b0b3bccJiri Slaby		   readb(base_addr+(CyGFRCR<<index)));
327802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		 */
327902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
328002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	return chip_number;
328102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cyy_init_card */
32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sets global variables and return the number of ISA boards found.
32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------
32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
328902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int __init cy_detect_isa(void)
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ISA
329202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned short cy_isa_irq, nboard;
329302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	void __iomem *cy_isa_address;
329402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	unsigned short i, j, cy_isa_nchan;
329502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	int isparam = 0;
32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
329702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	nboard = 0;
32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for module parameters */
330002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_CARDS; i++) {
330102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (maddr[i] || i) {
330202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			isparam = 1;
330302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_addresses[i] = maddr[i];
330402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
330502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (!maddr[i])
330602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			break;
33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
330902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* scan the address table probing for Cyclom-Y/ISA boards */
331002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_ISA_ADDRS; i++) {
331102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		unsigned int isa_address = cy_isa_addresses[i];
331215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox		if (isa_address == 0x0000)
3313096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* probe for CD1400... */
3316cd989b3a8c30148c872c7677c7a0415584f1658cAlan Cox		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
33173137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_isa_address == NULL) {
33183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
33193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"address\n");
33203137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			continue;
33213137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
332202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_isa_nchan = CyPORTS_PER_CHIP *
332302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cyy_init_card(cy_isa_address, 0);
332402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_isa_nchan == 0) {
33253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
332602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
332702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
33282090436357c20afad377a61c789f502c36d637deBartlomiej Zolnierkiewicz
3329196b3167efd13a02cdd34acc1a12316b9f45f41dRoel Kluin		if (isparam && i < NR_CARDS && irq[i])
333002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_irq = irq[i];
33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
333202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			/* find out the board's irq by probing */
333302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			cy_isa_irq = detect_isa_irq(cy_isa_address);
333402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (cy_isa_irq == 0) {
3335217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3336217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"IRQ could not be detected.\n",
333702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
333902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			continue;
334002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
334102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
334202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
3343217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3344217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"more channels are available. Change NR_PORTS "
3345217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"in cyclades.c and recompile kernel.\n",
334602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33473137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3348096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
334902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
335002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* fill the next cy_card structure available */
335102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		for (j = 0; j < NR_CARDS; j++) {
3352f742903424aae3fc7ea7079a3618d90634c0b301Jiri Slaby			if (cy_card[j].base_addr == NULL)
335302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				break;
335402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
335502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (j == NR_CARDS) {	/* no more cy_cards available */
3356217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3357217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"more cards can be used. Change NR_CARDS in "
3358217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"cyclades.c and recompile kernel.\n",
335902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				(unsigned long)cy_isa_address);
33603137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3361096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
336202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
336302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
336402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* allocate IRQ */
336502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		if (request_irq(cy_isa_irq, cyy_interrupt,
33669cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang				0, "Cyclom-Y", &cy_card[j])) {
3367217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3368217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"could not allocate IRQ#%d.\n",
3369217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				(unsigned long)cy_isa_address, cy_isa_irq);
33703137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
3371096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby			return nboard;
337202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
337302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
337402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		/* set cy_card */
337502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].base_addr = cy_isa_address;
337697e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_card[j].ctl_addr.p9050 = NULL;
337702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].irq = (int)cy_isa_irq;
337802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].bus_index = 0;
337902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_card[j].first_line = cy_next_channel;
3380963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3381963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[j].nports = cy_isa_nchan;
33823137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_init_card(&cy_card[j])) {
33833137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			cy_card[j].base_addr = NULL;
33843137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			free_irq(cy_isa_irq, &cy_card[j]);
33853137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			iounmap(cy_isa_address);
33863137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			continue;
33873137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
338802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		nboard++;
338902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3390217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3391217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			"%d channels starting from port %d\n",
339202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			j + 1, (unsigned long)cy_isa_address,
339302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
3394217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			cy_isa_irq, cy_isa_nchan, cy_next_channel);
3395217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
33966ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby		for (j = cy_next_channel;
33976ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby				j < cy_next_channel + cy_isa_nchan; j++)
33986ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby			tty_register_device(cy_serial_driver, j, NULL);
339902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		cy_next_channel += cy_isa_nchan;
340002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
3401096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return nboard;
34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3403096dcfce39f952292b019a2c42c241782c9ca226Jiri Slaby	return 0;
340402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_ISA */
340502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_detect_isa */
34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
340758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby#ifdef CONFIG_PCI
3408054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3409054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3410054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int a;
3411054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3412054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (a = 0; a < size && *str; a++, str++)
3413054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (*str & 0x80)
3414054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3415054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3416054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (; a < size; a++, str++)
3417054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (*str)
3418054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3419054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3420054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return 0;
3421054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3422054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3423f61e761e2128c7ca0d044651b18928991ab03be2David Woodhousestatic inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3424054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		unsigned int size)
3425054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3426054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (; size > 0; size--) {
3427054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(fpga, *data++);
3428054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(10);
3429054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3430054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3431054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3432054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic void __devinit plx_init(struct pci_dev *pdev, int irq,
3433054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		struct RUNTIME_9060 __iomem *addr)
34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
343502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Reset PLX */
3436054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
343702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(100L);
3438054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
343902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
344002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Reload Config. Registers from EEPROM */
3441054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
344202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	udelay(100L);
3443054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3444054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3445054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3446054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3447054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 * registers. This will remain here until we find a permanent fix.
3448054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 */
3449054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3450054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3451054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3452054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic int __devinit __cyz_load_fw(const struct firmware *fw,
3453054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		const char *name, const u32 mailbox, void __iomem *base,
3454054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		void __iomem *fpga)
3455054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3456f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const void *ptr = fw->data;
3457f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_header *h = ptr;
3458f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_config *c, *cs;
3459f61e761e2128c7ca0d044651b18928991ab03be2David Woodhouse	const struct zfile_block *b, *bs;
3460054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int a, tmp, len = fw->size;
3461054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#define BAD_FW KERN_ERR "Bad firmware: "
3462054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (len < sizeof(*h)) {
3463054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3464054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3465054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3466054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3467054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cs = ptr + h->config_offset;
3468054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	bs = ptr + h->block_offset;
3469054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3470054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if ((void *)(cs + h->n_config) > ptr + len ||
3471054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			(void *)(bs + h->n_blocks) > ptr + len) {
3472054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "too short");
3473054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return  -EINVAL;
3474054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3475054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3476054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3477054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			cyc_isfwstr(h->date, sizeof(h->date))) {
3478054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "bad formatted header string\n");
3479054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3480054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3481054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3482054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (strncmp(name, h->name, sizeof(h->name))) {
3483054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3484054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3485054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3486054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3487054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	tmp = 0;
3488054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (c = cs; c < cs + h->n_config; c++) {
3489054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		for (a = 0; a < c->n_blocks; a++)
3490054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (c->block_list[a] > h->n_blocks) {
3491054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				printk(BAD_FW "bad block ref number in cfgs\n");
3492054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				return -EINVAL;
3493054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			}
3494054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3495054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			tmp++;
3496054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3497054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (!tmp) {
3498054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		printk(BAD_FW "nothing appropriate\n");
3499054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		return -EINVAL;
3500054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3501054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3502054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (b = bs; b < bs + h->n_blocks; b++)
3503054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (b->file_offset + b->size > len) {
3504054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			printk(BAD_FW "bad block data offset\n");
3505054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			return -EINVAL;
3506054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3507054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3508054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* everything is OK, let's seek'n'load it */
3509054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (c = cs; c < cs + h->n_config; c++)
3510054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (c->mailbox == mailbox && c->function == 0)
3511054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			break;
3512054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3513054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	for (a = 0; a < c->n_blocks; a++) {
3514054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		b = &bs[c->block_list[a]];
3515054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (b->type == ZBLOCK_FPGA) {
3516054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (fpga != NULL)
3517054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				cyz_fpga_copy(fpga, ptr + b->file_offset,
3518054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby						b->size);
3519054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		} else {
3520054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			if (base != NULL)
3521054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				memcpy_toio(base + b->ram_offset,
3522054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					       ptr + b->file_offset, b->size);
3523054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3524054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3525054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby#undef BAD_FW
3526054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return 0;
3527054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby}
3528054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3529054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabystatic int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3530054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3531054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby{
3532054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	const struct firmware *fw;
3533054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3534054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct CUSTOM_REG __iomem *cust = base_addr;
3535054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	struct ZFW_CTRL __iomem *pt_zfwctrl;
3536c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby	void __iomem *tmp;
3537963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	u32 mailbox, status, nchan;
3538054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	unsigned int i;
3539054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	int retval;
3540054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3541054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3542054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (retval) {
3543054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_err(&pdev->dev, "can't get firmware\n");
3544054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3545054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3546054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3547054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* Check whether the firmware is already loaded and running. If
3548054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   positive, skip this board */
35492693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3550054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		u32 cntval = readl(base_addr + 0x190);
3551054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3552054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(100);
3553054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (cntval != readl(base_addr + 0x190)) {
3554054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			/* FW counter is working, FW is running */
3555054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3556054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"Skipping board.\n");
3557054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = 0;
3558054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
3559054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3560054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3561054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3562054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* start boot */
3563054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3564054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			~0x00030800UL);
3565054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3566054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	mailbox = readl(&ctl_addr->mail_box_0);
3567054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
35682693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3569054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* stops CPU and set window to beginning of RAM */
3570054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3571054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&cust->cpu_stop, 0);
3572054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3573054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		udelay(100);
3574054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3575054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3576054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	plx_init(pdev, irq, ctl_addr);
3577054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3578054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (mailbox != 0) {
3579054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* load FPGA */
3580054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3581054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				base_addr);
3582054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (retval)
3583054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
35842693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!__cyz_fpga_loaded(ctl_addr)) {
3585054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "fw upload successful, but fw is "
3586054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"not loaded\n");
3587054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err_rel;
3588054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3589054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3590054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3591054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* stops CPU and set window to beginning of RAM */
3592054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3593054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&cust->cpu_stop, 0);
3594054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3595054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	udelay(100);
3596054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3597054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* clear memory */
3598c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3599054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writeb(tmp, 255);
3600054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (mailbox != 0) {
3601054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* set window to last 512K of RAM */
3602054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
3603c4923b4f13156455a9e84f0b918866aef300cc57Jiri Slaby		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3604054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			cy_writeb(tmp, 255);
3605054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		/* set window to beginning of RAM */
3606054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3607054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3608054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3609054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3610054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	release_firmware(fw);
3611054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (retval)
3612054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3613054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3614054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/* finish boot and start boards */
3615054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3616054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&cust->cpu_start, 0);
3617054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3618054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	i = 0;
3619054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3620054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		msleep(100);
3621054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	if (status != ZFIRM_ID) {
3622054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (status == ZFIRM_HLT) {
3623054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "you need an external power supply "
3624054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"for this number of ports. Firmware halted and "
3625054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"board reset.\n");
3626054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = -EIO;
3627054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err;
3628054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3629054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3630054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"some more time\n", status);
3631054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3632054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				i++ < 200)
3633054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			msleep(100);
3634054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		if (status != ZFIRM_ID) {
3635054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_err(&pdev->dev, "Board not started in 20 seconds! "
3636054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					"Giving up. (fid->signature = 0x%x)\n",
3637054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby					status);
3638054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			dev_info(&pdev->dev, "*** Warning ***: if you are "
3639054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"upgrading the FW, please power cycle the "
3640054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"system before loading the new FW to the "
3641054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"Cyclades-Z.\n");
3642054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
36432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby			if (__cyz_fpga_loaded(ctl_addr))
3644054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				plx_init(pdev, irq, ctl_addr);
3645054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3646054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			retval = -EIO;
3647054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			goto err;
3648054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		}
3649054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3650054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				i / 10);
3651054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3652054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3653054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3654054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3655054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3656054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			base_addr + readl(&fid->zfwctrl_addr));
3657054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3658963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3659054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
3660963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3661054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3662963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	if (nchan == 0) {
3663054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3664054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			"check the connection between the Z host card and the "
3665054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			"serial expanders.\n");
3666054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
36672693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (__cyz_fpga_loaded(ctl_addr))
3668054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			plx_init(pdev, irq, ctl_addr);
3669054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3670054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		dev_info(&pdev->dev, "Null number of ports detected. Board "
3671054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby				"reset.\n");
3672054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		retval = 0;
3673054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		goto err;
3674054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	}
3675054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3676054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3677054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3678054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3679054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	/*
3680054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   Early firmware failed to start looking for commands.
3681054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	   This enables firmware interrupts for those commands.
3682054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	 */
3683054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3684054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			(1 << 17));
3685054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3686054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby			0x00030800UL);
3687054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby
3688963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	return nchan;
3689054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyerr_rel:
3690054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	release_firmware(fw);
3691054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slabyerr:
3692054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby	return retval;
36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
369558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slabystatic int __devinit cy_pci_probe(struct pci_dev *pdev,
369658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		const struct pci_device_id *ent)
36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36983137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	void __iomem *addr0 = NULL, *addr2 = NULL;
36993137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	char *card_name = NULL;
3700101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby	u32 uninitialized_var(mailbox);
37013137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	unsigned int device_id, nchan = 0, card_no, i;
37023137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	unsigned char plx_ver;
37033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	int retval, irq;
370402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
370558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	retval = pci_enable_device(pdev);
370658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	if (retval) {
370758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		dev_err(&pdev->dev, "cannot enable device\n");
37083137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err;
370958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	}
37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	/* read PCI configuration area */
37123137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	irq = pdev->irq;
371358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby#if defined(__alpha__)
37163137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
37173137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
37183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"addresses on Alpha systems.\n");
37193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = -EIO;
37203137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37213137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby#endif
37233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
37243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
37253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"addresses\n");
37263137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = -EIO;
37273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
37313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
37323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				"it...\n");
37333137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		pdev->resource[2].flags &= ~IORESOURCE_IO;
37343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = pci_request_regions(pdev, "cyclades");
37373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (retval) {
37383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "failed to reserve resources\n");
37393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_dis;
37403137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
37413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
37423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = -EIO;
374358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
374458936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
37453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		card_name = "Cyclom-Y";
37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
374724e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
374824e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Yctl);
37493137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr0 == NULL) {
37503137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap ctl region\n");
37513137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_reg;
375258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
375324e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
375424e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Ywin);
37553137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr2 == NULL) {
37563137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap base region\n");
37573137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
375858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37603137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
37613137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (nchan == 0) {
3762217191910c0286e0b3c7e3011630273695253da3Jiri Slaby			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3763217191910c0286e0b3c7e3011630273695253da3Jiri Slaby					"Serial-Modules\n");
3764c847d47cb7b2fa78b17c9e17ed3fbd010ee3d3caAndrew Morton			goto err_unmap;
376558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
376658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
37673137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		struct RUNTIME_9060 __iomem *ctl_addr;
3768217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
376924e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
377024e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				CyPCI_Zctl);
37713137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr0 == NULL) {
37723137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap ctl region\n");
37733137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_reg;
37743137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
377558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
377658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		/* Disable interrupts on the PLX before resetting it */
377797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writew(&ctl_addr->intr_ctrl_stat,
377897e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
377958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
3780054f5b0aaa58dfc841635e52b6c1cc2b14ec37fcJiri Slaby		plx_init(pdev, irq, addr0);
378102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3782101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		mailbox = readl(&ctl_addr->mail_box_0);
378358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
378424e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
378524e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
37863137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (addr2 == NULL) {
37873137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "can't remap base region\n");
37883137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
378958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
379058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
379158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		if (mailbox == ZE_V1) {
37923137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			card_name = "Cyclades-Ze";
379358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		} else {
37943137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			card_name = "Cyclades-8Zo";
37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CY_PCI_DEBUG
37963137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			if (mailbox == ZO_V1) {
37973137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
37983137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
37993137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"id %lx, ver %lx\n", (ulong)(0xff &
38003137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					readl(&((struct CUSTOM_REG *)addr2)->
38013137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby						fpga_id)), (ulong)(0xff &
38023137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					readl(&((struct CUSTOM_REG *)addr2)->
38033137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby						fpga_version)));
38043137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
38053137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			} else {
38063137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
38073137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					"Cyclades-Z board.  FPGA not loaded\n");
38083137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			}
38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
38103137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			/* The following clears the firmware id word.  This
38113137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			   ensures that the driver will not attempt to talk to
38123137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			   the board until it has been properly initialized.
38133137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			 */
38143137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
38153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				cy_writel(addr2 + ID_ADDRESS, 0L);
381658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
3817ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby
3818ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby		retval = cyz_load_fw(pdev, addr2, addr0, irq);
3819963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		if (retval <= 0)
3820ace08c3c4403140e5ce82116c8f2acb38f58f61dJiri Slaby			goto err_unmap;
3821963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		nchan = retval;
38223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38233137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if ((cy_next_channel + nchan) > NR_PORTS) {
38253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
38263137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"channels are available. Change NR_PORTS in "
38273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"cyclades.c and recompile kernel.\n");
38283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_unmap;
38293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38303137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	/* fill the next cy_card structure available */
38313137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	for (card_no = 0; card_no < NR_CARDS; card_no++) {
38323137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (cy_card[card_no].base_addr == NULL)
38333137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
38343137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38353137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (card_no == NR_CARDS) {	/* no more cy_cards available */
38363137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
38373137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"more cards can be used. Change NR_CARDS in "
38383137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			"cyclades.c and recompile kernel.\n");
38393137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_unmap;
38403137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
38413137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38423137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
38433137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
38443137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		/* allocate IRQ */
38453137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		retval = request_irq(irq, cyy_interrupt,
38463137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
38473137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (retval) {
38483137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			dev_err(&pdev->dev, "could not allocate IRQ\n");
38493137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			goto err_unmap;
385058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
3851963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby		cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
38523137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	} else {
3853f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3854f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		struct ZFW_CTRL __iomem *zfw_ctrl;
3855f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3856f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3857f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby
3858101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		cy_card[card_no].hw_ver = mailbox;
3859101b81590d8df0a74c33cf739886247c0a13f4afJiri Slaby		cy_card[card_no].num_chips = (unsigned int)-1;
3860f0eefdc30e55e761facf645bd1be1339b21c30e6Jiri Slaby		cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
386102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#ifdef CONFIG_CYZ_INTR
386258936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		/* allocate IRQ only if board has an IRQ */
38633137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		if (irq != 0 && irq != 255) {
38643137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			retval = request_irq(irq, cyz_interrupt,
386558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby					IRQF_SHARED, "Cyclades-Z",
38663137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby					&cy_card[card_no]);
386758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby			if (retval) {
3868217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				dev_err(&pdev->dev, "could not allocate IRQ\n");
38693137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby				goto err_unmap;
387002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			}
387158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby		}
387202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby#endif				/* CONFIG_CYZ_INTR */
38733137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	}
387402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
38753137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	/* set cy_card */
38763137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].base_addr = addr2;
387797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	cy_card[card_no].ctl_addr.p9050 = addr0;
38783137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].irq = irq;
38793137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].bus_index = 1;
38803137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].first_line = cy_next_channel;
3881963118eef9e6706e2b5356309fb0cdd9c9eba81dJiri Slaby	cy_card[card_no].nports = nchan;
38823137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	retval = cy_init_card(&cy_card[card_no]);
38833137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (retval)
38843137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		goto err_null;
388558936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
38863137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_set_drvdata(pdev, &cy_card[card_no]);
388758936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
38883137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
38893137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
38903137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		/* enable interrupts in the PCI interface */
38913137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
38923137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		switch (plx_ver) {
38933137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9050:
38943137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			cy_writeb(addr0 + 0x4c, 0x43);
38953137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
38963137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
38973137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9060:
38983137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		case PLX_9080:
38993137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		default:	/* Old boards, use PLX_9060 */
390097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		{
390197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			struct RUNTIME_9060 __iomem *ctl_addr = addr0;
390297e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			plx_init(pdev, irq, ctl_addr);
390397e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			cy_writew(&ctl_addr->intr_ctrl_stat,
390497e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
39053137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby			break;
39063137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		}
390797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		}
390858936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	}
390958936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39103137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
39113137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
39123137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
39133137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby		tty_register_device(cy_serial_driver, i, &pdev->dev);
39143137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_next_channel += nchan;
39153137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby
391658936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby	return 0;
39173137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_null:
39183137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	cy_card[card_no].base_addr = NULL;
39193137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	free_irq(irq, &cy_card[card_no]);
39203137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_unmap:
392124e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby	iounmap(addr0);
39223137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	if (addr2)
392324e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby		iounmap(addr2);
39243137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_reg:
39253137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_release_regions(pdev);
39263137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr_dis:
39273137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	pci_disable_device(pdev);
39283137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slabyerr:
39293137553d3f78f12a077459ee59e4b17f8db9f0cfJiri Slaby	return retval;
393058936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby}
393158936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby
39326747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slabystatic void __devexit cy_pci_remove(struct pci_dev *pdev)
393358936d8d944e27b75c99b1c59cfeea3f253b03cbJiri Slaby{
393438d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3935f3851e73ecdd070bc379677ed7aad958446f26e7Jiri Slaby	unsigned int i;
393638d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
393785c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby	/* non-Z with old PLX */
39382693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
3939c2ad4c75154d98c07d30493e4906e1cd0a9162a5Jiri Slaby			PLX_9050)
394097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
394185c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby	else
394285c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby#ifndef CONFIG_CYZ_INTR
39432693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		if (!cy_is_Z(cinfo))
394485c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby#endif
394597e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
394697e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
394797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			~0x0900);
394885c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby
394924e6fd4cdc841176ca3713fddc9a02bd128b1191Jiri Slaby	iounmap(cinfo->base_addr);
395097e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby	if (cinfo->ctl_addr.p9050)
395197e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby		iounmap(cinfo->ctl_addr.p9050);
395238d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	if (cinfo->irq
395338d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby#ifndef CONFIG_CYZ_INTR
39542693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby		&& !cy_is_Z(cinfo)
395538d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby#endif /* CONFIG_CYZ_INTR */
395638d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby		)
395738d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby		free_irq(cinfo->irq, cinfo);
395838d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	pci_release_regions(pdev);
395938d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
396038d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby	cinfo->base_addr = NULL;
39616ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby	for (i = cinfo->first_line; i < cinfo->first_line +
39626ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby			cinfo->nports; i++)
39636ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby		tty_unregister_device(cy_serial_driver, i);
3964dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	cinfo->nports = 0;
3965dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	kfree(cinfo->ports);
396638d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby}
396738d090932564140454e5a0bc915beca07d8a65a0Jiri Slaby
39686747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slabystatic struct pci_driver cy_pci_driver = {
39696747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.name = "cyclades",
39706747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.id_table = cy_pci_dev_id,
39716747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.probe = cy_pci_probe,
39726747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	.remove = __devexit_p(cy_pci_remove)
39736747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby};
39746747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
39756747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby
3976444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic int cyclades_proc_show(struct seq_file *m, void *v)
39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
397802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	struct cyclades_port *info;
3979dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	unsigned int i, j;
398002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	__u32 cur_jifs = jiffies;
398102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
3982444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
398302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby			"IdleIn  Overruns  Ldisc\n");
398402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
398502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Output one line for each known port */
3986dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	for (i = 0; i < NR_CARDS; i++)
3987dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		for (j = 0; j < cy_card[i].nports; j++) {
3988dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			info = &cy_card[i].ports[j];
3989dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby
3990d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			if (info->port.count) {
3991d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				/* XXX is the ldisc num worth this? */
3992d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				struct tty_struct *tty;
3993d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				struct tty_ldisc *ld;
3994d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				int num = 0;
3995d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				tty = tty_port_tty_get(&info->port);
3996d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				if (tty) {
3997d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					ld = tty_ldisc_ref(tty);
3998d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					if (ld) {
3999d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby						num = ld->ops->num;
4000d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby						tty_ldisc_deref(ld);
4001d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					}
4002d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					tty_kref_put(tty);
4003d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby				}
4004444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan				seq_printf(m, "%3d %8lu %10lu %8lu "
4005d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					"%10lu %8lu %9lu %6d\n", info->line,
4006dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.in_use) /
4007dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.xmit_bytes,
4008dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.xmit_idle)/
4009dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.recv_bytes,
4010dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					(cur_jifs - info->idle_stats.recv_idle)/
4011dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					HZ, info->idle_stats.overruns,
4012d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby					num);
4013d13549f804d2965a9f279a8ff867f35d949572c8Jiri Slaby			} else
4014444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan				seq_printf(m, "%3d %8lu %10lu %8lu "
4015dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					"%10lu %8lu %9lu %6ld\n",
4016dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
401702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
4018444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	return 0;
4019444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan}
4020444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan
4021444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic int cyclades_proc_open(struct inode *inode, struct file *file)
4022444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan{
4023444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	return single_open(file, cyclades_proc_show, NULL);
40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4026444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyanstatic const struct file_operations cyclades_proc_fops = {
4027444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.owner		= THIS_MODULE,
4028444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.open		= cyclades_proc_open,
4029444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.read		= seq_read,
4030444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.llseek		= seq_lseek,
4031444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.release	= single_release,
4032444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan};
4033444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan
40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The serial driver boot-time initialization code!
40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Hardware I/O ports are mapped to character special devices on a
40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    first found, first allocated manner.  That is, this code searches
40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for Cyclom cards in the system.  As each is found, it is probed
40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    to discover how many chips (and thus how many ports) are present.
40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    These ports are mapped to the tty ports 32 and upward in monotonic
40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    fashion.  If an 8-port card is replaced with a 16-port card, the
40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    port mapping on a following card will shift.
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This approach is different from what is used in the other serial
40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    device driver because the Cyclom is more properly a multiplexer,
40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    not just an aggregation of serial ports on one card.
40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    If there are more cards with more ports than have been
40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    statically allocated above, a warning is printed and the
40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    extra ports are ignored.
40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4052b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations cy_ops = {
405302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.open = cy_open,
405402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.close = cy_close,
405502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.write = cy_write,
405602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.put_char = cy_put_char,
405702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.flush_chars = cy_flush_chars,
405802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.write_room = cy_write_room,
405902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.chars_in_buffer = cy_chars_in_buffer,
406002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.flush_buffer = cy_flush_buffer,
406102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.ioctl = cy_ioctl,
406202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.throttle = cy_throttle,
406302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.unthrottle = cy_unthrottle,
406402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.set_termios = cy_set_termios,
406502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.stop = cy_stop,
406602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.start = cy_start,
406702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.hangup = cy_hangup,
406802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.break_ctl = cy_break,
406902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.wait_until_sent = cy_wait_until_sent,
407002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.tiocmget = cy_tiocmget,
407102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	.tiocmset = cy_tiocmset,
40720587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox	.get_icount = cy_get_icount,
4073444697d61b6d5ae43b317d259db7c362c9d3756aAlexey Dobriyan	.proc_fops = &cyclades_proc_fops,
40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
407602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic int __init cy_init(void)
40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4078dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	unsigned int nboards;
40799dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	int retval = -ENOMEM;
408002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
408102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver = alloc_tty_driver(NR_PORTS);
408202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	if (!cy_serial_driver)
40839dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		goto err;
4084217191910c0286e0b3c7e3011630273695253da3Jiri Slaby
408564a14b51bed6427a2e6d68ed687027f065f5a156Michal Marek	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
408602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
408702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* Initialize the tty_driver structure */
408802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
408902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->driver_name = "cyclades";
409002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->name = "ttyC";
409102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->major = CYCLADES_MAJOR;
409202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->minor_start = 0;
409302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
409402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
409502f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->init_termios = tty_std_termios;
409602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	cy_serial_driver->init_termios.c_cflag =
409702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
40986ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
409902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	tty_set_operations(cy_serial_driver, &cy_ops);
410002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41019dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	retval = tty_register_driver(cy_serial_driver);
41029dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	if (retval) {
41039dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
41049dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby		goto err_frtty;
41059dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	}
410602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
410702f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* the code below is responsible to find the boards. Each different
410802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   type of board has its own detection routine. If a board is found,
410902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   the next cy_card structure available is set by the detection
411002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   routine. These functions are responsible for checking the
411102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   availability of cy_card and cy_port data structures and updating
411202f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	   the cy_next_channel. */
411302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
411402f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* look for isa boards */
411514a55a6789d8409e58329310f9a18fc141deb4c2Jiri Slaby	nboards = cy_detect_isa();
411602f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby
41176747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#ifdef CONFIG_PCI
411802f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	/* look for pci boards */
41196747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	retval = pci_register_driver(&cy_pci_driver);
4120d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl	if (retval && !nboards) {
4121d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl		tty_unregister_driver(cy_serial_driver);
4122d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl		goto err_frtty;
4123d941ea7d496db914205c3872942fd1ff0e7dccefJesper Juhl	}
41246747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
41259dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby
41269dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	return 0;
41279dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slabyerr_frtty:
41289dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	put_tty_driver(cy_serial_driver);
41299dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slabyerr:
41309dacf3b2f0cc657a5621e7f6d67ed27ce598f405Jiri Slaby	return retval;
413102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby}				/* cy_init */
41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
413302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slabystatic void __exit cy_cleanup_module(void)
41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4135dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby	struct cyclades_card *card;
413665f76a82ec7a0374fad85211535330e203740475Jiri Slaby	unsigned int i, e1;
41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
4139b70509066cba24067757f1422c899c43e433429dJiri Slaby	del_timer_sync(&cyz_timerlist);
41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_CYZ_INTR */
41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
414215ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	e1 = tty_unregister_driver(cy_serial_driver);
414315ed6cc0ba6b7beaf31c6756b0c838188800051bAlan Cox	if (e1)
4144217191910c0286e0b3c7e3011630273695253da3Jiri Slaby		printk(KERN_ERR "failed to unregister Cyclades serial "
4145217191910c0286e0b3c7e3011630273695253da3Jiri Slaby				"driver(%d)\n", e1);
41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41476747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#ifdef CONFIG_PCI
41486747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby	pci_unregister_driver(&cy_pci_driver);
41496747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby#endif
41506747cd93f3ed6e60b4e851b5985d038ac0b88742Jiri Slaby
415102f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	for (i = 0; i < NR_CARDS; i++) {
4152dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		card = &cy_card[i];
4153dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby		if (card->base_addr) {
415485c93fa95b8fa8dabc6d14c77eb9a9c2e9753eccJiri Slaby			/* clear interrupt */
4155dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4156dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			iounmap(card->base_addr);
415797e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby			if (card->ctl_addr.p9050)
415897e87f8ebe978e881c7325ba490574bd5500b133Jiri Slaby				iounmap(card->ctl_addr.p9050);
4159dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			if (card->irq
41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_CYZ_INTR
41612693f485c22d18474c077f12fd0f797ee8679b33Jiri Slaby				&& !cy_is_Z(card)
41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_CYZ_INTR */
416302f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby				)
4164dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby				free_irq(card->irq, card);
416565f76a82ec7a0374fad85211535330e203740475Jiri Slaby			for (e1 = card->first_line; e1 < card->first_line +
4166dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby					card->nports; e1++)
41676ad1ccc196f76833f41b187e01a28a024fe11f8bJiri Slaby				tty_unregister_device(cy_serial_driver, e1);
4168dd025c0c7a047b1be7dfaa4061368b4783d89ebbJiri Slaby			kfree(card->ports);
416902f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby		}
417002f1175c8737802b5609aa2c0b1fb3ca2c23069fJiri Slaby	}
4171f2462bfe558559c9fbc4ef60812d5df30ccb01f6Jiri Slaby
4172f2462bfe558559c9fbc4ef60812d5df30ccb01f6Jiri Slaby	put_tty_driver(cy_serial_driver);
41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cy_cleanup_module */
41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(cy_init);
41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cy_cleanup_module);
41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
4179c8e1693a4f63e317966f3dfe8f815eda95e26610Jiri SlabyMODULE_VERSION(CY_VERSION);
41809f56fad741163fe2111cbbcfb7ff795ebdabdab1Scott James RemnantMODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4181e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("cyzfirm.bin");
4182