cyclades.c 110.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11
#undef	BLOCKMOVE
#define	Z_WAKE
#undef	Z_EXT_CHARS_IN_BUFFER

/*
 * This file contains the driver for the Cyclades async multiport
 * serial boards.
 *
 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
 *
J
Jiri Slaby 已提交
12
 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
L
Linus Torvalds 已提交
13 14 15 16 17
 *
 * Much of the design and some of the code came from serial.c
 * which was copyright (C) 1991, 1992  Linus Torvalds.  It was
 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
 * and then fixed as suggested by Michael K. Johnson 12/12/92.
18
 * Converted to pci probing and cleaned up by Jiri Slaby.
L
Linus Torvalds 已提交
19 20 21
 *
 */

J
Jiri Slaby 已提交
22
#define CY_VERSION	"2.6"
J
Jiri Slaby 已提交
23

L
Linus Torvalds 已提交
24 25 26 27
/* If you need to install more boards than NR_CARDS, change the constant
   in the definition below. No other change is necessary to support up to
   eight boards. Beyond that you'll have to extend cy_isa_addresses. */

28
#define NR_CARDS	4
L
Linus Torvalds 已提交
29 30 31 32 33 34

/*
   If the total number of ports is larger than NR_PORTS, change this
   constant in the definition below. No other change is necessary to
   support more boards/ports. */

35
#define NR_PORTS	256
L
Linus Torvalds 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#define ZO_V1	0
#define ZO_V2	1
#define ZE_V1	2

#define	SERIAL_PARANOIA_CHECK
#undef	CY_DEBUG_OPEN
#undef	CY_DEBUG_THROTTLE
#undef	CY_DEBUG_OTHER
#undef	CY_DEBUG_IO
#undef	CY_DEBUG_COUNT
#undef	CY_DEBUG_DTR
#undef	CY_DEBUG_INTERRUPTS
#undef	CY_16Y_HACK
#undef	CY_ENABLE_MONITORING
#undef	CY_PCI_DEBUG

/*
A
Alan Cox 已提交
54
 * Include section
L
Linus Torvalds 已提交
55 56 57 58 59 60 61 62
 */
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
A
Alan Cox 已提交
63
#include <linux/tty_flip.h>
L
Linus Torvalds 已提交
64 65 66 67 68 69 70 71 72 73 74 75
#include <linux/serial.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/cyclades.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
76
#include <linux/firmware.h>
77
#include <linux/device.h>
78
#include <linux/slab.h>
L
Linus Torvalds 已提交
79

A
Alan Cox 已提交
80 81
#include <linux/io.h>
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
82 83 84 85 86 87

#include <linux/kernel.h>
#include <linux/pci.h>

#include <linux/stat.h>
#include <linux/proc_fs.h>
88
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
89

90
static void cy_send_xchar(struct tty_struct *tty, char ch);
L
Linus Torvalds 已提交
91 92 93 94 95 96 97

#ifndef SERIAL_XMIT_SIZE
#define	SERIAL_XMIT_SIZE	(min(PAGE_SIZE, 4096))
#endif

#define STD_COM_FLAGS (0)

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/* firmware stuff */
#define ZL_MAX_BLOCKS	16
#define DRIVER_VERSION	0x02010203
#define RAM_SIZE 0x80000

enum zblock_type {
	ZBLOCK_PRG = 0,
	ZBLOCK_FPGA = 1
};

struct zfile_header {
	char name[64];
	char date[32];
	char aux[32];
	u32 n_config;
	u32 config_offset;
	u32 n_blocks;
	u32 block_offset;
	u32 reserved[9];
} __attribute__ ((packed));

struct zfile_config {
	char name[64];
	u32 mailbox;
	u32 function;
	u32 n_blocks;
	u32 block_list[ZL_MAX_BLOCKS];
} __attribute__ ((packed));

struct zfile_block {
	u32 type;
	u32 file_offset;
	u32 ram_offset;
	u32 size;
} __attribute__ ((packed));

L
Linus Torvalds 已提交
134 135 136 137 138 139 140 141 142 143 144
static struct tty_driver *cy_serial_driver;

#ifdef CONFIG_ISA
/* This is the address lookup table. The driver will probe for
   Cyclom-Y/ISA boards at all addresses in here. If you want the
   driver to probe addresses at a different address, add it to
   this table.  If the driver is probing some other board and
   causing problems, remove the offending address from this table.
*/

static unsigned int cy_isa_addresses[] = {
145 146 147 148 149 150 151 152 153
	0xD0000,
	0xD2000,
	0xD4000,
	0xD6000,
	0xD8000,
	0xDA000,
	0xDC000,
	0xDE000,
	0, 0, 0, 0, 0, 0, 0, 0
L
Linus Torvalds 已提交
154
};
155

156
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
L
Linus Torvalds 已提交
157

158 159
static long maddr[NR_CARDS];
static int irq[NR_CARDS];
L
Linus Torvalds 已提交
160 161 162 163

module_param_array(maddr, long, NULL, 0);
module_param_array(irq, int, NULL, 0);

164
#endif				/* CONFIG_ISA */
L
Linus Torvalds 已提交
165 166 167 168 169 170

/* This is the per-card data structure containing address, irq, number of
   channels, etc. This driver supports a maximum of NR_CARDS cards.
*/
static struct cyclades_card cy_card[NR_CARDS];

171
static int cy_next_channel;	/* next minor available */
L
Linus Torvalds 已提交
172 173 174 175

/*
 * This is used to look up the divisor speeds and the timeouts
 * We're normally limited to 15 distinct baud rates.  The extra
A
Alan Cox 已提交
176
 * are accessed via settings in info->port.flags.
L
Linus Torvalds 已提交
177 178 179 180 181
 *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
 *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
 *                                               HI            VHI
 *     20
 */
J
Jiri Slaby 已提交
182
static const int baud_table[] = {
183 184 185 186 187
	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
	1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
	230400, 0
};

J
Jiri Slaby 已提交
188
static const char baud_co_25[] = {	/* 25 MHz clock option table */
189 190 191 192 193 194
	/* value =>    00    01   02    03    04 */
	/* divide by    8    32   128   512  2048 */
	0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
	0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

J
Jiri Slaby 已提交
195
static const char baud_bpr_25[] = {	/* 25 MHz baud rate period table */
196 197 198 199
	0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
	0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
};

J
Jiri Slaby 已提交
200
static const char baud_co_60[] = {	/* 60 MHz clock option table (CD1400 J) */
201 202 203 204 205 206 207
	/* value =>    00    01   02    03    04 */
	/* divide by    8    32   128   512  2048 */
	0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
	0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00
};

J
Jiri Slaby 已提交
208
static const char baud_bpr_60[] = {	/* 60 MHz baud rate period table (CD1400 J) */
209 210 211 212 213
	0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
	0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
	0x21
};

J
Jiri Slaby 已提交
214
static const char baud_cor3[] = {	/* receive threshold */
215 216 217 218
	0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
	0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
	0x07
};
L
Linus Torvalds 已提交
219 220 221

/*
 * The Cyclades driver implements HW flow control as any serial driver.
A
Alan Cox 已提交
222 223 224 225 226 227
 * The cyclades_port structure member rflow and the vector rflow_thr
 * allows us to take advantage of a special feature in the CD1400 to avoid
 * data loss even when the system interrupt latency is too high. These flags
 * are to be used only with very special applications. Setting these flags
 * requires the use of a special cable (DTR and RTS reversed). In the new
 * CD1400-based boards (rev. 6.00 or later), there is no need for special
L
Linus Torvalds 已提交
228 229 230
 * cables.
 */

J
Jiri Slaby 已提交
231
static const char rflow_thr[] = {	/* rflow threshold */
232 233 234 235
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
	0x0a
};
L
Linus Torvalds 已提交
236 237 238 239

/*  The Cyclom-Ye has placed the sequential chips in non-sequential
 *  address order.  This look-up table overcomes that problem.
 */
240
static const unsigned int cy_chip_offset[] = { 0x0000,
241 242 243 244 245 246 247 248
	0x0400,
	0x0800,
	0x0C00,
	0x0200,
	0x0600,
	0x0A00,
	0x0E00
};
L
Linus Torvalds 已提交
249 250 251 252

/* PCI related definitions */

#ifdef CONFIG_PCI
J
Jiri Slaby 已提交
253
static const struct pci_device_id cy_pci_dev_id[] = {
A
Alan Cox 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
	/* PCI < 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
	/* PCI > 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
	/* 4Y PCI < 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
	/* 4Y PCI > 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
	/* 8Y PCI < 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
	/* 8Y PCI > 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
	/* Z PCI < 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
	/* Z PCI > 1Mb */
	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
270
	{ }			/* end of table */
271
};
272
MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
L
Linus Torvalds 已提交
273 274 275
#endif

static void cy_start(struct tty_struct *);
J
Jiri Slaby 已提交
276
static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
K
Klaus Kudielka 已提交
277
static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
L
Linus Torvalds 已提交
278 279
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
280
#endif				/* CONFIG_ISA */
L
Linus Torvalds 已提交
281 282 283 284 285 286 287

#ifndef CONFIG_CYZ_INTR
static void cyz_poll(unsigned long);

/* The Cyclades-Z polling cycle is defined by this variable */
static long cyz_polling_cycle = CZ_DEF_POLL;

288
static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
L
Linus Torvalds 已提交
289

290
#else				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
291 292
static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
293
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
294

295 296 297 298 299 300 301 302 303 304 305 306 307 308
static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
{
	struct cyclades_card *card = port->card;

	cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
}

static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
{
	struct cyclades_card *card = port->card;

	return readb(port->u.cyy.base_addr + (reg << card->bus_index));
}

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
static inline bool cy_is_Z(struct cyclades_card *card)
{
	return card->num_chips == (unsigned int)-1;
}

static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
{
	return readl(&ctl_addr->init_ctrl) & (1 << 17);
}

static inline bool cyz_fpga_loaded(struct cyclades_card *card)
{
	return __cyz_fpga_loaded(card->ctl_addr.p9060);
}

static inline bool cyz_is_loaded(struct cyclades_card *card)
{
	struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;

	return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
			readl(&fw_id->signature) == ZFIRM_ID;
}

332
static inline int serial_paranoia_check(struct cyclades_port *info,
J
Jiri Slaby 已提交
333
		const char *name, const char *routine)
L
Linus Torvalds 已提交
334 335
{
#ifdef SERIAL_PARANOIA_CHECK
336
	if (!info) {
J
Jiri Slaby 已提交
337 338
		printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
				"in %s\n", name, routine);
339 340 341 342
		return 1;
	}

	if (info->magic != CYCLADES_MAGIC) {
J
Jiri Slaby 已提交
343 344
		printk(KERN_WARNING "cyc Warning: bad magic number for serial "
				"struct (%s) in %s\n", name, routine);
345 346
		return 1;
	}
L
Linus Torvalds 已提交
347
#endif
348
	return 0;
J
Jiri Slaby 已提交
349
}
L
Linus Torvalds 已提交
350 351 352 353 354 355 356 357 358 359 360

/***********************************************************/
/********* Start of block of Cyclom-Y specific code ********/

/* This routine waits up to 1000 micro-seconds for the previous
   command to the Cirrus chip to complete and then issues the
   new command.  An error is returned if the previous command
   didn't finish within the time limit.

   This function is only called from inside spinlock-protected code.
 */
361
static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
L
Linus Torvalds 已提交
362
{
363
	void __iomem *ccr = base_addr + (CyCCR << index);
J
Jiri Slaby 已提交
364
	unsigned int i;
L
Linus Torvalds 已提交
365

366 367
	/* Check to see that the previous command has completed */
	for (i = 0; i < 100; i++) {
368
		if (readb(ccr) == 0)
369 370
			break;
		udelay(10L);
L
Linus Torvalds 已提交
371
	}
372 373 374
	/* if the CCR never cleared, the previous command
	   didn't finish within the "reasonable time" */
	if (i == 100)
J
Jiri Slaby 已提交
375
		return -1;
L
Linus Torvalds 已提交
376

377
	/* Issue the new command */
378
	cy_writeb(ccr, cmd);
L
Linus Torvalds 已提交
379

J
Jiri Slaby 已提交
380
	return 0;
381 382 383 384 385 386 387
}

static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
{
	return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
			port->card->bus_index);
}
L
Linus Torvalds 已提交
388 389 390

#ifdef CONFIG_ISA
/* ISA interrupt detection code */
A
Alan Cox 已提交
391
static unsigned detect_isa_irq(void __iomem *address)
L
Linus Torvalds 已提交
392
{
393 394 395 396 397 398 399 400 401 402 403 404 405 406
	int irq;
	unsigned long irqs, flags;
	int save_xir, save_car;
	int index = 0;		/* IRQ probing is only for ISA */

	/* forget possible initially masked and pending IRQ */
	irq = probe_irq_off(probe_irq_on());

	/* Clear interrupts on the board first */
	cy_writeb(address + (Cy_ClrIntr << index), 0);
	/* Cy_ClrIntr is 0x1800 */

	irqs = probe_irq_on();
	/* Wait ... */
J
Jiri Slaby 已提交
407
	msleep(5);
408 409 410 411

	/* Enable the Tx interrupts on the CD1400 */
	local_irq_save(flags);
	cy_writeb(address + (CyCAR << index), 0);
412
	__cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
413 414 415

	cy_writeb(address + (CyCAR << index), 0);
	cy_writeb(address + (CySRER << index),
416
		  readb(address + (CySRER << index)) | CyTxRdy);
417 418 419
	local_irq_restore(flags);

	/* Wait ... */
J
Jiri Slaby 已提交
420
	msleep(5);
421 422 423 424 425

	/* Check which interrupt is in use */
	irq = probe_irq_off(irqs);

	/* Clean up */
426 427
	save_xir = (u_char) readb(address + (CyTIR << index));
	save_car = readb(address + (CyCAR << index));
428 429
	cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
	cy_writeb(address + (CySRER << index),
430
		  readb(address + (CySRER << index)) & ~CyTxRdy);
431 432 433 434 435 436
	cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
	cy_writeb(address + (CyCAR << index), (save_car));
	cy_writeb(address + (Cy_ClrIntr << index), 0);
	/* Cy_ClrIntr is 0x1800 */

	return (irq > 0) ? irq : 0;
L
Linus Torvalds 已提交
437
}
438
#endif				/* CONFIG_ISA */
L
Linus Torvalds 已提交
439

440 441
static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
		void __iomem *base_addr)
442 443 444
{
	struct cyclades_port *info;
	struct tty_struct *tty;
J
Jiri Slaby 已提交
445
	int len, index = cinfo->bus_index;
446
	u8 ivr, save_xir, channel, save_car, data, char_count;
447 448

#ifdef CY_DEBUG_INTERRUPTS
449
	printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
450
#endif
451
	/* determine the channel & change to that context */
J
Jiri Slaby 已提交
452 453
	save_xir = readb(base_addr + (CyRIR << index));
	channel = save_xir & CyIRChannel;
454
	info = &cinfo->ports[channel + chip * 4];
455 456 457
	save_car = cyy_readb(info, CyCAR);
	cyy_writeb(info, CyCAR, save_xir);
	ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
458

J
Jiri Slaby 已提交
459
	tty = tty_port_tty_get(&info->port);
460
	/* if there is nowhere to put the data, discard it */
J
Jiri Slaby 已提交
461
	if (tty == NULL) {
462 463
		if (ivr == CyIVRRxEx) {	/* exception */
			data = cyy_readb(info, CyRDSR);
464
		} else {	/* normal character reception */
465
			char_count = cyy_readb(info, CyRDCR);
466
			while (char_count--)
467
				data = cyy_readb(info, CyRDSR);
468 469 470 471
		}
		goto end;
	}
	/* there is an open port for this data */
472 473
	if (ivr == CyIVRRxEx) {	/* exception */
		data = cyy_readb(info, CyRDSR);
474 475 476 477 478 479 480 481 482 483 484 485 486

		/* For statistics only */
		if (data & CyBREAK)
			info->icount.brk++;
		else if (data & CyFRAME)
			info->icount.frame++;
		else if (data & CyPARITY)
			info->icount.parity++;
		else if (data & CyOVERRUN)
			info->icount.overrun++;

		if (data & info->ignore_status_mask) {
			info->icount.rx++;
J
Jiri Slaby 已提交
487
			tty_kref_put(tty);
488 489 490 491 492 493
			return;
		}
		if (tty_buffer_request_room(tty, 1)) {
			if (data & info->read_status_mask) {
				if (data & CyBREAK) {
					tty_insert_flip_char(tty,
494 495
						cyy_readb(info, CyRDSR),
						TTY_BREAK);
496
					info->icount.rx++;
A
Alan Cox 已提交
497
					if (info->port.flags & ASYNC_SAK)
498 499
						do_SAK(tty);
				} else if (data & CyFRAME) {
A
Alan Cox 已提交
500
					tty_insert_flip_char(tty,
501 502
						cyy_readb(info, CyRDSR),
						TTY_FRAME);
503 504 505 506 507
					info->icount.rx++;
					info->idle_stats.frame_errs++;
				} else if (data & CyPARITY) {
					/* Pieces of seven... */
					tty_insert_flip_char(tty,
508 509
						cyy_readb(info, CyRDSR),
						TTY_PARITY);
510 511 512 513 514 515 516 517 518 519 520
					info->icount.rx++;
					info->idle_stats.parity_errs++;
				} else if (data & CyOVERRUN) {
					tty_insert_flip_char(tty, 0,
							TTY_OVERRUN);
					info->icount.rx++;
					/* If the flip buffer itself is
					   overflowing, we still lose
					   the next incoming character.
					 */
					tty_insert_flip_char(tty,
521 522
						cyy_readb(info, CyRDSR),
						TTY_FRAME);
523 524
					info->icount.rx++;
					info->idle_stats.overruns++;
525 526 527 528 529 530 531 532
				/* These two conditions may imply */
				/* a normal read should be done. */
				/* } else if(data & CyTIMEOUT) { */
				/* } else if(data & CySPECHAR) { */
				} else {
					tty_insert_flip_char(tty, 0,
							TTY_NORMAL);
					info->icount.rx++;
533
				}
534 535 536 537 538 539 540 541 542 543 544 545
			} else {
				tty_insert_flip_char(tty, 0, TTY_NORMAL);
				info->icount.rx++;
			}
		} else {
			/* there was a software buffer overrun and nothing
			 * could be done about it!!! */
			info->icount.buf_overrun++;
			info->idle_stats.overruns++;
		}
	} else {	/* normal character reception */
		/* load # chars available from the chip */
546
		char_count = cyy_readb(info, CyRDCR);
547 548

#ifdef CY_ENABLE_MONITORING
549 550 551 552 553
		++info->mon.int_count;
		info->mon.char_count += char_count;
		if (char_count > info->mon.char_max)
			info->mon.char_max = char_count;
		info->mon.char_last = char_count;
554
#endif
555 556
		len = tty_buffer_request_room(tty, char_count);
		while (len--) {
557
			data = cyy_readb(info, CyRDSR);
558 559 560
			tty_insert_flip_char(tty, data, TTY_NORMAL);
			info->idle_stats.recv_bytes++;
			info->icount.rx++;
561
#ifdef CY_16Y_HACK
562
			udelay(10L);
563 564
#endif
		}
565
		info->idle_stats.recv_idle = jiffies;
566
	}
567
	tty_schedule_flip(tty);
J
Jiri Slaby 已提交
568
	tty_kref_put(tty);
569 570
end:
	/* end of service */
571 572
	cyy_writeb(info, CyRIR, save_xir & 0x3f);
	cyy_writeb(info, CyCAR, save_car);
573
}
574

J
Jiri Slaby 已提交
575
static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
576 577 578
		void __iomem *base_addr)
{
	struct cyclades_port *info;
J
Jiri Slaby 已提交
579
	struct tty_struct *tty;
J
Jiri Slaby 已提交
580 581
	int char_count, index = cinfo->bus_index;
	u8 save_xir, channel, save_car, outch;
582 583 584 585

	/* Since we only get here when the transmit buffer
	   is empty, we know we can always stuff a dozen
	   characters. */
586
#ifdef CY_DEBUG_INTERRUPTS
587
	printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
588 589
#endif

590
	/* determine the channel & change to that context */
J
Jiri Slaby 已提交
591 592
	save_xir = readb(base_addr + (CyTIR << index));
	channel = save_xir & CyIRChannel;
593 594 595 596
	save_car = readb(base_addr + (CyCAR << index));
	cy_writeb(base_addr + (CyCAR << index), save_xir);

	info = &cinfo->ports[channel + chip * 4];
J
Jiri Slaby 已提交
597 598
	tty = tty_port_tty_get(&info->port);
	if (tty == NULL) {
599
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
600 601
		goto end;
	}
602

603 604
	/* load the on-chip space for outbound data */
	char_count = info->xmit_fifo_size;
605

606 607
	if (info->x_char) {	/* send special char */
		outch = info->x_char;
608
		cyy_writeb(info, CyTDR, outch);
609 610 611 612
		char_count--;
		info->icount.tx++;
		info->x_char = 0;
	}
613

614 615
	if (info->breakon || info->breakoff) {
		if (info->breakon) {
616 617
			cyy_writeb(info, CyTDR, 0);
			cyy_writeb(info, CyTDR, 0x81);
618 619
			info->breakon = 0;
			char_count -= 2;
620
		}
621
		if (info->breakoff) {
622 623
			cyy_writeb(info, CyTDR, 0);
			cyy_writeb(info, CyTDR, 0x83);
624 625
			info->breakoff = 0;
			char_count -= 2;
626
		}
627
	}
628

629 630
	while (char_count-- > 0) {
		if (!info->xmit_cnt) {
631 632 633
			if (cyy_readb(info, CySRER) & CyTxMpty) {
				cyy_writeb(info, CySRER,
					cyy_readb(info, CySRER) & ~CyTxMpty);
634
			} else {
635 636
				cyy_writeb(info, CySRER, CyTxMpty |
					(cyy_readb(info, CySRER) & ~CyTxRdy));
637
			}
638 639
			goto done;
		}
A
Alan Cox 已提交
640
		if (info->port.xmit_buf == NULL) {
641 642
			cyy_writeb(info, CySRER,
				cyy_readb(info, CySRER) & ~CyTxRdy);
643 644
			goto done;
		}
J
Jiri Slaby 已提交
645
		if (tty->stopped || tty->hw_stopped) {
646 647
			cyy_writeb(info, CySRER,
				cyy_readb(info, CySRER) & ~CyTxRdy);
648 649 650 651 652 653 654 655 656 657 658
			goto done;
		}
		/* Because the Embedded Transmit Commands have been enabled,
		 * we must check to see if the escape character, NULL, is being
		 * sent. If it is, we must ensure that there is room for it to
		 * be doubled in the output stream.  Therefore we no longer
		 * advance the pointer when the character is fetched, but
		 * rather wait until after the check for a NULL output
		 * character. This is necessary because there may not be room
		 * for the two chars needed to send a NULL.)
		 */
A
Alan Cox 已提交
659
		outch = info->port.xmit_buf[info->xmit_tail];
660 661 662 663
		if (outch) {
			info->xmit_cnt--;
			info->xmit_tail = (info->xmit_tail + 1) &
					(SERIAL_XMIT_SIZE - 1);
664
			cyy_writeb(info, CyTDR, outch);
665 666 667
			info->icount.tx++;
		} else {
			if (char_count > 1) {
668 669
				info->xmit_cnt--;
				info->xmit_tail = (info->xmit_tail + 1) &
670
					(SERIAL_XMIT_SIZE - 1);
671 672
				cyy_writeb(info, CyTDR, outch);
				cyy_writeb(info, CyTDR, 0);
673
				info->icount.tx++;
674
				char_count--;
675
			}
676 677 678
		}
	}

679
done:
J
Jiri Slaby 已提交
680 681
	tty_wakeup(tty);
	tty_kref_put(tty);
682 683
end:
	/* end of service */
684 685
	cyy_writeb(info, CyTIR, save_xir & 0x3f);
	cyy_writeb(info, CyCAR, save_car);
686
}
687

688 689 690 691
static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
		void __iomem *base_addr)
{
	struct cyclades_port *info;
J
Jiri Slaby 已提交
692
	struct tty_struct *tty;
J
Jiri Slaby 已提交
693 694
	int index = cinfo->bus_index;
	u8 save_xir, channel, save_car, mdm_change, mdm_status;
695 696

	/* determine the channel & change to that context */
J
Jiri Slaby 已提交
697 698
	save_xir = readb(base_addr + (CyMIR << index));
	channel = save_xir & CyIRChannel;
699
	info = &cinfo->ports[channel + chip * 4];
700 701
	save_car = cyy_readb(info, CyCAR);
	cyy_writeb(info, CyCAR, save_xir);
702

703 704
	mdm_change = cyy_readb(info, CyMISR);
	mdm_status = cyy_readb(info, CyMSVR1);
705

J
Jiri Slaby 已提交
706 707
	tty = tty_port_tty_get(&info->port);
	if (!tty)
708 709 710 711 712 713 714 715 716 717 718 719 720
		goto end;

	if (mdm_change & CyANY_DELTA) {
		/* For statistics only */
		if (mdm_change & CyDCD)
			info->icount.dcd++;
		if (mdm_change & CyCTS)
			info->icount.cts++;
		if (mdm_change & CyDSR)
			info->icount.dsr++;
		if (mdm_change & CyRI)
			info->icount.rng++;

721
		wake_up_interruptible(&info->port.delta_msr_wait);
722 723
	}

A
Alan Cox 已提交
724
	if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
J
Jiri Slaby 已提交
725 726 727
		if (mdm_status & CyDCD)
			wake_up_interruptible(&info->port.open_wait);
		else
J
Jiri Slaby 已提交
728
			tty_hangup(tty);
729
	}
A
Alan Cox 已提交
730
	if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
J
Jiri Slaby 已提交
731
		if (tty->hw_stopped) {
732 733 734
			if (mdm_status & CyCTS) {
				/* cy_start isn't used
				   because... !!! */
J
Jiri Slaby 已提交
735
				tty->hw_stopped = 0;
736 737
				cyy_writeb(info, CySRER,
					cyy_readb(info, CySRER) | CyTxRdy);
J
Jiri Slaby 已提交
738
				tty_wakeup(tty);
739
			}
740 741 742 743
		} else {
			if (!(mdm_status & CyCTS)) {
				/* cy_stop isn't used
				   because ... !!! */
J
Jiri Slaby 已提交
744
				tty->hw_stopped = 1;
745 746
				cyy_writeb(info, CySRER,
					cyy_readb(info, CySRER) & ~CyTxRdy);
747
			}
748 749
		}
	}
750 751 752 753
/*	if (mdm_change & CyDSR) {
	}
	if (mdm_change & CyRI) {
	}*/
J
Jiri Slaby 已提交
754
	tty_kref_put(tty);
755 756
end:
	/* end of service */
757 758
	cyy_writeb(info, CyMIR, save_xir & 0x3f);
	cyy_writeb(info, CyCAR, save_car);
759 760
}

L
Linus Torvalds 已提交
761 762 763 764
/* The real interrupt service routine is called
   whenever the card wants its hand held--chars
   received, out buffer empty, modem change, etc.
 */
765
static irqreturn_t cyy_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
766
{
767
	int status;
J
Jiri Slaby 已提交
768
	struct cyclades_card *cinfo = dev_id;
769
	void __iomem *base_addr, *card_base_addr;
J
Jiri Slaby 已提交
770
	unsigned int chip, too_many, had_work;
771 772
	int index;

J
Jiri Slaby 已提交
773
	if (unlikely(cinfo == NULL)) {
L
Linus Torvalds 已提交
774
#ifdef CY_DEBUG_INTERRUPTS
A
Alan Cox 已提交
775 776
		printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
				irq);
L
Linus Torvalds 已提交
777
#endif
778 779 780 781 782 783
		return IRQ_NONE;	/* spurious interrupt */
	}

	card_base_addr = cinfo->base_addr;
	index = cinfo->bus_index;

J
Jiri Slaby 已提交
784 785 786 787
	/* card was not initialized yet (e.g. DEBUG_SHIRQ) */
	if (unlikely(card_base_addr == NULL))
		return IRQ_HANDLED;

788 789 790 791 792 793 794 795 796 797 798
	/* This loop checks all chips in the card.  Make a note whenever
	   _any_ chip had some work to do, as this is considered an
	   indication that there will be more to do.  Only when no chip
	   has any work does this outermost loop exit.
	 */
	do {
		had_work = 0;
		for (chip = 0; chip < cinfo->num_chips; chip++) {
			base_addr = cinfo->base_addr +
					(cy_chip_offset[chip] << index);
			too_many = 0;
799
			while ((status = readb(base_addr +
800 801 802 803 804 805 806
						(CySVRR << index))) != 0x00) {
				had_work++;
			/* The purpose of the following test is to ensure that
			   no chip can monopolize the driver.  This forces the
			   chips to be checked in a round-robin fashion (after
			   draining each of a bunch (1000) of characters).
			 */
807
				if (1000 < too_many++)
808
					break;
809
				spin_lock(&cinfo->card_lock);
810 811 812 813 814 815
				if (status & CySRReceive) /* rx intr */
					cyy_chip_rx(cinfo, chip, base_addr);
				if (status & CySRTransmit) /* tx intr */
					cyy_chip_tx(cinfo, chip, base_addr);
				if (status & CySRModem) /* modem intr */
					cyy_chip_modem(cinfo, chip, base_addr);
816
				spin_unlock(&cinfo->card_lock);
817 818 819 820 821 822 823 824 825 826 827
			}
		}
	} while (had_work);

	/* clear interrupts */
	spin_lock(&cinfo->card_lock);
	cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
	/* Cy_ClrIntr is 0x1800 */
	spin_unlock(&cinfo->card_lock);
	return IRQ_HANDLED;
}				/* cyy_interrupt */
L
Linus Torvalds 已提交
828

J
Jiri Slaby 已提交
829 830 831 832
static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
		unsigned int clear)
{
	struct cyclades_card *card = info->card;
833
	int channel = info->line - card->first_line;
J
Jiri Slaby 已提交
834
	u32 rts, dtr, msvrr, msvrd;
J
Jiri Slaby 已提交
835 836 837

	channel &= 0x03;

J
Jiri Slaby 已提交
838 839 840 841 842 843 844 845 846 847 848
	if (info->rtsdtr_inv) {
		msvrr = CyMSVR2;
		msvrd = CyMSVR1;
		rts = CyDTR;
		dtr = CyRTS;
	} else {
		msvrr = CyMSVR1;
		msvrd = CyMSVR2;
		rts = CyRTS;
		dtr = CyDTR;
	}
J
Jiri Slaby 已提交
849
	if (set & TIOCM_RTS) {
850 851
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrr, rts);
J
Jiri Slaby 已提交
852 853
	}
	if (clear & TIOCM_RTS) {
854 855
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrr, ~rts);
J
Jiri Slaby 已提交
856 857
	}
	if (set & TIOCM_DTR) {
858 859
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrd, dtr);
J
Jiri Slaby 已提交
860 861 862
#ifdef CY_DEBUG_DTR
		printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
863 864
			cyy_readb(info, CyMSVR1),
			cyy_readb(info, CyMSVR2));
J
Jiri Slaby 已提交
865 866 867
#endif
	}
	if (clear & TIOCM_DTR) {
868 869
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrd, ~dtr);
J
Jiri Slaby 已提交
870 871 872
#ifdef CY_DEBUG_DTR
		printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
873 874
			cyy_readb(info, CyMSVR1),
			cyy_readb(info, CyMSVR2));
J
Jiri Slaby 已提交
875 876 877 878
#endif
	}
}

L
Linus Torvalds 已提交
879 880
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
A
Alan Cox 已提交
881
/******** Start of block of Cyclades-Z specific code *******/
L
Linus Torvalds 已提交
882 883 884
/***********************************************************/

static int
885
cyz_fetch_msg(struct cyclades_card *cinfo,
A
Alan Cox 已提交
886
		__u32 *channel, __u8 *cmd, __u32 *param)
L
Linus Torvalds 已提交
887
{
888
	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
889 890
	unsigned long loc_doorbell;

891
	loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
892 893
	if (loc_doorbell) {
		*cmd = (char)(0xff & loc_doorbell);
894 895
		*channel = readl(&board_ctrl->fwcmd_channel);
		*param = (__u32) readl(&board_ctrl->fwcmd_param);
896
		cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
897 898 899 900
		return 1;
	}
	return 0;
}				/* cyz_fetch_msg */
L
Linus Torvalds 已提交
901 902

static int
903
cyz_issue_cmd(struct cyclades_card *cinfo,
K
Klaus Kudielka 已提交
904
		__u32 channel, __u8 cmd, __u32 param)
L
Linus Torvalds 已提交
905
{
906
	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
K
Klaus Kudielka 已提交
907
	__u32 __iomem *pci_doorbell;
J
Jiri Slaby 已提交
908
	unsigned int index;
909

910
	if (!cyz_is_loaded(cinfo))
J
Jiri Slaby 已提交
911
		return -1;
A
Alan Cox 已提交
912

913
	index = 0;
914
	pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
915
	while ((readl(pci_doorbell) & 0xff) != 0) {
A
Alan Cox 已提交
916
		if (index++ == 1000)
917
			return (int)(readl(pci_doorbell) & 0xff);
918 919 920 921 922 923
		udelay(50L);
	}
	cy_writel(&board_ctrl->hcmd_channel, channel);
	cy_writel(&board_ctrl->hcmd_param, param);
	cy_writel(pci_doorbell, (long)cmd);

J
Jiri Slaby 已提交
924
	return 0;
925
}				/* cyz_issue_cmd */
L
Linus Torvalds 已提交
926

927
static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
928
{
929
	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
930
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
931
	unsigned int char_count;
932
	int len;
L
Linus Torvalds 已提交
933
#ifdef BLOCKMOVE
J
Jiri Slaby 已提交
934
	unsigned char *buf;
L
Linus Torvalds 已提交
935
#else
936
	char data;
L
Linus Torvalds 已提交
937
#endif
J
Jiri Slaby 已提交
938
	__u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
L
Linus Torvalds 已提交
939

940 941 942 943
	rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
	rx_put = readl(&buf_ctrl->rx_put);
	rx_bufsize = readl(&buf_ctrl->rx_bufsize);
	rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
944 945 946 947
	if (rx_put >= rx_get)
		char_count = rx_put - rx_get;
	else
		char_count = rx_put - rx_get + rx_bufsize;
L
Linus Torvalds 已提交
948

949
	if (char_count) {
L
Linus Torvalds 已提交
950
#ifdef CY_ENABLE_MONITORING
951 952 953 954 955
		info->mon.int_count++;
		info->mon.char_count += char_count;
		if (char_count > info->mon.char_max)
			info->mon.char_max = char_count;
		info->mon.char_last = char_count;
L
Linus Torvalds 已提交
956
#endif
J
Jiri Slaby 已提交
957
		if (tty == NULL) {
958 959 960 961 962
			/* flush received characters */
			new_rx_get = (new_rx_get + char_count) &
					(rx_bufsize - 1);
			info->rflush_count++;
		} else {
L
Linus Torvalds 已提交
963
#ifdef BLOCKMOVE
964 965 966
		/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
		   for performance, but because of buffer boundaries, there
		   may be several steps to the operation */
J
Jiri Slaby 已提交
967 968 969 970 971 972 973 974 975 976 977 978 979
			while (1) {
				len = tty_prepare_flip_string(tty, &buf,
						char_count);
				if (!len)
					break;

				len = min_t(unsigned int, min(len, char_count),
						rx_bufsize - new_rx_get);

				memcpy_fromio(buf, cinfo->base_addr +
						rx_bufaddr + new_rx_get, len);

				new_rx_get = (new_rx_get + len) &
980
						(rx_bufsize - 1);
J
Jiri Slaby 已提交
981 982 983
				char_count -= len;
				info->icount.rx += len;
				info->idle_stats.recv_bytes += len;
984
			}
L
Linus Torvalds 已提交
985
#else
986 987
			len = tty_buffer_request_room(tty, char_count);
			while (len--) {
988
				data = readb(cinfo->base_addr + rx_bufaddr +
989
						new_rx_get);
A
Alan Cox 已提交
990 991
				new_rx_get = (new_rx_get + 1) &
							(rx_bufsize - 1);
992 993 994 995
				tty_insert_flip_char(tty, data, TTY_NORMAL);
				info->idle_stats.recv_bytes++;
				info->icount.rx++;
			}
L
Linus Torvalds 已提交
996 997
#endif
#ifdef CONFIG_CYZ_INTR
998 999
		/* Recalculate the number of chars in the RX buffer and issue
		   a cmd in case it's higher than the RX high water mark */
1000
			rx_put = readl(&buf_ctrl->rx_put);
1001 1002 1003 1004
			if (rx_put >= rx_get)
				char_count = rx_put - rx_get;
			else
				char_count = rx_put - rx_get + rx_bufsize;
J
Jiri Slaby 已提交
1005
			if (char_count >= readl(&buf_ctrl->rx_threshold) &&
1006 1007 1008 1009
					!timer_pending(&cyz_rx_full_timer[
							info->line]))
				mod_timer(&cyz_rx_full_timer[info->line],
						jiffies + 1);
L
Linus Torvalds 已提交
1010
#endif
1011 1012 1013 1014 1015
			info->idle_stats.recv_idle = jiffies;
			tty_schedule_flip(tty);
		}
		/* Update rx_get */
		cy_writel(&buf_ctrl->rx_get, new_rx_get);
L
Linus Torvalds 已提交
1016 1017 1018
	}
}

1019
static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1020
{
1021
	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1022
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
1023 1024
	u8 data;
	unsigned int char_count;
L
Linus Torvalds 已提交
1025
#ifdef BLOCKMOVE
1026
	int small_count;
L
Linus Torvalds 已提交
1027
#endif
J
Jiri Slaby 已提交
1028
	__u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
L
Linus Torvalds 已提交
1029

1030 1031
	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
		return;
L
Linus Torvalds 已提交
1032

1033 1034 1035 1036
	tx_get = readl(&buf_ctrl->tx_get);
	tx_put = readl(&buf_ctrl->tx_put);
	tx_bufsize = readl(&buf_ctrl->tx_bufsize);
	tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
1037 1038 1039 1040
	if (tx_put >= tx_get)
		char_count = tx_get - tx_put - 1 + tx_bufsize;
	else
		char_count = tx_get - tx_put - 1;
L
Linus Torvalds 已提交
1041

1042
	if (char_count) {
L
Linus Torvalds 已提交
1043

J
Jiri Slaby 已提交
1044
		if (tty == NULL)
1045
			goto ztxdone;
L
Linus Torvalds 已提交
1046

1047 1048
		if (info->x_char) {	/* send special char */
			data = info->x_char;
L
Linus Torvalds 已提交
1049

1050 1051 1052 1053 1054 1055
			cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
			tx_put = (tx_put + 1) & (tx_bufsize - 1);
			info->x_char = 0;
			char_count--;
			info->icount.tx++;
		}
L
Linus Torvalds 已提交
1056
#ifdef BLOCKMOVE
1057 1058 1059 1060 1061 1062 1063 1064
		while (0 < (small_count = min_t(unsigned int,
				tx_bufsize - tx_put, min_t(unsigned int,
					(SERIAL_XMIT_SIZE - info->xmit_tail),
					min_t(unsigned int, info->xmit_cnt,
						char_count))))) {

			memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
					tx_put),
A
Alan Cox 已提交
1065
					&info->port.xmit_buf[info->xmit_tail],
1066 1067 1068 1069 1070 1071 1072 1073 1074
					small_count);

			tx_put = (tx_put + small_count) & (tx_bufsize - 1);
			char_count -= small_count;
			info->icount.tx += small_count;
			info->xmit_cnt -= small_count;
			info->xmit_tail = (info->xmit_tail + small_count) &
					(SERIAL_XMIT_SIZE - 1);
		}
L
Linus Torvalds 已提交
1075
#else
1076
		while (info->xmit_cnt && char_count) {
A
Alan Cox 已提交
1077
			data = info->port.xmit_buf[info->xmit_tail];
1078 1079 1080 1081 1082 1083 1084 1085 1086
			info->xmit_cnt--;
			info->xmit_tail = (info->xmit_tail + 1) &
					(SERIAL_XMIT_SIZE - 1);

			cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
			tx_put = (tx_put + 1) & (tx_bufsize - 1);
			char_count--;
			info->icount.tx++;
		}
L
Linus Torvalds 已提交
1087
#endif
1088
		tty_wakeup(tty);
1089
ztxdone:
1090 1091
		/* Update tx_put */
		cy_writel(&buf_ctrl->tx_put, tx_put);
L
Linus Torvalds 已提交
1092 1093 1094
	}
}

1095
static void cyz_handle_cmd(struct cyclades_card *cinfo)
L
Linus Torvalds 已提交
1096
{
1097
	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
1098 1099
	struct tty_struct *tty;
	struct cyclades_port *info;
J
Jiri Slaby 已提交
1100
	__u32 channel, param, fw_ver;
K
Klaus Kudielka 已提交
1101
	__u8 cmd;
1102 1103 1104
	int special_count;
	int delta_count;

1105
	fw_ver = readl(&board_ctrl->fw_version);
1106 1107 1108 1109

	while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
		special_count = 0;
		delta_count = 0;
J
Jiri Slaby 已提交
1110
		info = &cinfo->ports[channel];
J
Jiri Slaby 已提交
1111
		tty = tty_port_tty_get(&info->port);
A
Alan Cox 已提交
1112
		if (tty == NULL)
1113
			continue;
J
Jiri Slaby 已提交
1114

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
		switch (cmd) {
		case C_CM_PR_ERROR:
			tty_insert_flip_char(tty, 0, TTY_PARITY);
			info->icount.rx++;
			special_count++;
			break;
		case C_CM_FR_ERROR:
			tty_insert_flip_char(tty, 0, TTY_FRAME);
			info->icount.rx++;
			special_count++;
			break;
		case C_CM_RXBRK:
			tty_insert_flip_char(tty, 0, TTY_BREAK);
			info->icount.rx++;
			special_count++;
			break;
		case C_CM_MDCD:
			info->icount.dcd++;
			delta_count++;
A
Alan Cox 已提交
1134
			if (info->port.flags & ASYNC_CHECK_CD) {
1135 1136
				u32 dcd = fw_ver > 241 ? param :
					readl(&info->u.cyz.ch_ctrl->rs_status);
J
Jiri Slaby 已提交
1137
				if (dcd & C_RS_DCD)
A
Alan Cox 已提交
1138
					wake_up_interruptible(&info->port.open_wait);
J
Jiri Slaby 已提交
1139
				else
J
Jiri Slaby 已提交
1140
					tty_hangup(tty);
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
			}
			break;
		case C_CM_MCTS:
			info->icount.cts++;
			delta_count++;
			break;
		case C_CM_MRI:
			info->icount.rng++;
			delta_count++;
			break;
		case C_CM_MDSR:
			info->icount.dsr++;
			delta_count++;
			break;
L
Linus Torvalds 已提交
1155
#ifdef Z_WAKE
1156
		case C_CM_IOCTLW:
1157
			complete(&info->shutdown_wait);
1158
			break;
L
Linus Torvalds 已提交
1159 1160
#endif
#ifdef CONFIG_CYZ_INTR
1161 1162 1163 1164
		case C_CM_RXHIWM:
		case C_CM_RXNNDT:
		case C_CM_INTBACK2:
			/* Reception Interrupt */
L
Linus Torvalds 已提交
1165
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1166 1167
			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
					"port %ld\n", info->card, channel);
L
Linus Torvalds 已提交
1168
#endif
1169
			cyz_handle_rx(info, tty);
1170 1171 1172 1173 1174
			break;
		case C_CM_TXBEMPTY:
		case C_CM_TXLOWWM:
		case C_CM_INTBACK:
			/* Transmission Interrupt */
L
Linus Torvalds 已提交
1175
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1176 1177
			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
					"port %ld\n", info->card, channel);
L
Linus Torvalds 已提交
1178
#endif
1179
			cyz_handle_tx(info, tty);
1180 1181 1182 1183 1184 1185 1186 1187 1188
			break;
#endif				/* CONFIG_CYZ_INTR */
		case C_CM_FATAL:
			/* should do something with this !!! */
			break;
		default:
			break;
		}
		if (delta_count)
1189
			wake_up_interruptible(&info->port.delta_msr_wait);
1190 1191
		if (special_count)
			tty_schedule_flip(tty);
J
Jiri Slaby 已提交
1192
		tty_kref_put(tty);
L
Linus Torvalds 已提交
1193 1194 1195 1196
	}
}

#ifdef CONFIG_CYZ_INTR
1197
static irqreturn_t cyz_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
1198
{
J
Jiri Slaby 已提交
1199
	struct cyclades_card *cinfo = dev_id;
L
Linus Torvalds 已提交
1200

1201
	if (unlikely(!cyz_is_loaded(cinfo))) {
L
Linus Torvalds 已提交
1202
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1203 1204
		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
				"(IRQ%d).\n", irq);
L
Linus Torvalds 已提交
1205
#endif
1206 1207
		return IRQ_NONE;
	}
L
Linus Torvalds 已提交
1208

1209 1210
	/* Handle the interrupts */
	cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1211

1212 1213
	return IRQ_HANDLED;
}				/* cyz_interrupt */
L
Linus Torvalds 已提交
1214

1215
static void cyz_rx_restart(unsigned long arg)
L
Linus Torvalds 已提交
1216
{
1217
	struct cyclades_port *info = (struct cyclades_port *)arg;
1218
	struct cyclades_card *card = info->card;
1219
	int retval;
1220
	__u32 channel = info->line - card->first_line;
1221 1222
	unsigned long flags;

1223
	spin_lock_irqsave(&card->card_lock, flags);
1224
	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
1225
	if (retval != 0) {
J
Jiri Slaby 已提交
1226
		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
1227 1228
			info->line, retval);
	}
1229
	spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
1230 1231
}

1232
#else				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1233

1234
static void cyz_poll(unsigned long arg)
L
Linus Torvalds 已提交
1235
{
1236 1237
	struct cyclades_card *cinfo;
	struct cyclades_port *info;
J
Jiri Slaby 已提交
1238
	unsigned long expires = jiffies + HZ;
J
Jiri Slaby 已提交
1239
	unsigned int port, card;
L
Linus Torvalds 已提交
1240

1241 1242 1243
	for (card = 0; card < NR_CARDS; card++) {
		cinfo = &cy_card[card];

1244
		if (!cy_is_Z(cinfo))
1245
			continue;
1246
		if (!cyz_is_loaded(cinfo))
1247 1248
			continue;

L
Linus Torvalds 已提交
1249
	/* Skip first polling cycle to avoid racing conditions with the FW */
1250 1251 1252 1253
		if (!cinfo->intr_enabled) {
			cinfo->intr_enabled = 1;
			continue;
		}
L
Linus Torvalds 已提交
1254

1255
		cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1256

1257
		for (port = 0; port < cinfo->nports; port++) {
J
Jiri Slaby 已提交
1258 1259
			struct tty_struct *tty;

J
Jiri Slaby 已提交
1260
			info = &cinfo->ports[port];
J
Jiri Slaby 已提交
1261 1262 1263 1264
			tty = tty_port_tty_get(&info->port);
			/* OK to pass NULL to the handle functions below.
			   They need to drop the data in that case. */

1265
			if (!info->throttle)
1266 1267
				cyz_handle_rx(info, tty);
			cyz_handle_tx(info, tty);
J
Jiri Slaby 已提交
1268
			tty_kref_put(tty);
1269 1270
		}
		/* poll every 'cyz_polling_cycle' period */
J
Jiri Slaby 已提交
1271
		expires = jiffies + cyz_polling_cycle;
L
Linus Torvalds 已提交
1272
	}
J
Jiri Slaby 已提交
1273
	mod_timer(&cyz_timerlist, expires);
1274
}				/* cyz_poll */
L
Linus Torvalds 已提交
1275

1276
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1277 1278 1279 1280 1281 1282 1283

/********** End of block of Cyclades-Z specific code *********/
/***********************************************************/

/* This is called whenever a port becomes active;
   interrupts are enabled and DTR & RTS are turned on.
 */
J
Jiri Slaby 已提交
1284
static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1285
{
1286
	struct cyclades_card *card;
1287 1288
	unsigned long flags;
	int retval = 0;
J
Jiri Slaby 已提交
1289
	int channel;
1290
	unsigned long page;
L
Linus Torvalds 已提交
1291

1292
	card = info->card;
1293
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1294

1295 1296 1297
	page = get_zeroed_page(GFP_KERNEL);
	if (!page)
		return -ENOMEM;
L
Linus Torvalds 已提交
1298

1299
	spin_lock_irqsave(&card->card_lock, flags);
L
Linus Torvalds 已提交
1300

J
Jiri Slaby 已提交
1301
	if (info->port.flags & ASYNC_INITIALIZED)
1302
		goto errout;
L
Linus Torvalds 已提交
1303

1304
	if (!info->type) {
J
Jiri Slaby 已提交
1305
		set_bit(TTY_IO_ERROR, &tty->flags);
1306 1307
		goto errout;
	}
L
Linus Torvalds 已提交
1308

A
Alan Cox 已提交
1309
	if (info->port.xmit_buf)
1310 1311
		free_page(page);
	else
A
Alan Cox 已提交
1312
		info->port.xmit_buf = (unsigned char *)page;
L
Linus Torvalds 已提交
1313

1314
	spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
1315

J
Jiri Slaby 已提交
1316
	cy_set_line_char(info, tty);
L
Linus Torvalds 已提交
1317

1318
	if (!cy_is_Z(card)) {
1319
		channel &= 0x03;
L
Linus Torvalds 已提交
1320

1321
		spin_lock_irqsave(&card->card_lock, flags);
L
Linus Torvalds 已提交
1322

1323
		cyy_writeb(info, CyCAR, channel);
L
Linus Torvalds 已提交
1324

1325
		cyy_writeb(info, CyRTPR,
1326 1327
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */
L
Linus Torvalds 已提交
1328

1329
		cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
L
Linus Torvalds 已提交
1330

J
Jiri Slaby 已提交
1331
		cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
L
Linus Torvalds 已提交
1332

1333
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
1334
	} else {
1335
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
L
Linus Torvalds 已提交
1336

1337
		if (!cyz_is_loaded(card))
1338
			return -ENODEV;
L
Linus Torvalds 已提交
1339 1340

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1341
		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1342
			"base_addr %p\n", card, channel, card->base_addr);
L
Linus Torvalds 已提交
1343
#endif
1344
		spin_lock_irqsave(&card->card_lock, flags);
L
Linus Torvalds 已提交
1345

1346
		cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
L
Linus Torvalds 已提交
1347 1348
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
1349
		cy_writel(&ch_ctrl->intr_enable,
1350 1351
			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
L
Linus Torvalds 已提交
1352
#else
1353
		cy_writel(&ch_ctrl->intr_enable,
1354 1355
			  C_IN_IOCTLW | C_IN_MDCD);
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1356 1357
#else
#ifdef CONFIG_CYZ_INTR
1358
		cy_writel(&ch_ctrl->intr_enable,
1359 1360
			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
			  C_IN_RXNNDT | C_IN_MDCD);
L
Linus Torvalds 已提交
1361
#else
1362
		cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
1363 1364 1365
#endif				/* CONFIG_CYZ_INTR */
#endif				/* Z_WAKE */

1366
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
1367
		if (retval != 0) {
J
Jiri Slaby 已提交
1368 1369
			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
				"%x\n", info->line, retval);
1370
		}
L
Linus Torvalds 已提交
1371

1372
		/* Flush RX buffers before raising DTR and RTS */
1373
		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
1374
		if (retval != 0) {
J
Jiri Slaby 已提交
1375 1376
			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
				"%x\n", info->line, retval);
1377
		}
L
Linus Torvalds 已提交
1378

1379 1380
		/* set timeout !!! */
		/* set RTS and DTR !!! */
J
Jiri Slaby 已提交
1381
		tty_port_raise_dtr_rts(&info->port);
L
Linus Torvalds 已提交
1382

1383
		/* enable send, recv, modem !!! */
J
Jiri Slaby 已提交
1384
	}
1385

J
Jiri Slaby 已提交
1386
	info->port.flags |= ASYNC_INITIALIZED;
L
Linus Torvalds 已提交
1387

J
Jiri Slaby 已提交
1388 1389 1390 1391 1392 1393 1394 1395 1396
	clear_bit(TTY_IO_ERROR, &tty->flags);
	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
	info->breakon = info->breakoff = 0;
	memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
	info->idle_stats.in_use =
	info->idle_stats.recv_idle =
	info->idle_stats.xmit_idle = jiffies;

	spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
1397 1398

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1399
	printk(KERN_DEBUG "cyc startup done\n");
L
Linus Torvalds 已提交
1400 1401 1402 1403
#endif
	return 0;

errout:
1404
	spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1405
	free_page(page);
L
Linus Torvalds 已提交
1406
	return retval;
1407
}				/* startup */
L
Linus Torvalds 已提交
1408

1409
static void start_xmit(struct cyclades_port *info)
L
Linus Torvalds 已提交
1410
{
1411
	struct cyclades_card *card = info->card;
1412
	unsigned long flags;
1413
	int channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1414

1415
	if (!cy_is_Z(card)) {
1416
		spin_lock_irqsave(&card->card_lock, flags);
1417 1418
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
1419
		spin_unlock_irqrestore(&card->card_lock, flags);
1420
	} else {
L
Linus Torvalds 已提交
1421
#ifdef CONFIG_CYZ_INTR
1422
		int retval;
L
Linus Torvalds 已提交
1423

1424
		spin_lock_irqsave(&card->card_lock, flags);
1425
		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
1426
		if (retval != 0) {
J
Jiri Slaby 已提交
1427 1428
			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
				"%x\n", info->line, retval);
1429
		}
1430
		spin_unlock_irqrestore(&card->card_lock, flags);
1431 1432 1433 1434 1435
#else				/* CONFIG_CYZ_INTR */
		/* Don't have to do anything at this time */
#endif				/* CONFIG_CYZ_INTR */
	}
}				/* start_xmit */
L
Linus Torvalds 已提交
1436 1437 1438 1439 1440

/*
 * This routine shuts down a serial port; interrupts are disabled,
 * and DTR is dropped if the hangup on close termio flag is on.
 */
J
Jiri Slaby 已提交
1441
static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1442
{
1443
	struct cyclades_card *card;
1444 1445
	unsigned long flags;

A
Alan Cox 已提交
1446
	if (!(info->port.flags & ASYNC_INITIALIZED))
1447 1448 1449
		return;

	card = info->card;
1450
	if (!cy_is_Z(card)) {
1451
		spin_lock_irqsave(&card->card_lock, flags);
1452 1453

		/* Clear delta_msr_wait queue to avoid mem leaks. */
1454
		wake_up_interruptible(&info->port.delta_msr_wait);
L
Linus Torvalds 已提交
1455

A
Alan Cox 已提交
1456
		if (info->port.xmit_buf) {
1457
			unsigned char *temp;
A
Alan Cox 已提交
1458 1459
			temp = info->port.xmit_buf;
			info->port.xmit_buf = NULL;
1460 1461
			free_page((unsigned long)temp);
		}
J
Jiri Slaby 已提交
1462 1463 1464
		if (tty->termios->c_cflag & HUPCL)
			cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);

1465
		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
1466 1467 1468
		/* it may be appropriate to clear _XMIT at
		   some later date (after testing)!!! */

J
Jiri Slaby 已提交
1469
		set_bit(TTY_IO_ERROR, &tty->flags);
A
Alan Cox 已提交
1470
		info->port.flags &= ~ASYNC_INITIALIZED;
1471
		spin_unlock_irqrestore(&card->card_lock, flags);
1472
	} else {
L
Linus Torvalds 已提交
1473
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1474
		int channel = info->line - card->first_line;
J
Jiri Slaby 已提交
1475
		printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
1476
			"base_addr %p\n", card, channel, card->base_addr);
L
Linus Torvalds 已提交
1477 1478
#endif

1479
		if (!cyz_is_loaded(card))
1480
			return;
L
Linus Torvalds 已提交
1481

1482
		spin_lock_irqsave(&card->card_lock, flags);
L
Linus Torvalds 已提交
1483

A
Alan Cox 已提交
1484
		if (info->port.xmit_buf) {
1485
			unsigned char *temp;
A
Alan Cox 已提交
1486 1487
			temp = info->port.xmit_buf;
			info->port.xmit_buf = NULL;
1488
			free_page((unsigned long)temp);
L
Linus Torvalds 已提交
1489
		}
1490

J
Jiri Slaby 已提交
1491 1492
		if (tty->termios->c_cflag & HUPCL)
			tty_port_lower_dtr_rts(&info->port);
L
Linus Torvalds 已提交
1493

J
Jiri Slaby 已提交
1494
		set_bit(TTY_IO_ERROR, &tty->flags);
A
Alan Cox 已提交
1495
		info->port.flags &= ~ASYNC_INITIALIZED;
1496

1497
		spin_unlock_irqrestore(&card->card_lock, flags);
1498
	}
L
Linus Torvalds 已提交
1499 1500

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1501
	printk(KERN_DEBUG "cyc shutdown done\n");
L
Linus Torvalds 已提交
1502
#endif
1503
}				/* shutdown */
L
Linus Torvalds 已提交
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514

/*
 * ------------------------------------------------------------
 * cy_open() and friends
 * ------------------------------------------------------------
 */

/*
 * This routine is called whenever a serial port is opened.  It
 * performs the serial-specific initialization for the tty structure.
 */
1515
static int cy_open(struct tty_struct *tty, struct file *filp)
L
Linus Torvalds 已提交
1516
{
1517
	struct cyclades_port *info;
1518
	unsigned int i, line = tty->index;
J
Jiri Slaby 已提交
1519
	int retval;
L
Linus Torvalds 已提交
1520

J
Jiri Slaby 已提交
1521 1522 1523 1524 1525 1526 1527
	for (i = 0; i < NR_CARDS; i++)
		if (line < cy_card[i].first_line + cy_card[i].nports &&
				line >= cy_card[i].first_line)
			break;
	if (i >= NR_CARDS)
		return -ENODEV;
	info = &cy_card[i].ports[line - cy_card[i].first_line];
A
Alan Cox 已提交
1528
	if (info->line < 0)
1529
		return -ENODEV;
L
Linus Torvalds 已提交
1530

1531 1532 1533 1534
	/* If the card's firmware hasn't been loaded,
	   treat it as absent from the system.  This
	   will make the user pay attention.
	 */
1535
	if (cy_is_Z(info->card)) {
1536
		struct cyclades_card *cinfo = info->card;
1537 1538
		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;

1539 1540
		if (!cyz_is_loaded(cinfo)) {
			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
J
Jiri Slaby 已提交
1541 1542
					readl(&firm_id->signature) ==
					ZFIRM_HLT) {
J
Jiri Slaby 已提交
1543 1544 1545 1546
				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
					"need an external power supply for "
					"this number of ports.\nFirmware "
					"halted.\n");
1547
			} else {
J
Jiri Slaby 已提交
1548 1549
				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
					"yet loaded\n");
1550 1551 1552 1553 1554 1555 1556 1557 1558
			}
			return -ENODEV;
		}
#ifdef CONFIG_CYZ_INTR
		else {
		/* In case this Z board is operating in interrupt mode, its
		   interrupts should be enabled as soon as the first open
		   happens to one of its ports. */
			if (!cinfo->intr_enabled) {
1559
				u16 intr;
1560 1561

				/* Enable interrupts on the PLX chip */
1562 1563 1564 1565
				intr = readw(&cinfo->ctl_addr.p9060->
						intr_ctrl_stat) | 0x0900;
				cy_writew(&cinfo->ctl_addr.p9060->
						intr_ctrl_stat, intr);
1566 1567 1568 1569
				/* Enable interrupts on the FW */
				retval = cyz_issue_cmd(cinfo, 0,
						C_CM_IRQ_ENBL, 0L);
				if (retval != 0) {
J
Jiri Slaby 已提交
1570 1571
					printk(KERN_ERR "cyc:IRQ enable retval "
						"was %x\n", retval);
1572 1573 1574
				}
				cinfo->intr_enabled = 1;
			}
L
Linus Torvalds 已提交
1575
		}
1576 1577 1578 1579
#endif				/* CONFIG_CYZ_INTR */
		/* Make sure this Z port really exists in hardware */
		if (info->line > (cinfo->first_line + cinfo->nports - 1))
			return -ENODEV;
L
Linus Torvalds 已提交
1580 1581
	}
#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
1582
	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1583
#endif
1584
	tty->driver_data = info;
A
Alan Cox 已提交
1585
	if (serial_paranoia_check(info, tty->name, "cy_open"))
1586
		return -ENODEV;
A
Alan Cox 已提交
1587

L
Linus Torvalds 已提交
1588
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1589
	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
A
Alan Cox 已提交
1590
			info->port.count);
L
Linus Torvalds 已提交
1591
#endif
A
Alan Cox 已提交
1592
	info->port.count++;
L
Linus Torvalds 已提交
1593
#ifdef CY_DEBUG_COUNT
J
Jiri Slaby 已提交
1594
	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
A
Alan Cox 已提交
1595
		current->pid, info->port.count);
L
Linus Torvalds 已提交
1596 1597
#endif

1598 1599 1600
	/*
	 * If the port is the middle of closing, bail out now
	 */
A
Alan Cox 已提交
1601
	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
1602
		wait_event_interruptible_tty(info->port.close_wait,
A
Alan Cox 已提交
1603 1604
				!(info->port.flags & ASYNC_CLOSING));
		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
1605
	}
L
Linus Torvalds 已提交
1606

1607 1608 1609
	/*
	 * Start up serial port
	 */
J
Jiri Slaby 已提交
1610
	retval = cy_startup(info, tty);
A
Alan Cox 已提交
1611
	if (retval)
1612
		return retval;
L
Linus Torvalds 已提交
1613

J
Jiri Slaby 已提交
1614
	retval = tty_port_block_til_ready(&info->port, tty, filp);
1615
	if (retval) {
L
Linus Torvalds 已提交
1616
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1617 1618
		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
			"with %d\n", retval);
L
Linus Torvalds 已提交
1619
#endif
1620 1621
		return retval;
	}
L
Linus Torvalds 已提交
1622

1623
	info->throttle = 0;
J
Jiri Slaby 已提交
1624
	tty_port_tty_set(&info->port, tty);
L
Linus Torvalds 已提交
1625

1626
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1627
	printk(KERN_DEBUG "cyc:cy_open done\n");
1628 1629 1630
#endif
	return 0;
}				/* cy_open */
L
Linus Torvalds 已提交
1631 1632 1633 1634

/*
 * cy_wait_until_sent() --- wait until the transmitter is empty
 */
1635
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
L
Linus Torvalds 已提交
1636
{
1637
	struct cyclades_card *card;
1638
	struct cyclades_port *info = tty->driver_data;
1639 1640 1641 1642 1643 1644 1645 1646
	unsigned long orig_jiffies;
	int char_time;

	if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
		return;

	if (info->xmit_fifo_size == 0)
		return;		/* Just in case.... */
L
Linus Torvalds 已提交
1647

1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
	orig_jiffies = jiffies;
	/*
	 * Set the check interval to be 1/5 of the estimated time to
	 * send a single character, and make it at least 1.  The check
	 * interval should also be less than the timeout.
	 *
	 * Note: we have to use pretty tight timings here to satisfy
	 * the NIST-PCTS.
	 */
	char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
	char_time = char_time / 5;
	if (char_time <= 0)
		char_time = 1;
	if (timeout < 0)
		timeout = 0;
	if (timeout)
		char_time = min(char_time, timeout);
	/*
	 * If the transmitter hasn't cleared in twice the approximate
	 * amount of time to send the entire FIFO, it probably won't
	 * ever clear.  This assumes the UART isn't doing flow
	 * control, which is currently the case.  Hence, if it ever
	 * takes longer than info->timeout, this is probably due to a
	 * UART bug of some kind.  So, we clamp the timeout parameter at
	 * 2*info->timeout.
	 */
	if (!timeout || timeout > 2 * info->timeout)
		timeout = 2 * info->timeout;
1676

1677
	card = info->card;
1678
	if (!cy_is_Z(card)) {
1679
		while (cyy_readb(info, CySRER) & CyTxRdy) {
1680 1681 1682 1683 1684 1685
			if (msleep_interruptible(jiffies_to_msecs(char_time)))
				break;
			if (timeout && time_after(jiffies, orig_jiffies +
					timeout))
				break;
		}
L
Linus Torvalds 已提交
1686
	}
1687 1688
	/* Run one more char cycle */
	msleep_interruptible(jiffies_to_msecs(char_time * 5));
L
Linus Torvalds 已提交
1689 1690
}

1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
static void cy_flush_buffer(struct tty_struct *tty)
{
	struct cyclades_port *info = tty->driver_data;
	struct cyclades_card *card;
	int channel, retval;
	unsigned long flags;

#ifdef CY_DEBUG_IO
	printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
#endif

	if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
		return;

	card = info->card;
	channel = info->line - card->first_line;

	spin_lock_irqsave(&card->card_lock, flags);
	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
	spin_unlock_irqrestore(&card->card_lock, flags);

1712
	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
					   buffers as well */
		spin_lock_irqsave(&card->card_lock, flags);
		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
		if (retval != 0) {
			printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
				"was %x\n", info->line, retval);
		}
		spin_unlock_irqrestore(&card->card_lock, flags);
	}
	tty_wakeup(tty);
}				/* cy_flush_buffer */


1726
static void cy_do_close(struct tty_port *port)
L
Linus Torvalds 已提交
1727
{
1728 1729
	struct cyclades_port *info = container_of(port, struct cyclades_port,
								port);
1730
	struct cyclades_card *card;
1731
	unsigned long flags;
1732
	int channel;
L
Linus Torvalds 已提交
1733

1734
	card = info->card;
1735
	channel = info->line - card->first_line;
1736
	spin_lock_irqsave(&card->card_lock, flags);
1737

1738
	if (!cy_is_Z(card)) {
1739
		/* Stop accepting input */
1740 1741
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
A
Alan Cox 已提交
1742
		if (info->port.flags & ASYNC_INITIALIZED) {
A
Alan Cox 已提交
1743 1744
			/* Waiting for on-board buffers to be empty before
			   closing the port */
1745
			spin_unlock_irqrestore(&card->card_lock, flags);
1746
			cy_wait_until_sent(port->tty, info->timeout);
1747
			spin_lock_irqsave(&card->card_lock, flags);
1748 1749 1750
		}
	} else {
#ifdef Z_WAKE
A
Alan Cox 已提交
1751 1752
		/* Waiting for on-board buffers to be empty before closing
		   the port */
1753
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
1754 1755
		int retval;

1756
		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
1757
			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
1758
			if (retval != 0) {
J
Jiri Slaby 已提交
1759 1760
				printk(KERN_DEBUG "cyc:cy_close retval on "
					"ttyC%d was %x\n", info->line, retval);
1761
			}
1762
			spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1763
			wait_for_completion_interruptible(&info->shutdown_wait);
1764
			spin_lock_irqsave(&card->card_lock, flags);
1765
		}
L
Linus Torvalds 已提交
1766
#endif
1767
	}
1768
	spin_unlock_irqrestore(&card->card_lock, flags);
1769 1770
	cy_shutdown(info, port->tty);
}
L
Linus Torvalds 已提交
1771

1772 1773 1774 1775 1776 1777 1778 1779 1780
/*
 * This routine is called when a particular tty device is closed.
 */
static void cy_close(struct tty_struct *tty, struct file *filp)
{
	struct cyclades_port *info = tty->driver_data;
	if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
		return;
	tty_port_close(&info->port, tty, filp);
1781
}				/* cy_close */
L
Linus Torvalds 已提交
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795

/* This routine gets called when tty_write has put something into
 * the write_queue.  The characters may come from user space or
 * kernel space.
 *
 * This routine will return the number of characters actually
 * accepted for writing.
 *
 * If the port is not already transmitting stuff, start it off by
 * enabling interrupts.  The interrupt service routine will then
 * ensure that the characters are sent.
 * If the port is already active, there is no need to kick it.
 *
 */
1796
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
L
Linus Torvalds 已提交
1797
{
1798
	struct cyclades_port *info = tty->driver_data;
1799 1800
	unsigned long flags;
	int c, ret = 0;
L
Linus Torvalds 已提交
1801 1802

#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1803
	printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1804 1805
#endif

A
Alan Cox 已提交
1806
	if (serial_paranoia_check(info, tty->name, "cy_write"))
1807
		return 0;
L
Linus Torvalds 已提交
1808

A
Alan Cox 已提交
1809
	if (!info->port.xmit_buf)
1810
		return 0;
L
Linus Torvalds 已提交
1811

1812
	spin_lock_irqsave(&info->card->card_lock, flags);
1813
	while (1) {
1814 1815
		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
1816 1817 1818 1819

		if (c <= 0)
			break;

A
Alan Cox 已提交
1820
		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
1821 1822 1823 1824 1825 1826 1827
		info->xmit_head = (info->xmit_head + c) &
			(SERIAL_XMIT_SIZE - 1);
		info->xmit_cnt += c;
		buf += c;
		count -= c;
		ret += c;
	}
1828
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1829 1830 1831 1832

	info->idle_stats.xmit_bytes += ret;
	info->idle_stats.xmit_idle = jiffies;

A
Alan Cox 已提交
1833
	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1834
		start_xmit(info);
A
Alan Cox 已提交
1835

1836 1837
	return ret;
}				/* cy_write */
L
Linus Torvalds 已提交
1838 1839 1840 1841 1842 1843 1844 1845

/*
 * This routine is called by the kernel to write a single
 * character to the tty device.  If the kernel uses this routine,
 * it must call the flush_chars() routine (if defined) when it is
 * done stuffing characters into the driver.  If there is no room
 * in the queue, the character is ignored.
 */
1846
static int cy_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
1847
{
1848
	struct cyclades_port *info = tty->driver_data;
1849
	unsigned long flags;
L
Linus Torvalds 已提交
1850 1851

#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1852
	printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1853 1854
#endif

1855
	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1856
		return 0;
L
Linus Torvalds 已提交
1857

A
Alan Cox 已提交
1858
	if (!info->port.xmit_buf)
1859
		return 0;
L
Linus Torvalds 已提交
1860

1861
	spin_lock_irqsave(&info->card->card_lock, flags);
J
Jiri Slaby 已提交
1862
	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
1863
		spin_unlock_irqrestore(&info->card->card_lock, flags);
1864
		return 0;
1865
	}
L
Linus Torvalds 已提交
1866

A
Alan Cox 已提交
1867
	info->port.xmit_buf[info->xmit_head++] = ch;
1868 1869
	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
	info->xmit_cnt++;
L
Linus Torvalds 已提交
1870 1871
	info->idle_stats.xmit_bytes++;
	info->idle_stats.xmit_idle = jiffies;
1872
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1873
	return 1;
1874
}				/* cy_put_char */
L
Linus Torvalds 已提交
1875 1876 1877

/*
 * This routine is called by the kernel after it has written a
A
Alan Cox 已提交
1878
 * series of characters to the tty device using put_char().
L
Linus Torvalds 已提交
1879
 */
1880
static void cy_flush_chars(struct tty_struct *tty)
L
Linus Torvalds 已提交
1881
{
1882
	struct cyclades_port *info = tty->driver_data;
1883

L
Linus Torvalds 已提交
1884
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1885
	printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1886 1887
#endif

1888 1889
	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
		return;
L
Linus Torvalds 已提交
1890

1891
	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
A
Alan Cox 已提交
1892
			!info->port.xmit_buf)
1893
		return;
L
Linus Torvalds 已提交
1894

1895 1896
	start_xmit(info);
}				/* cy_flush_chars */
L
Linus Torvalds 已提交
1897 1898 1899 1900 1901 1902 1903

/*
 * This routine returns the numbers of characters the tty driver
 * will accept for queuing to be written.  This number is subject
 * to change as output buffers get emptied, or if the output flow
 * control is activated.
 */
1904
static int cy_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
1905
{
1906
	struct cyclades_port *info = tty->driver_data;
1907 1908
	int ret;

L
Linus Torvalds 已提交
1909
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1910
	printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1911 1912
#endif

1913 1914 1915 1916 1917 1918 1919
	if (serial_paranoia_check(info, tty->name, "cy_write_room"))
		return 0;
	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
	if (ret < 0)
		ret = 0;
	return ret;
}				/* cy_write_room */
L
Linus Torvalds 已提交
1920

1921
static int cy_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1922
{
1923
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
1924

1925 1926 1927
	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
		return 0;

L
Linus Torvalds 已提交
1928
#ifdef Z_EXT_CHARS_IN_BUFFER
1929
	if (!cy_is_Z(info->card)) {
1930
#endif				/* Z_EXT_CHARS_IN_BUFFER */
L
Linus Torvalds 已提交
1931
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1932 1933
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt);
L
Linus Torvalds 已提交
1934
#endif
1935
		return info->xmit_cnt;
L
Linus Torvalds 已提交
1936
#ifdef Z_EXT_CHARS_IN_BUFFER
1937
	} else {
1938
		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1939
		int char_count;
J
Jiri Slaby 已提交
1940
		__u32 tx_put, tx_get, tx_bufsize;
1941

1942 1943 1944
		tx_get = readl(&buf_ctrl->tx_get);
		tx_put = readl(&buf_ctrl->tx_put);
		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1945 1946 1947 1948
		if (tx_put >= tx_get)
			char_count = tx_put - tx_get;
		else
			char_count = tx_put - tx_get + tx_bufsize;
L
Linus Torvalds 已提交
1949
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1950 1951
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt + char_count);
L
Linus Torvalds 已提交
1952
#endif
J
Jiri Slaby 已提交
1953
		return info->xmit_cnt + char_count;
1954 1955 1956
	}
#endif				/* Z_EXT_CHARS_IN_BUFFER */
}				/* cy_chars_in_buffer */
L
Linus Torvalds 已提交
1957 1958 1959 1960 1961 1962 1963

/*
 * ------------------------------------------------------------
 * cy_ioctl() and friends
 * ------------------------------------------------------------
 */

K
Klaus Kudielka 已提交
1964
static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
L
Linus Torvalds 已提交
1965
{
1966
	int co, co_val, bpr;
K
Klaus Kudielka 已提交
1967
	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
1968
			25000000);
L
Linus Torvalds 已提交
1969

1970 1971 1972 1973
	if (baud == 0) {
		info->tbpr = info->tco = info->rbpr = info->rco = 0;
		return;
	}
L
Linus Torvalds 已提交
1974

1975 1976 1977 1978 1979
	/* determine which prescaler to use */
	for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
		if (cy_clock / co_val / baud > 63)
			break;
	}
L
Linus Torvalds 已提交
1980

1981 1982 1983
	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
	if (bpr > 255)
		bpr = 255;
L
Linus Torvalds 已提交
1984

1985 1986
	info->tbpr = info->rbpr = bpr;
	info->tco = info->rco = co;
L
Linus Torvalds 已提交
1987 1988 1989 1990 1991 1992
}

/*
 * This routine finds or computes the various line characteristics.
 * It used to be called config_setup
 */
J
Jiri Slaby 已提交
1993
static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1994
{
1995
	struct cyclades_card *card;
1996
	unsigned long flags;
1997
	int channel;
1998 1999 2000 2001
	unsigned cflag, iflag;
	int baud, baud_rate = 0;
	int i;

J
Jiri Slaby 已提交
2002
	if (!tty->termios) /* XXX can this happen at all? */
2003
		return;
A
Alan Cox 已提交
2004 2005

	if (info->line == -1)
2006
		return;
A
Alan Cox 已提交
2007

J
Jiri Slaby 已提交
2008 2009
	cflag = tty->termios->c_cflag;
	iflag = tty->termios->c_iflag;
L
Linus Torvalds 已提交
2010

2011 2012 2013
	/*
	 * Set up the tty->alt_speed kludge
	 */
J
Jiri Slaby 已提交
2014 2015 2016 2017 2018 2019 2020 2021
	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
		tty->alt_speed = 57600;
	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
		tty->alt_speed = 115200;
	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
		tty->alt_speed = 230400;
	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
		tty->alt_speed = 460800;
2022 2023

	card = info->card;
2024
	channel = info->line - card->first_line;
2025

2026
	if (!cy_is_Z(card)) {
2027 2028
		u32 cflags;

2029
		/* baud rate */
J
Jiri Slaby 已提交
2030
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2031
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
				ASYNC_SPD_CUST) {
			if (info->custom_divisor)
				baud_rate = info->baud / info->custom_divisor;
			else
				baud_rate = info->baud;
		} else if (baud > CD1400_MAX_SPEED) {
			baud = CD1400_MAX_SPEED;
		}
		/* find the baud index */
		for (i = 0; i < 20; i++) {
A
Alan Cox 已提交
2042
			if (baud == baud_table[i])
2043 2044
				break;
		}
A
Alan Cox 已提交
2045
		if (i == 20)
2046 2047
			i = 19;	/* CD1400_MAX_SPEED */

A
Alan Cox 已提交
2048
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068
				ASYNC_SPD_CUST) {
			cyy_baud_calc(info, baud_rate);
		} else {
			if (info->chip_rev >= CD1400_REV_J) {
				/* It is a CD1400 rev. J or later */
				info->tbpr = baud_bpr_60[i];	/* Tx BPR */
				info->tco = baud_co_60[i];	/* Tx CO */
				info->rbpr = baud_bpr_60[i];	/* Rx BPR */
				info->rco = baud_co_60[i];	/* Rx CO */
			} else {
				info->tbpr = baud_bpr_25[i];	/* Tx BPR */
				info->tco = baud_co_25[i];	/* Tx CO */
				info->rbpr = baud_bpr_25[i];	/* Rx BPR */
				info->rco = baud_co_25[i];	/* Rx CO */
			}
		}
		if (baud_table[i] == 134) {
			/* get it right for 134.5 baud */
			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
					2;
A
Alan Cox 已提交
2069
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104
				ASYNC_SPD_CUST) {
			info->timeout = (info->xmit_fifo_size * HZ * 15 /
					baud_rate) + 2;
		} else if (baud_table[i]) {
			info->timeout = (info->xmit_fifo_size * HZ * 15 /
					baud_table[i]) + 2;
			/* this needs to be propagated into the card info */
		} else {
			info->timeout = 0;
		}
		/* By tradition (is it a standard?) a baud rate of zero
		   implies the line should be/has been closed.  A bit
		   later in this routine such a test is performed. */

		/* byte size and parity */
		info->cor5 = 0;
		info->cor4 = 0;
		/* receive threshold */
		info->cor3 = (info->default_threshold ?
				info->default_threshold : baud_cor3[i]);
		info->cor2 = CyETC;
		switch (cflag & CSIZE) {
		case CS5:
			info->cor1 = Cy_5_BITS;
			break;
		case CS6:
			info->cor1 = Cy_6_BITS;
			break;
		case CS7:
			info->cor1 = Cy_7_BITS;
			break;
		case CS8:
			info->cor1 = Cy_8_BITS;
			break;
		}
A
Alan Cox 已提交
2105
		if (cflag & CSTOPB)
2106
			info->cor1 |= Cy_2_STOP;
A
Alan Cox 已提交
2107

2108
		if (cflag & PARENB) {
A
Alan Cox 已提交
2109
			if (cflag & PARODD)
2110
				info->cor1 |= CyPARITY_O;
A
Alan Cox 已提交
2111
			else
2112
				info->cor1 |= CyPARITY_E;
A
Alan Cox 已提交
2113
		} else
2114 2115 2116 2117
			info->cor1 |= CyPARITY_NONE;

		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
A
Alan Cox 已提交
2118
			info->port.flags |= ASYNC_CTS_FLOW;
2119 2120
			info->cor2 |= CyCtsAE;
		} else {
A
Alan Cox 已提交
2121
			info->port.flags &= ~ASYNC_CTS_FLOW;
2122 2123 2124
			info->cor2 &= ~CyCtsAE;
		}
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2125
			info->port.flags &= ~ASYNC_CHECK_CD;
2126
		else
A
Alan Cox 已提交
2127
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138

	 /***********************************************
	    The hardware option, CyRtsAO, presents RTS when
	    the chip has characters to send.  Since most modems
	    use RTS as reverse (inbound) flow control, this
	    option is not used.  If inbound flow control is
	    necessary, DTR can be programmed to provide the
	    appropriate signals for use with a non-standard
	    cable.  Contact Marcio Saito for details.
	 ***********************************************/

2139
		channel &= 0x03;
L
Linus Torvalds 已提交
2140

2141
		spin_lock_irqsave(&card->card_lock, flags);
2142
		cyy_writeb(info, CyCAR, channel);
2143 2144 2145

		/* tx and rx baud rate */

2146 2147 2148 2149
		cyy_writeb(info, CyTCOR, info->tco);
		cyy_writeb(info, CyTBPR, info->tbpr);
		cyy_writeb(info, CyRCOR, info->rco);
		cyy_writeb(info, CyRBPR, info->rbpr);
2150 2151 2152

		/* set line characteristics  according configuration */

2153 2154 2155 2156 2157 2158 2159
		cyy_writeb(info, CySCHR1, START_CHAR(tty));
		cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
		cyy_writeb(info, CyCOR1, info->cor1);
		cyy_writeb(info, CyCOR2, info->cor2);
		cyy_writeb(info, CyCOR3, info->cor3);
		cyy_writeb(info, CyCOR4, info->cor4);
		cyy_writeb(info, CyCOR5, info->cor5);
2160

2161 2162
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
				CyCOR3ch);
2163

A
Alan Cox 已提交
2164
		/* !!! Is this needed? */
2165 2166
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, CyRTPR,
2167 2168 2169
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */

2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181
		cflags = CyCTS;
		if (!C_CLOCAL(tty))
			cflags |= CyDSR | CyRI | CyDCD;
		/* without modem intr */
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
		/* act on 1->0 modem transitions */
		if ((cflag & CRTSCTS) && info->rflow)
			cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
		else
			cyy_writeb(info, CyMCOR1, cflags);
		/* act on 0->1 modem transitions */
		cyy_writeb(info, CyMCOR2, cflags);
2182

J
Jiri Slaby 已提交
2183 2184 2185 2186
		if (i == 0)	/* baud rate is zero, turn off line */
			cyy_change_rts_dtr(info, 0, TIOCM_DTR);
		else
			cyy_change_rts_dtr(info, TIOCM_DTR, 0);
L
Linus Torvalds 已提交
2187

J
Jiri Slaby 已提交
2188
		clear_bit(TTY_IO_ERROR, &tty->flags);
2189
		spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
2190 2191

	} else {
2192
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
K
Klaus Kudielka 已提交
2193
		__u32 sw_flow;
2194
		int retval;
L
Linus Torvalds 已提交
2195

2196
		if (!cyz_is_loaded(card))
2197
			return;
L
Linus Torvalds 已提交
2198

2199
		/* baud rate */
J
Jiri Slaby 已提交
2200
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2201
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
				ASYNC_SPD_CUST) {
			if (info->custom_divisor)
				baud_rate = info->baud / info->custom_divisor;
			else
				baud_rate = info->baud;
		} else if (baud > CYZ_MAX_SPEED) {
			baud = CYZ_MAX_SPEED;
		}
		cy_writel(&ch_ctrl->comm_baud, baud);

		if (baud == 134) {
			/* get it right for 134.5 baud */
			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
					2;
A
Alan Cox 已提交
2216
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
				ASYNC_SPD_CUST) {
			info->timeout = (info->xmit_fifo_size * HZ * 15 /
					baud_rate) + 2;
		} else if (baud) {
			info->timeout = (info->xmit_fifo_size * HZ * 15 /
					baud) + 2;
			/* this needs to be propagated into the card info */
		} else {
			info->timeout = 0;
		}
L
Linus Torvalds 已提交
2227

2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244
		/* byte size and parity */
		switch (cflag & CSIZE) {
		case CS5:
			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
			break;
		case CS6:
			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
			break;
		case CS7:
			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
			break;
		case CS8:
			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
			break;
		}
		if (cflag & CSTOPB) {
			cy_writel(&ch_ctrl->comm_data_l,
2245
				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
2246 2247
		} else {
			cy_writel(&ch_ctrl->comm_data_l,
2248
				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
2249 2250
		}
		if (cflag & PARENB) {
A
Alan Cox 已提交
2251
			if (cflag & PARODD)
2252
				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
A
Alan Cox 已提交
2253
			else
2254
				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
A
Alan Cox 已提交
2255
		} else
2256
			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
L
Linus Torvalds 已提交
2257

2258 2259 2260
		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
			cy_writel(&ch_ctrl->hw_flow,
2261
				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
2262
		} else {
2263 2264
			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
					~(C_RS_CTS | C_RS_RTS));
2265 2266 2267
		}
		/* As the HW flow control is done in firmware, the driver
		   doesn't need to care about it */
A
Alan Cox 已提交
2268
		info->port.flags &= ~ASYNC_CTS_FLOW;
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278

		/* XON/XOFF/XANY flow control flags */
		sw_flow = 0;
		if (iflag & IXON) {
			sw_flow |= C_FL_OXX;
			if (iflag & IXANY)
				sw_flow |= C_FL_OIXANY;
		}
		cy_writel(&ch_ctrl->sw_flow, sw_flow);

2279
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
2280
		if (retval != 0) {
J
Jiri Slaby 已提交
2281 2282
			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
				"was %x\n", info->line, retval);
2283 2284 2285
		}

		/* CD sensitivity */
A
Alan Cox 已提交
2286
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2287
			info->port.flags &= ~ASYNC_CHECK_CD;
A
Alan Cox 已提交
2288
		else
A
Alan Cox 已提交
2289
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2290

2291 2292
		if (baud == 0) {	/* baud rate is zero, turn off line */
			cy_writel(&ch_ctrl->rs_control,
2293
				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
L
Linus Torvalds 已提交
2294
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2295
			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
L
Linus Torvalds 已提交
2296
#endif
2297 2298
		} else {
			cy_writel(&ch_ctrl->rs_control,
2299
				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
L
Linus Torvalds 已提交
2300
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2301
			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
L
Linus Torvalds 已提交
2302
#endif
2303
		}
L
Linus Torvalds 已提交
2304

A
Alan Cox 已提交
2305
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
2306
		if (retval != 0) {
J
Jiri Slaby 已提交
2307 2308
			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
				"was %x\n", info->line, retval);
2309
		}
L
Linus Torvalds 已提交
2310

J
Jiri Slaby 已提交
2311
		clear_bit(TTY_IO_ERROR, &tty->flags);
L
Linus Torvalds 已提交
2312
	}
2313
}				/* set_line_char */
L
Linus Torvalds 已提交
2314

J
Jiri Slaby 已提交
2315
static int cy_get_serial_info(struct cyclades_port *info,
A
Alan Cox 已提交
2316
		struct serial_struct __user *retinfo)
L
Linus Torvalds 已提交
2317
{
2318
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331
	struct serial_struct tmp = {
		.type = info->type,
		.line = info->line,
		.port = (info->card - cy_card) * 0x100 + info->line -
			cinfo->first_line,
		.irq = cinfo->irq,
		.flags = info->port.flags,
		.close_delay = info->port.close_delay,
		.closing_wait = info->port.closing_wait,
		.baud_base = info->baud,
		.custom_divisor = info->custom_divisor,
		.hub6 = 0,		/*!!! */
	};
2332
	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
J
Jiri Slaby 已提交
2333
}
L
Linus Torvalds 已提交
2334 2335

static int
J
Jiri Slaby 已提交
2336
cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
A
Alan Cox 已提交
2337
		struct serial_struct __user *new_info)
L
Linus Torvalds 已提交
2338
{
2339
	struct serial_struct new_serial;
A
Alan Cox 已提交
2340
	int ret;
2341 2342 2343 2344

	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
		return -EFAULT;

A
Alan Cox 已提交
2345
	mutex_lock(&info->port.mutex);
2346
	if (!capable(CAP_SYS_ADMIN)) {
A
Alan Cox 已提交
2347
		if (new_serial.close_delay != info->port.close_delay ||
2348 2349 2350
				new_serial.baud_base != info->baud ||
				(new_serial.flags & ASYNC_FLAGS &
					~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
2351
				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
A
Alan Cox 已提交
2352 2353
		{
			mutex_unlock(&info->port.mutex);
2354
			return -EPERM;
A
Alan Cox 已提交
2355
		}
A
Alan Cox 已提交
2356
		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
				(new_serial.flags & ASYNC_USR_MASK);
		info->baud = new_serial.baud_base;
		info->custom_divisor = new_serial.custom_divisor;
		goto check_and_exit;
	}

	/*
	 * OK, past this point, all the error checking has been done.
	 * At this point, we start making changes.....
	 */

	info->baud = new_serial.baud_base;
	info->custom_divisor = new_serial.custom_divisor;
A
Alan Cox 已提交
2370
	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
2371
			(new_serial.flags & ASYNC_FLAGS);
A
Alan Cox 已提交
2372 2373
	info->port.close_delay = new_serial.close_delay * HZ / 100;
	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
L
Linus Torvalds 已提交
2374 2375

check_and_exit:
A
Alan Cox 已提交
2376
	if (info->port.flags & ASYNC_INITIALIZED) {
J
Jiri Slaby 已提交
2377
		cy_set_line_char(info, tty);
A
Alan Cox 已提交
2378
		ret = 0;
2379
	} else {
A
Alan Cox 已提交
2380
		ret = cy_startup(info, tty);
2381
	}
A
Alan Cox 已提交
2382 2383
	mutex_unlock(&info->port.mutex);
	return ret;
2384
}				/* set_serial_info */
L
Linus Torvalds 已提交
2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395

/*
 * get_lsr_info - get line status register info
 *
 * Purpose: Let user call ioctl() to get info when the UART physically
 *	    is emptied.  On bus types like RS485, the transmitter must
 *	    release the bus after transmitting. This must be done when
 *	    the transmit shift register is empty, not be done when the
 *	    transmit holding register is empty.  This functionality
 *	    allows an RS485 driver to be written in user space.
 */
A
Alan Cox 已提交
2396
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
L
Linus Torvalds 已提交
2397
{
2398
	struct cyclades_card *card = info->card;
2399 2400
	unsigned int result;
	unsigned long flags;
2401
	u8 status;
L
Linus Torvalds 已提交
2402

2403
	if (!cy_is_Z(card)) {
2404
		spin_lock_irqsave(&card->card_lock, flags);
2405
		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
2406
		spin_unlock_irqrestore(&card->card_lock, flags);
2407 2408 2409 2410 2411
		result = (status ? 0 : TIOCSER_TEMT);
	} else {
		/* Not supported yet */
		return -EINVAL;
	}
2412
	return put_user(result, value);
L
Linus Torvalds 已提交
2413 2414
}

2415
static int cy_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
2416
{
2417
	struct cyclades_port *info = tty->driver_data;
2418
	struct cyclades_card *card;
2419
	int result;
2420

2421
	if (serial_paranoia_check(info, tty->name, __func__))
2422
		return -ENODEV;
L
Linus Torvalds 已提交
2423

2424
	card = info->card;
J
Jiri Slaby 已提交
2425

2426
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2427
		unsigned long flags;
2428 2429
		int channel = info->line - card->first_line;
		u8 status;
L
Linus Torvalds 已提交
2430

2431
		spin_lock_irqsave(&card->card_lock, flags);
2432 2433 2434
		cyy_writeb(info, CyCAR, channel & 0x03);
		status = cyy_readb(info, CyMSVR1);
		status |= cyy_readb(info, CyMSVR2);
2435
		spin_unlock_irqrestore(&card->card_lock, flags);
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447

		if (info->rtsdtr_inv) {
			result = ((status & CyRTS) ? TIOCM_DTR : 0) |
				((status & CyDTR) ? TIOCM_RTS : 0);
		} else {
			result = ((status & CyRTS) ? TIOCM_RTS : 0) |
				((status & CyDTR) ? TIOCM_DTR : 0);
		}
		result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
			((status & CyRI) ? TIOCM_RNG : 0) |
			((status & CyDSR) ? TIOCM_DSR : 0) |
			((status & CyCTS) ? TIOCM_CTS : 0);
L
Linus Torvalds 已提交
2448
	} else {
J
Jiri Slaby 已提交
2449 2450 2451 2452 2453
		u32 lstatus;

		if (!cyz_is_loaded(card)) {
			result = -ENODEV;
			goto end;
2454
		}
L
Linus Torvalds 已提交
2455

J
Jiri Slaby 已提交
2456 2457 2458 2459 2460 2461 2462
		lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
		result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
			((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
			((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
			((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
			((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
			((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
2463
	}
J
Jiri Slaby 已提交
2464
end:
2465 2466
	return result;
}				/* cy_tiomget */
L
Linus Torvalds 已提交
2467 2468

static int
2469
cy_tiocmset(struct tty_struct *tty,
2470
		unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
2471
{
2472
	struct cyclades_port *info = tty->driver_data;
2473
	struct cyclades_card *card;
2474 2475
	unsigned long flags;

2476
	if (serial_paranoia_check(info, tty->name, __func__))
2477 2478 2479
		return -ENODEV;

	card = info->card;
2480
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2481 2482 2483
		spin_lock_irqsave(&card->card_lock, flags);
		cyy_change_rts_dtr(info, set, clear);
		spin_unlock_irqrestore(&card->card_lock, flags);
2484
	} else {
J
Jiri Slaby 已提交
2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
		int retval, channel = info->line - card->first_line;
		u32 rs;

		if (!cyz_is_loaded(card))
			return -ENODEV;

		spin_lock_irqsave(&card->card_lock, flags);
		rs = readl(&ch_ctrl->rs_control);
		if (set & TIOCM_RTS)
			rs |= C_RS_RTS;
		if (clear & TIOCM_RTS)
			rs &= ~C_RS_RTS;
		if (set & TIOCM_DTR) {
			rs |= C_RS_DTR;
L
Linus Torvalds 已提交
2500
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2501
			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
L
Linus Torvalds 已提交
2502
#endif
J
Jiri Slaby 已提交
2503 2504 2505
		}
		if (clear & TIOCM_DTR) {
			rs &= ~C_RS_DTR;
L
Linus Torvalds 已提交
2506
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2507 2508
			printk(KERN_DEBUG "cyc:set_modem_info clearing "
				"Z DTR\n");
L
Linus Torvalds 已提交
2509
#endif
2510
		}
J
Jiri Slaby 已提交
2511
		cy_writel(&ch_ctrl->rs_control, rs);
2512
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
J
Jiri Slaby 已提交
2513
		spin_unlock_irqrestore(&card->card_lock, flags);
2514
		if (retval != 0) {
J
Jiri Slaby 已提交
2515 2516
			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
				"was %x\n", info->line, retval);
2517
		}
L
Linus Torvalds 已提交
2518
	}
2519
	return 0;
J
Jiri Slaby 已提交
2520
}
L
Linus Torvalds 已提交
2521 2522 2523 2524

/*
 * cy_break() --- routine which turns the break handling on or off
 */
A
Alan Cox 已提交
2525
static int cy_break(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
2526
{
2527
	struct cyclades_port *info = tty->driver_data;
2528
	struct cyclades_card *card;
2529
	unsigned long flags;
A
Alan Cox 已提交
2530
	int retval = 0;
L
Linus Torvalds 已提交
2531

2532
	if (serial_paranoia_check(info, tty->name, "cy_break"))
A
Alan Cox 已提交
2533
		return -EINVAL;
L
Linus Torvalds 已提交
2534

2535 2536 2537
	card = info->card;

	spin_lock_irqsave(&card->card_lock, flags);
2538
	if (!cy_is_Z(card)) {
2539 2540 2541 2542 2543 2544 2545
		/* Let the transmit ISR take care of this (since it
		   requires stuffing characters into the output stream).
		 */
		if (break_state == -1) {
			if (!info->breakon) {
				info->breakon = 1;
				if (!info->xmit_cnt) {
2546
					spin_unlock_irqrestore(&card->card_lock, flags);
2547
					start_xmit(info);
2548
					spin_lock_irqsave(&card->card_lock, flags);
2549 2550 2551 2552 2553 2554
				}
			}
		} else {
			if (!info->breakoff) {
				info->breakoff = 1;
				if (!info->xmit_cnt) {
2555
					spin_unlock_irqrestore(&card->card_lock, flags);
2556
					start_xmit(info);
2557
					spin_lock_irqsave(&card->card_lock, flags);
2558 2559
				}
			}
L
Linus Torvalds 已提交
2560 2561
		}
	} else {
2562
		if (break_state == -1) {
2563 2564
			retval = cyz_issue_cmd(card,
				info->line - card->first_line,
2565 2566
				C_CM_SET_BREAK, 0L);
			if (retval != 0) {
J
Jiri Slaby 已提交
2567 2568
				printk(KERN_ERR "cyc:cy_break (set) retval on "
					"ttyC%d was %x\n", info->line, retval);
2569 2570
			}
		} else {
2571 2572
			retval = cyz_issue_cmd(card,
				info->line - card->first_line,
2573 2574
				C_CM_CLR_BREAK, 0L);
			if (retval != 0) {
J
Jiri Slaby 已提交
2575 2576 2577
				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
					"on ttyC%d was %x\n", info->line,
					retval);
2578
			}
L
Linus Torvalds 已提交
2579 2580
		}
	}
2581
	spin_unlock_irqrestore(&card->card_lock, flags);
A
Alan Cox 已提交
2582
	return retval;
2583
}				/* cy_break */
L
Linus Torvalds 已提交
2584

2585
static int set_threshold(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2586
{
2587
	struct cyclades_card *card = info->card;
2588
	unsigned long flags;
L
Linus Torvalds 已提交
2589

2590
	if (!cy_is_Z(card)) {
2591 2592
		info->cor3 &= ~CyREC_FIFO;
		info->cor3 |= value & CyREC_FIFO;
L
Linus Torvalds 已提交
2593

2594
		spin_lock_irqsave(&card->card_lock, flags);
2595 2596
		cyy_writeb(info, CyCOR3, info->cor3);
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
2597
		spin_unlock_irqrestore(&card->card_lock, flags);
2598 2599 2600
	}
	return 0;
}				/* set_threshold */
L
Linus Torvalds 已提交
2601

A
Alan Cox 已提交
2602 2603
static int get_threshold(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2604
{
2605
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2606

2607
	if (!cy_is_Z(card)) {
2608
		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
2609 2610
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2611
	return 0;
2612
}				/* get_threshold */
L
Linus Torvalds 已提交
2613

2614
static int set_timeout(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2615
{
2616
	struct cyclades_card *card = info->card;
2617
	unsigned long flags;
L
Linus Torvalds 已提交
2618

2619
	if (!cy_is_Z(card)) {
2620
		spin_lock_irqsave(&card->card_lock, flags);
2621
		cyy_writeb(info, CyRTPR, value & 0xff);
2622
		spin_unlock_irqrestore(&card->card_lock, flags);
2623 2624 2625
	}
	return 0;
}				/* set_timeout */
L
Linus Torvalds 已提交
2626

A
Alan Cox 已提交
2627 2628
static int get_timeout(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2629
{
2630
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2631

2632
	if (!cy_is_Z(card)) {
2633
		u8 tmp = cyy_readb(info, CyRTPR);
2634 2635
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2636
	return 0;
2637
}				/* get_timeout */
L
Linus Torvalds 已提交
2638

J
Jiri Slaby 已提交
2639 2640
static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
		struct cyclades_icount *cprev)
L
Linus Torvalds 已提交
2641
{
J
Jiri Slaby 已提交
2642 2643 2644
	struct cyclades_icount cnow;
	unsigned long flags;
	int ret;
L
Linus Torvalds 已提交
2645

J
Jiri Slaby 已提交
2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
	spin_lock_irqsave(&info->card->card_lock, flags);
	cnow = info->icount;	/* atomic copy */
	spin_unlock_irqrestore(&info->card->card_lock, flags);

	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));

	*cprev = cnow;

	return ret;
}
L
Linus Torvalds 已提交
2659 2660 2661 2662 2663 2664 2665

/*
 * This routine allows the tty driver to implement device-
 * specific ioctl's.  If the ioctl number passed in cmd is
 * not recognized by the driver, it should return ENOIOCTLCMD.
 */
static int
2666
cy_ioctl(struct tty_struct *tty,
2667
	 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2668
{
2669
	struct cyclades_port *info = tty->driver_data;
J
Jiri Slaby 已提交
2670
	struct cyclades_icount cnow;	/* kernel counter temps */
2671 2672 2673 2674 2675 2676
	int ret_val = 0;
	unsigned long flags;
	void __user *argp = (void __user *)arg;

	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
		return -ENODEV;
L
Linus Torvalds 已提交
2677 2678

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2679 2680
	printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
		info->line, cmd, arg);
L
Linus Torvalds 已提交
2681 2682
#endif

2683 2684
	switch (cmd) {
	case CYGETMON:
J
Jiri Slaby 已提交
2685 2686 2687 2688 2689
		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
			ret_val = -EFAULT;
			break;
		}
		memset(&info->mon, 0, sizeof(info->mon));
2690 2691 2692 2693 2694 2695 2696 2697
		break;
	case CYGETTHRESH:
		ret_val = get_threshold(info, argp);
		break;
	case CYSETTHRESH:
		ret_val = set_threshold(info, arg);
		break;
	case CYGETDEFTHRESH:
J
Jiri Slaby 已提交
2698 2699
		ret_val = put_user(info->default_threshold,
				(unsigned long __user *)argp);
2700 2701
		break;
	case CYSETDEFTHRESH:
J
Jiri Slaby 已提交
2702
		info->default_threshold = arg & 0x0f;
2703 2704 2705 2706 2707 2708 2709 2710
		break;
	case CYGETTIMEOUT:
		ret_val = get_timeout(info, argp);
		break;
	case CYSETTIMEOUT:
		ret_val = set_timeout(info, arg);
		break;
	case CYGETDEFTIMEOUT:
J
Jiri Slaby 已提交
2711 2712
		ret_val = put_user(info->default_timeout,
				(unsigned long __user *)argp);
2713 2714
		break;
	case CYSETDEFTIMEOUT:
J
Jiri Slaby 已提交
2715
		info->default_timeout = arg & 0xff;
2716
		break;
L
Linus Torvalds 已提交
2717
	case CYSETRFLOW:
2718 2719
		info->rflow = (int)arg;
		break;
L
Linus Torvalds 已提交
2720
	case CYGETRFLOW:
2721 2722
		ret_val = info->rflow;
		break;
L
Linus Torvalds 已提交
2723
	case CYSETRTSDTR_INV:
2724 2725
		info->rtsdtr_inv = (int)arg;
		break;
L
Linus Torvalds 已提交
2726
	case CYGETRTSDTR_INV:
2727 2728
		ret_val = info->rtsdtr_inv;
		break;
L
Linus Torvalds 已提交
2729
	case CYGETCD1400VER:
2730 2731
		ret_val = info->chip_rev;
		break;
L
Linus Torvalds 已提交
2732 2733
#ifndef CONFIG_CYZ_INTR
	case CYZSETPOLLCYCLE:
2734 2735
		cyz_polling_cycle = (arg * HZ) / 1000;
		break;
L
Linus Torvalds 已提交
2736
	case CYZGETPOLLCYCLE:
2737 2738 2739
		ret_val = (cyz_polling_cycle * 1000) / HZ;
		break;
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
2740
	case CYSETWAIT:
A
Alan Cox 已提交
2741
		info->port.closing_wait = (unsigned short)arg * HZ / 100;
2742
		break;
L
Linus Torvalds 已提交
2743
	case CYGETWAIT:
A
Alan Cox 已提交
2744
		ret_val = info->port.closing_wait / (HZ / 100);
2745 2746
		break;
	case TIOCGSERIAL:
J
Jiri Slaby 已提交
2747
		ret_val = cy_get_serial_info(info, argp);
2748 2749
		break;
	case TIOCSSERIAL:
J
Jiri Slaby 已提交
2750
		ret_val = cy_set_serial_info(info, tty, argp);
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760
		break;
	case TIOCSERGETLSR:	/* Get line status register */
		ret_val = get_lsr_info(info, argp);
		break;
		/*
		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
		 * - mask passed in arg for lines of interest
		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
		 * Caller should use TIOCGICOUNT to see which one it was
		 */
L
Linus Torvalds 已提交
2761
	case TIOCMIWAIT:
2762
		spin_lock_irqsave(&info->card->card_lock, flags);
2763
		/* note the counters on entry */
J
Jiri Slaby 已提交
2764
		cnow = info->icount;
2765
		spin_unlock_irqrestore(&info->card->card_lock, flags);
2766
		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
J
Jiri Slaby 已提交
2767
				cy_cflags_changed(info, arg, &cnow));
J
Jiri Slaby 已提交
2768
		break;
L
Linus Torvalds 已提交
2769

2770 2771 2772 2773 2774 2775 2776 2777 2778
		/*
		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
		 * Return: write counters to the user passed counter struct
		 * NB: both 1->0 and 0->1 transitions are counted except for
		 *     RI where only 0->1 is counted.
		 */
	default:
		ret_val = -ENOIOCTLCMD;
	}
L
Linus Torvalds 已提交
2779 2780

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2781
	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
L
Linus Torvalds 已提交
2782
#endif
2783 2784
	return ret_val;
}				/* cy_ioctl */
L
Linus Torvalds 已提交
2785

2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
static int cy_get_icount(struct tty_struct *tty,
				struct serial_icounter_struct *sic)
{
	struct cyclades_port *info = tty->driver_data;
	struct cyclades_icount cnow;	/* Used to snapshot */
	unsigned long flags;

	spin_lock_irqsave(&info->card->card_lock, flags);
	cnow = info->icount;
	spin_unlock_irqrestore(&info->card->card_lock, flags);

	sic->cts = cnow.cts;
	sic->dsr = cnow.dsr;
	sic->rng = cnow.rng;
	sic->dcd = cnow.dcd;
	sic->rx = cnow.rx;
	sic->tx = cnow.tx;
	sic->frame = cnow.frame;
	sic->overrun = cnow.overrun;
	sic->parity = cnow.parity;
	sic->brk = cnow.brk;
	sic->buf_overrun = cnow.buf_overrun;
	return 0;
}

L
Linus Torvalds 已提交
2811 2812 2813 2814 2815 2816
/*
 * This routine allows the tty driver to be notified when
 * device's termios settings have changed.  Note that a
 * well-designed tty driver should be prepared to accept the case
 * where old == NULL, and try to do something rational.
 */
2817
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
L
Linus Torvalds 已提交
2818
{
2819
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
2820 2821

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2822
	printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
L
Linus Torvalds 已提交
2823 2824
#endif

J
Jiri Slaby 已提交
2825
	cy_set_line_char(info, tty);
2826 2827 2828 2829 2830 2831

	if ((old_termios->c_cflag & CRTSCTS) &&
			!(tty->termios->c_cflag & CRTSCTS)) {
		tty->hw_stopped = 0;
		cy_start(tty);
	}
L
Linus Torvalds 已提交
2832
#if 0
2833 2834 2835 2836 2837 2838 2839 2840
	/*
	 * No need to wake up processes in open wait, since they
	 * sample the CLOCAL flag once, and don't recheck it.
	 * XXX  It's not clear whether the current behavior is correct
	 * or not.  Hence, this may change.....
	 */
	if (!(old_termios->c_cflag & CLOCAL) &&
	    (tty->termios->c_cflag & CLOCAL))
A
Alan Cox 已提交
2841
		wake_up_interruptible(&info->port.open_wait);
L
Linus Torvalds 已提交
2842
#endif
2843
}				/* cy_set_termios */
L
Linus Torvalds 已提交
2844 2845 2846 2847

/* This function is used to send a high-priority XON/XOFF character to
   the device.
*/
2848
static void cy_send_xchar(struct tty_struct *tty, char ch)
L
Linus Torvalds 已提交
2849
{
2850
	struct cyclades_port *info = tty->driver_data;
2851 2852
	struct cyclades_card *card;
	int channel;
L
Linus Torvalds 已提交
2853

2854
	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
L
Linus Torvalds 已提交
2855 2856
		return;

2857
	info->x_char = ch;
L
Linus Torvalds 已提交
2858 2859

	if (ch)
2860
		cy_start(tty);
L
Linus Torvalds 已提交
2861 2862

	card = info->card;
2863
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
2864

2865
	if (cy_is_Z(card)) {
2866
		if (ch == STOP_CHAR(tty))
2867
			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
2868
		else if (ch == START_CHAR(tty))
2869
			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
L
Linus Torvalds 已提交
2870 2871 2872 2873 2874 2875 2876
	}
}

/* This routine is called by the upper-layer tty layer to signal
   that incoming characters should be throttled because the input
   buffers are close to full.
 */
2877
static void cy_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2878
{
2879
	struct cyclades_port *info = tty->driver_data;
2880
	struct cyclades_card *card;
2881
	unsigned long flags;
L
Linus Torvalds 已提交
2882 2883

#ifdef CY_DEBUG_THROTTLE
2884
	char buf[64];
L
Linus Torvalds 已提交
2885

J
Jiri Slaby 已提交
2886
	printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
2887
			tty->ldisc.chars_in_buffer(tty), info->line);
L
Linus Torvalds 已提交
2888 2889
#endif

A
Alan Cox 已提交
2890
	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2891 2892 2893 2894 2895
		return;

	card = info->card;

	if (I_IXOFF(tty)) {
2896
		if (!cy_is_Z(card))
2897 2898 2899 2900
			cy_send_xchar(tty, STOP_CHAR(tty));
		else
			info->throttle = 1;
	}
L
Linus Torvalds 已提交
2901

2902
	if (tty->termios->c_cflag & CRTSCTS) {
2903
		if (!cy_is_Z(card)) {
2904
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2905
			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
2906
			spin_unlock_irqrestore(&card->card_lock, flags);
2907 2908 2909 2910 2911
		} else {
			info->throttle = 1;
		}
	}
}				/* cy_throttle */
L
Linus Torvalds 已提交
2912 2913 2914 2915 2916 2917

/*
 * This routine notifies the tty driver that it should signal
 * that characters can now be sent to the tty without fear of
 * overrunning the input buffers of the line disciplines.
 */
2918
static void cy_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2919
{
2920
	struct cyclades_port *info = tty->driver_data;
2921
	struct cyclades_card *card;
2922
	unsigned long flags;
L
Linus Torvalds 已提交
2923 2924

#ifdef CY_DEBUG_THROTTLE
2925 2926
	char buf[64];

J
Jiri Slaby 已提交
2927
	printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
A
Alan Cox 已提交
2928
		tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
L
Linus Torvalds 已提交
2929 2930
#endif

A
Alan Cox 已提交
2931
	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2932
		return;
L
Linus Torvalds 已提交
2933

2934 2935 2936 2937 2938
	if (I_IXOFF(tty)) {
		if (info->x_char)
			info->x_char = 0;
		else
			cy_send_xchar(tty, START_CHAR(tty));
L
Linus Torvalds 已提交
2939 2940
	}

2941 2942
	if (tty->termios->c_cflag & CRTSCTS) {
		card = info->card;
2943
		if (!cy_is_Z(card)) {
2944
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2945
			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
2946
			spin_unlock_irqrestore(&card->card_lock, flags);
2947 2948 2949 2950 2951
		} else {
			info->throttle = 0;
		}
	}
}				/* cy_unthrottle */
L
Linus Torvalds 已提交
2952 2953 2954 2955

/* cy_start and cy_stop provide software output flow control as a
   function of XON/XOFF, software CTS, and other such stuff.
*/
2956
static void cy_stop(struct tty_struct *tty)
L
Linus Torvalds 已提交
2957
{
2958
	struct cyclades_card *cinfo;
2959
	struct cyclades_port *info = tty->driver_data;
2960
	int channel;
2961
	unsigned long flags;
L
Linus Torvalds 已提交
2962 2963

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2964
	printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
L
Linus Torvalds 已提交
2965 2966
#endif

2967 2968
	if (serial_paranoia_check(info, tty->name, "cy_stop"))
		return;
L
Linus Torvalds 已提交
2969

2970
	cinfo = info->card;
2971
	channel = info->line - cinfo->first_line;
2972
	if (!cy_is_Z(cinfo)) {
2973
		spin_lock_irqsave(&cinfo->card_lock, flags);
2974 2975
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
2976
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2977 2978
	}
}				/* cy_stop */
L
Linus Torvalds 已提交
2979

2980
static void cy_start(struct tty_struct *tty)
L
Linus Torvalds 已提交
2981
{
2982
	struct cyclades_card *cinfo;
2983
	struct cyclades_port *info = tty->driver_data;
2984
	int channel;
2985
	unsigned long flags;
L
Linus Torvalds 已提交
2986 2987

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2988
	printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
L
Linus Torvalds 已提交
2989 2990
#endif

2991 2992
	if (serial_paranoia_check(info, tty->name, "cy_start"))
		return;
L
Linus Torvalds 已提交
2993

2994
	cinfo = info->card;
2995
	channel = info->line - cinfo->first_line;
2996
	if (!cy_is_Z(cinfo)) {
2997
		spin_lock_irqsave(&cinfo->card_lock, flags);
2998 2999
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
3000
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
3001 3002
	}
}				/* cy_start */
L
Linus Torvalds 已提交
3003 3004 3005 3006

/*
 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
 */
3007
static void cy_hangup(struct tty_struct *tty)
L
Linus Torvalds 已提交
3008
{
3009
	struct cyclades_port *info = tty->driver_data;
3010

L
Linus Torvalds 已提交
3011
#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
3012
	printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
L
Linus Torvalds 已提交
3013 3014
#endif

3015 3016
	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
		return;
L
Linus Torvalds 已提交
3017

3018
	cy_flush_buffer(tty);
J
Jiri Slaby 已提交
3019
	cy_shutdown(info, tty);
J
Jiri Slaby 已提交
3020
	tty_port_hangup(&info->port);
3021
}				/* cy_hangup */
L
Linus Torvalds 已提交
3022

J
Jiri Slaby 已提交
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032
static int cyy_carrier_raised(struct tty_port *port)
{
	struct cyclades_port *info = container_of(port, struct cyclades_port,
			port);
	struct cyclades_card *cinfo = info->card;
	unsigned long flags;
	int channel = info->line - cinfo->first_line;
	u32 cd;

	spin_lock_irqsave(&cinfo->card_lock, flags);
3033 3034
	cyy_writeb(info, CyCAR, channel & 0x03);
	cd = cyy_readb(info, CyMSVR1) & CyDCD;
J
Jiri Slaby 已提交
3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
	spin_unlock_irqrestore(&cinfo->card_lock, flags);

	return cd;
}

static void cyy_dtr_rts(struct tty_port *port, int raise)
{
	struct cyclades_port *info = container_of(port, struct cyclades_port,
			port);
	struct cyclades_card *cinfo = info->card;
	unsigned long flags;

	spin_lock_irqsave(&cinfo->card_lock, flags);
J
Jiri Slaby 已提交
3048 3049
	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
J
Jiri Slaby 已提交
3050 3051 3052 3053 3054 3055 3056 3057
	spin_unlock_irqrestore(&cinfo->card_lock, flags);
}

static int cyz_carrier_raised(struct tty_port *port)
{
	struct cyclades_port *info = container_of(port, struct cyclades_port,
			port);

3058
	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
J
Jiri Slaby 已提交
3059 3060 3061 3062 3063 3064 3065
}

static void cyz_dtr_rts(struct tty_port *port, int raise)
{
	struct cyclades_port *info = container_of(port, struct cyclades_port,
			port);
	struct cyclades_card *cinfo = info->card;
3066
	struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
J
Jiri Slaby 已提交
3067 3068 3069
	int ret, channel = info->line - cinfo->first_line;
	u32 rs;

3070
	rs = readl(&ch_ctrl->rs_control);
J
Jiri Slaby 已提交
3071 3072 3073 3074
	if (raise)
		rs |= C_RS_RTS | C_RS_DTR;
	else
		rs &= ~(C_RS_RTS | C_RS_DTR);
3075
	cy_writel(&ch_ctrl->rs_control, rs);
J
Jiri Slaby 已提交
3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087
	ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
	if (ret != 0)
		printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
				__func__, info->line, ret);
#ifdef CY_DEBUG_DTR
	printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
#endif
}

static const struct tty_port_operations cyy_port_ops = {
	.carrier_raised = cyy_carrier_raised,
	.dtr_rts = cyy_dtr_rts,
3088
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3089 3090 3091 3092 3093
};

static const struct tty_port_operations cyz_port_ops = {
	.carrier_raised = cyz_carrier_raised,
	.dtr_rts = cyz_dtr_rts,
3094
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3095 3096
};

L
Linus Torvalds 已提交
3097 3098 3099 3100 3101 3102 3103 3104
/*
 * ---------------------------------------------------------------------
 * cy_init() and friends
 *
 * cy_init() is called at boot-time to initialize the serial driver.
 * ---------------------------------------------------------------------
 */

J
Jiri Slaby 已提交
3105
static int __devinit cy_init_card(struct cyclades_card *cinfo)
3106 3107
{
	struct cyclades_port *info;
3108
	unsigned int channel, port;
3109

3110
	spin_lock_init(&cinfo->card_lock);
J
Jiri Slaby 已提交
3111
	cinfo->intr_enabled = 0;
3112

J
Jiri Slaby 已提交
3113 3114
	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
			GFP_KERNEL);
J
Jiri Slaby 已提交
3115 3116 3117 3118 3119
	if (cinfo->ports == NULL) {
		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
		return -ENOMEM;
	}

3120 3121 3122
	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
			channel++, port++) {
		info = &cinfo->ports[channel];
A
Alan Cox 已提交
3123
		tty_port_init(&info->port);
3124
		info->magic = CYCLADES_MAGIC;
3125
		info->card = cinfo;
3126 3127
		info->line = port;

A
Alan Cox 已提交
3128 3129
		info->port.closing_wait = CLOSING_WAIT_DELAY;
		info->port.close_delay = 5 * HZ / 10;
A
Alan Cox 已提交
3130
		info->port.flags = STD_COM_FLAGS;
J
Jiri Slaby 已提交
3131
		init_completion(&info->shutdown_wait);
3132

3133
		if (cy_is_Z(cinfo)) {
3134 3135 3136
			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
			struct ZFW_CTRL *zfw_ctrl;

J
Jiri Slaby 已提交
3137
			info->port.ops = &cyz_port_ops;
3138
			info->type = PORT_STARTECH;
3139 3140 3141 3142 3143 3144

			zfw_ctrl = cinfo->base_addr +
				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
			info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
			info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];

J
Jiri Slaby 已提交
3145
			if (cinfo->hw_ver == ZO_V1)
3146 3147
				info->xmit_fifo_size = CYZ_FIFO_SIZE;
			else
3148
				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
3149
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3150 3151
			setup_timer(&cyz_rx_full_timer[port],
				cyz_rx_restart, (unsigned long)info);
3152
#endif
3153
		} else {
3154
			unsigned short chip_number;
J
Jiri Slaby 已提交
3155
			int index = cinfo->bus_index;
3156

J
Jiri Slaby 已提交
3157
			info->port.ops = &cyy_port_ops;
3158 3159
			info->type = PORT_CIRRUS;
			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
3160
			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
3161 3162
			info->cor2 = CyETC;
			info->cor3 = 0x08;	/* _very_ small rcv threshold */
3163

3164
			chip_number = channel / CyPORTS_PER_CHIP;
3165 3166 3167
			info->u.cyy.base_addr = cinfo->base_addr +
				(cy_chip_offset[chip_number] << index);
			info->chip_rev = cyy_readb(info, CyGFRCR);
A
Alan Cox 已提交
3168 3169

			if (info->chip_rev >= CD1400_REV_J) {
3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182
				/* It is a CD1400 rev. J or later */
				info->tbpr = baud_bpr_60[13];	/* Tx BPR */
				info->tco = baud_co_60[13];	/* Tx CO */
				info->rbpr = baud_bpr_60[13];	/* Rx BPR */
				info->rco = baud_co_60[13];	/* Rx CO */
				info->rtsdtr_inv = 1;
			} else {
				info->tbpr = baud_bpr_25[13];	/* Tx BPR */
				info->tco = baud_co_25[13];	/* Tx CO */
				info->rbpr = baud_bpr_25[13];	/* Rx BPR */
				info->rco = baud_co_25[13];	/* Rx CO */
				info->rtsdtr_inv = 0;
			}
3183 3184
			info->read_status_mask = CyTIMEOUT | CySPECHAR |
				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3185
		}
3186

3187
	}
3188 3189

#ifndef CONFIG_CYZ_INTR
3190
	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
3191 3192 3193 3194 3195 3196
		mod_timer(&cyz_timerlist, jiffies + 1);
#ifdef CY_PCI_DEBUG
		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
#endif
	}
#endif
J
Jiri Slaby 已提交
3197
	return 0;
3198 3199
}

L
Linus Torvalds 已提交
3200 3201
/* initialize chips on Cyclom-Y card -- return number of valid
   chips (which is number of ports/4) */
3202 3203
static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
		int index)
L
Linus Torvalds 已提交
3204
{
3205 3206 3207 3208 3209 3210 3211 3212 3213
	unsigned int chip_number;
	void __iomem *base_addr;

	cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
	/* Cy_HwReset is 0x1400 */
	cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
	/* Cy_ClrIntr is 0x1800 */
	udelay(500L);

A
Alan Cox 已提交
3214 3215
	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
							chip_number++) {
3216 3217 3218
		base_addr =
		    true_base_addr + (cy_chip_offset[chip_number] << index);
		mdelay(1);
3219
		if (readb(base_addr + (CyCCR << index)) != 0x00) {
3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235
			/*************
			printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
			chip_number, (unsigned long)base_addr);
			*************/
			return chip_number;
		}

		cy_writeb(base_addr + (CyGFRCR << index), 0);
		udelay(10L);

		/* The Cyclom-16Y does not decode address bit 9 and therefore
		   cannot distinguish between references to chip 0 and a non-
		   existent chip 4.  If the preceding clearing of the supposed
		   chip 4 GFRCR register appears at chip 0, there is no chip 4
		   and this must be a Cyclom-16Y, not a Cyclom-32Ye.
		 */
3236
		if (chip_number == 4 && readb(true_base_addr +
3237 3238 3239 3240 3241 3242 3243 3244
				(cy_chip_offset[0] << index) +
				(CyGFRCR << index)) == 0) {
			return chip_number;
		}

		cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
		mdelay(1);

3245
		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
3246 3247 3248 3249 3250 3251 3252
			/*
			   printk(" chip #%d at %#6lx is not responding ",
			   chip_number, (unsigned long)base_addr);
			   printk("(GFRCR stayed 0)\n",
			 */
			return chip_number;
		}
3253
		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
				0x40) {
			/*
			printk(" chip #%d at %#6lx is not valid (GFRCR == "
					"%#2x)\n",
					chip_number, (unsigned long)base_addr,
					base_addr[CyGFRCR<<index]);
			 */
			return chip_number;
		}
		cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
3264
		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
3265 3266 3267 3268 3269 3270 3271 3272
			/* It is a CD1400 rev. J or later */
			/* Impossible to reach 5ms with this chip.
			   Changed to 2ms instead (f = 500 Hz). */
			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
		} else {
			/* f = 200 Hz */
			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
		}
L
Linus Torvalds 已提交
3273

3274 3275 3276
		/*
		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
		   chip_number, (unsigned long)base_addr,
3277
		   readb(base_addr+(CyGFRCR<<index)));
3278 3279 3280 3281
		 */
	}
	return chip_number;
}				/* cyy_init_card */
L
Linus Torvalds 已提交
3282 3283 3284 3285 3286 3287 3288

/*
 * ---------------------------------------------------------------------
 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
 * sets global variables and return the number of ISA boards found.
 * ---------------------------------------------------------------------
 */
3289
static int __init cy_detect_isa(void)
L
Linus Torvalds 已提交
3290 3291
{
#ifdef CONFIG_ISA
3292
	struct cyclades_card *card;
3293 3294 3295 3296
	unsigned short cy_isa_irq, nboard;
	void __iomem *cy_isa_address;
	unsigned short i, j, cy_isa_nchan;
	int isparam = 0;
L
Linus Torvalds 已提交
3297

3298
	nboard = 0;
L
Linus Torvalds 已提交
3299 3300

	/* Check for module parameters */
3301 3302 3303 3304 3305 3306 3307
	for (i = 0; i < NR_CARDS; i++) {
		if (maddr[i] || i) {
			isparam = 1;
			cy_isa_addresses[i] = maddr[i];
		}
		if (!maddr[i])
			break;
L
Linus Torvalds 已提交
3308 3309
	}

3310 3311 3312
	/* scan the address table probing for Cyclom-Y/ISA boards */
	for (i = 0; i < NR_ISA_ADDRS; i++) {
		unsigned int isa_address = cy_isa_addresses[i];
A
Alan Cox 已提交
3313
		if (isa_address == 0x0000)
J
Jiri Slaby 已提交
3314
			return nboard;
L
Linus Torvalds 已提交
3315

3316
		/* probe for CD1400... */
3317
		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
J
Jiri Slaby 已提交
3318 3319 3320 3321 3322
		if (cy_isa_address == NULL) {
			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
					"address\n");
			continue;
		}
3323 3324 3325
		cy_isa_nchan = CyPORTS_PER_CHIP *
			cyy_init_card(cy_isa_address, 0);
		if (cy_isa_nchan == 0) {
J
Jiri Slaby 已提交
3326
			iounmap(cy_isa_address);
3327 3328
			continue;
		}
3329

R
Roel Kluin 已提交
3330
		if (isparam && i < NR_CARDS && irq[i])
3331
			cy_isa_irq = irq[i];
L
Linus Torvalds 已提交
3332
		else
3333 3334 3335
			/* find out the board's irq by probing */
			cy_isa_irq = detect_isa_irq(cy_isa_address);
		if (cy_isa_irq == 0) {
J
Jiri Slaby 已提交
3336 3337
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
				"IRQ could not be detected.\n",
3338
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3339
			iounmap(cy_isa_address);
3340 3341 3342 3343
			continue;
		}

		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
J
Jiri Slaby 已提交
3344 3345 3346
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
				"more channels are available. Change NR_PORTS "
				"in cyclades.c and recompile kernel.\n",
3347
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3348
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3349
			return nboard;
3350 3351 3352
		}
		/* fill the next cy_card structure available */
		for (j = 0; j < NR_CARDS; j++) {
3353 3354
			card = &cy_card[j];
			if (card->base_addr == NULL)
3355 3356 3357
				break;
		}
		if (j == NR_CARDS) {	/* no more cy_cards available */
J
Jiri Slaby 已提交
3358 3359 3360
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
				"more cards can be used. Change NR_CARDS in "
				"cyclades.c and recompile kernel.\n",
3361
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3362
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3363
			return nboard;
3364 3365 3366 3367
		}

		/* allocate IRQ */
		if (request_irq(cy_isa_irq, cyy_interrupt,
3368
				0, "Cyclom-Y", card)) {
J
Jiri Slaby 已提交
3369 3370 3371
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
				"could not allocate IRQ#%d.\n",
				(unsigned long)cy_isa_address, cy_isa_irq);
J
Jiri Slaby 已提交
3372
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3373
			return nboard;
3374 3375 3376
		}

		/* set cy_card */
3377 3378 3379 3380 3381 3382 3383 3384 3385 3386
		card->base_addr = cy_isa_address;
		card->ctl_addr.p9050 = NULL;
		card->irq = (int)cy_isa_irq;
		card->bus_index = 0;
		card->first_line = cy_next_channel;
		card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
		card->nports = cy_isa_nchan;
		if (cy_init_card(card)) {
			card->base_addr = NULL;
			free_irq(cy_isa_irq, card);
J
Jiri Slaby 已提交
3387 3388 3389
			iounmap(cy_isa_address);
			continue;
		}
3390 3391
		nboard++;

J
Jiri Slaby 已提交
3392 3393
		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
			"%d channels starting from port %d\n",
3394 3395
			j + 1, (unsigned long)cy_isa_address,
			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
J
Jiri Slaby 已提交
3396 3397
			cy_isa_irq, cy_isa_nchan, cy_next_channel);

3398 3399 3400
		for (j = cy_next_channel;
				j < cy_next_channel + cy_isa_nchan; j++)
			tty_register_device(cy_serial_driver, j, NULL);
3401 3402
		cy_next_channel += cy_isa_nchan;
	}
J
Jiri Slaby 已提交
3403
	return nboard;
L
Linus Torvalds 已提交
3404
#else
J
Jiri Slaby 已提交
3405
	return 0;
3406 3407
#endif				/* CONFIG_ISA */
}				/* cy_detect_isa */
L
Linus Torvalds 已提交
3408

J
Jiri Slaby 已提交
3409
#ifdef CONFIG_PCI
3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424
static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
{
	unsigned int a;

	for (a = 0; a < size && *str; a++, str++)
		if (*str & 0x80)
			return -EINVAL;

	for (; a < size; a++, str++)
		if (*str)
			return -EINVAL;

	return 0;
}

3425
static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
		unsigned int size)
{
	for (; size > 0; size--) {
		cy_writel(fpga, *data++);
		udelay(10);
	}
}

static void __devinit plx_init(struct pci_dev *pdev, int irq,
		struct RUNTIME_9060 __iomem *addr)
L
Linus Torvalds 已提交
3436
{
3437
	/* Reset PLX */
3438
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
3439
	udelay(100L);
3440
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
3441 3442

	/* Reload Config. Registers from EEPROM */
3443
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3444
	udelay(100L);
3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);

	/* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
	 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
	 * registers. This will remain here until we find a permanent fix.
	 */
	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
}

static int __devinit __cyz_load_fw(const struct firmware *fw,
		const char *name, const u32 mailbox, void __iomem *base,
		void __iomem *fpga)
{
3458 3459 3460 3461
	const void *ptr = fw->data;
	const struct zfile_header *h = ptr;
	const struct zfile_config *c, *cs;
	const struct zfile_block *b, *bs;
3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537
	unsigned int a, tmp, len = fw->size;
#define BAD_FW KERN_ERR "Bad firmware: "
	if (len < sizeof(*h)) {
		printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
		return -EINVAL;
	}

	cs = ptr + h->config_offset;
	bs = ptr + h->block_offset;

	if ((void *)(cs + h->n_config) > ptr + len ||
			(void *)(bs + h->n_blocks) > ptr + len) {
		printk(BAD_FW "too short");
		return  -EINVAL;
	}

	if (cyc_isfwstr(h->name, sizeof(h->name)) ||
			cyc_isfwstr(h->date, sizeof(h->date))) {
		printk(BAD_FW "bad formatted header string\n");
		return -EINVAL;
	}

	if (strncmp(name, h->name, sizeof(h->name))) {
		printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
		return -EINVAL;
	}

	tmp = 0;
	for (c = cs; c < cs + h->n_config; c++) {
		for (a = 0; a < c->n_blocks; a++)
			if (c->block_list[a] > h->n_blocks) {
				printk(BAD_FW "bad block ref number in cfgs\n");
				return -EINVAL;
			}
		if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
			tmp++;
	}
	if (!tmp) {
		printk(BAD_FW "nothing appropriate\n");
		return -EINVAL;
	}

	for (b = bs; b < bs + h->n_blocks; b++)
		if (b->file_offset + b->size > len) {
			printk(BAD_FW "bad block data offset\n");
			return -EINVAL;
		}

	/* everything is OK, let's seek'n'load it */
	for (c = cs; c < cs + h->n_config; c++)
		if (c->mailbox == mailbox && c->function == 0)
			break;

	for (a = 0; a < c->n_blocks; a++) {
		b = &bs[c->block_list[a]];
		if (b->type == ZBLOCK_FPGA) {
			if (fpga != NULL)
				cyz_fpga_copy(fpga, ptr + b->file_offset,
						b->size);
		} else {
			if (base != NULL)
				memcpy_toio(base + b->ram_offset,
					       ptr + b->file_offset, b->size);
		}
	}
#undef BAD_FW
	return 0;
}

static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
{
	const struct firmware *fw;
	struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
	struct CUSTOM_REG __iomem *cust = base_addr;
	struct ZFW_CTRL __iomem *pt_zfwctrl;
J
Jiri Slaby 已提交
3538
	void __iomem *tmp;
J
Jiri Slaby 已提交
3539
	u32 mailbox, status, nchan;
3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550
	unsigned int i;
	int retval;

	retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
	if (retval) {
		dev_err(&pdev->dev, "can't get firmware\n");
		goto err;
	}

	/* Check whether the firmware is already loaded and running. If
	   positive, skip this board */
3551
	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569
		u32 cntval = readl(base_addr + 0x190);

		udelay(100);
		if (cntval != readl(base_addr + 0x190)) {
			/* FW counter is working, FW is running */
			dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
					"Skipping board.\n");
			retval = 0;
			goto err_rel;
		}
	}

	/* start boot */
	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
			~0x00030800UL);

	mailbox = readl(&ctl_addr->mail_box_0);

3570
	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585
		/* stops CPU and set window to beginning of RAM */
		cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
		cy_writel(&cust->cpu_stop, 0);
		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
		udelay(100);
	}

	plx_init(pdev, irq, ctl_addr);

	if (mailbox != 0) {
		/* load FPGA */
		retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
				base_addr);
		if (retval)
			goto err_rel;
3586
		if (!__cyz_fpga_loaded(ctl_addr)) {
3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599
			dev_err(&pdev->dev, "fw upload successful, but fw is "
					"not loaded\n");
			goto err_rel;
		}
	}

	/* stops CPU and set window to beginning of RAM */
	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
	cy_writel(&cust->cpu_stop, 0);
	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
	udelay(100);

	/* clear memory */
J
Jiri Slaby 已提交
3600
	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3601 3602 3603 3604
		cy_writeb(tmp, 255);
	if (mailbox != 0) {
		/* set window to last 512K of RAM */
		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
J
Jiri Slaby 已提交
3605
		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644
			cy_writeb(tmp, 255);
		/* set window to beginning of RAM */
		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
	}

	retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
	release_firmware(fw);
	if (retval)
		goto err;

	/* finish boot and start boards */
	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
	cy_writel(&cust->cpu_start, 0);
	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
	i = 0;
	while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
		msleep(100);
	if (status != ZFIRM_ID) {
		if (status == ZFIRM_HLT) {
			dev_err(&pdev->dev, "you need an external power supply "
				"for this number of ports. Firmware halted and "
				"board reset.\n");
			retval = -EIO;
			goto err;
		}
		dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
				"some more time\n", status);
		while ((status = readl(&fid->signature)) != ZFIRM_ID &&
				i++ < 200)
			msleep(100);
		if (status != ZFIRM_ID) {
			dev_err(&pdev->dev, "Board not started in 20 seconds! "
					"Giving up. (fid->signature = 0x%x)\n",
					status);
			dev_info(&pdev->dev, "*** Warning ***: if you are "
				"upgrading the FW, please power cycle the "
				"system before loading the new FW to the "
				"Cyclades-Z.\n");

3645
			if (__cyz_fpga_loaded(ctl_addr))
3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659
				plx_init(pdev, irq, ctl_addr);

			retval = -EIO;
			goto err;
		}
		dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
				i / 10);
	}
	pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);

	dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
			base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
			base_addr + readl(&fid->zfwctrl_addr));

J
Jiri Slaby 已提交
3660
	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3661
	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
J
Jiri Slaby 已提交
3662
		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3663

J
Jiri Slaby 已提交
3664
	if (nchan == 0) {
3665 3666 3667 3668
		dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
			"check the connection between the Z host card and the "
			"serial expanders.\n");

3669
		if (__cyz_fpga_loaded(ctl_addr))
3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689
			plx_init(pdev, irq, ctl_addr);

		dev_info(&pdev->dev, "Null number of ports detected. Board "
				"reset.\n");
		retval = 0;
		goto err;
	}

	cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
	cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);

	/*
	   Early firmware failed to start looking for commands.
	   This enables firmware interrupts for those commands.
	 */
	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
			(1 << 17));
	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
			0x00030800UL);

J
Jiri Slaby 已提交
3690
	return nchan;
3691 3692 3693 3694
err_rel:
	release_firmware(fw);
err:
	return retval;
L
Linus Torvalds 已提交
3695 3696
}

J
Jiri Slaby 已提交
3697 3698
static int __devinit cy_pci_probe(struct pci_dev *pdev,
		const struct pci_device_id *ent)
L
Linus Torvalds 已提交
3699
{
3700
	struct cyclades_card *card;
J
Jiri Slaby 已提交
3701 3702
	void __iomem *addr0 = NULL, *addr2 = NULL;
	char *card_name = NULL;
J
Jiri Slaby 已提交
3703
	u32 uninitialized_var(mailbox);
J
Jiri Slaby 已提交
3704 3705 3706
	unsigned int device_id, nchan = 0, card_no, i;
	unsigned char plx_ver;
	int retval, irq;
3707

J
Jiri Slaby 已提交
3708 3709 3710
	retval = pci_enable_device(pdev);
	if (retval) {
		dev_err(&pdev->dev, "cannot enable device\n");
J
Jiri Slaby 已提交
3711
		goto err;
J
Jiri Slaby 已提交
3712
	}
L
Linus Torvalds 已提交
3713

J
Jiri Slaby 已提交
3714
	/* read PCI configuration area */
J
Jiri Slaby 已提交
3715
	irq = pdev->irq;
J
Jiri Slaby 已提交
3716
	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
L
Linus Torvalds 已提交
3717

J
Jiri Slaby 已提交
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745
#if defined(__alpha__)
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
		dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
			"addresses on Alpha systems.\n");
		retval = -EIO;
		goto err_dis;
	}
#endif
	if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
		dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
			"addresses\n");
		retval = -EIO;
		goto err_dis;
	}

	if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
		dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
				"it...\n");
		pdev->resource[2].flags &= ~IORESOURCE_IO;
	}

	retval = pci_request_regions(pdev, "cyclades");
	if (retval) {
		dev_err(&pdev->dev, "failed to reserve resources\n");
		goto err_dis;
	}

	retval = -EIO;
J
Jiri Slaby 已提交
3746 3747
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
J
Jiri Slaby 已提交
3748
		card_name = "Cyclom-Y";
L
Linus Torvalds 已提交
3749

J
Jiri Slaby 已提交
3750 3751
		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Yctl);
J
Jiri Slaby 已提交
3752 3753 3754
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
J
Jiri Slaby 已提交
3755
		}
J
Jiri Slaby 已提交
3756 3757
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				CyPCI_Ywin);
J
Jiri Slaby 已提交
3758 3759 3760
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3761
		}
L
Linus Torvalds 已提交
3762

J
Jiri Slaby 已提交
3763 3764
		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
		if (nchan == 0) {
J
Jiri Slaby 已提交
3765 3766
			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
					"Serial-Modules\n");
3767
			goto err_unmap;
J
Jiri Slaby 已提交
3768 3769
		}
	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
J
Jiri Slaby 已提交
3770
		struct RUNTIME_9060 __iomem *ctl_addr;
J
Jiri Slaby 已提交
3771

J
Jiri Slaby 已提交
3772 3773
		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Zctl);
J
Jiri Slaby 已提交
3774 3775 3776 3777
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
		}
J
Jiri Slaby 已提交
3778 3779

		/* Disable interrupts on the PLX before resetting it */
3780 3781
		cy_writew(&ctl_addr->intr_ctrl_stat,
				readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
J
Jiri Slaby 已提交
3782

3783
		plx_init(pdev, irq, addr0);
3784

J
Jiri Slaby 已提交
3785
		mailbox = readl(&ctl_addr->mail_box_0);
J
Jiri Slaby 已提交
3786

J
Jiri Slaby 已提交
3787 3788
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
J
Jiri Slaby 已提交
3789 3790 3791
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3792 3793 3794
		}

		if (mailbox == ZE_V1) {
J
Jiri Slaby 已提交
3795
			card_name = "Cyclades-Ze";
J
Jiri Slaby 已提交
3796
		} else {
J
Jiri Slaby 已提交
3797
			card_name = "Cyclades-8Zo";
L
Linus Torvalds 已提交
3798
#ifdef CY_PCI_DEBUG
J
Jiri Slaby 已提交
3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811
			if (mailbox == ZO_V1) {
				cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
				dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
					"id %lx, ver %lx\n", (ulong)(0xff &
					readl(&((struct CUSTOM_REG *)addr2)->
						fpga_id)), (ulong)(0xff &
					readl(&((struct CUSTOM_REG *)addr2)->
						fpga_version)));
				cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
			} else {
				dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
					"Cyclades-Z board.  FPGA not loaded\n");
			}
L
Linus Torvalds 已提交
3812
#endif
J
Jiri Slaby 已提交
3813 3814 3815 3816 3817 3818
			/* The following clears the firmware id word.  This
			   ensures that the driver will not attempt to talk to
			   the board until it has been properly initialized.
			 */
			if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
				cy_writel(addr2 + ID_ADDRESS, 0L);
J
Jiri Slaby 已提交
3819
		}
3820 3821

		retval = cyz_load_fw(pdev, addr2, addr0, irq);
J
Jiri Slaby 已提交
3822
		if (retval <= 0)
3823
			goto err_unmap;
J
Jiri Slaby 已提交
3824
		nchan = retval;
J
Jiri Slaby 已提交
3825 3826 3827 3828 3829 3830 3831 3832 3833 3834
	}

	if ((cy_next_channel + nchan) > NR_PORTS) {
		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
			"channels are available. Change NR_PORTS in "
			"cyclades.c and recompile kernel.\n");
		goto err_unmap;
	}
	/* fill the next cy_card structure available */
	for (card_no = 0; card_no < NR_CARDS; card_no++) {
3835 3836
		card = &cy_card[card_no];
		if (card->base_addr == NULL)
J
Jiri Slaby 已提交
3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849
			break;
	}
	if (card_no == NR_CARDS) {	/* no more cy_cards available */
		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
			"more cards can be used. Change NR_CARDS in "
			"cyclades.c and recompile kernel.\n");
		goto err_unmap;
	}

	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
		/* allocate IRQ */
		retval = request_irq(irq, cyy_interrupt,
3850
				IRQF_SHARED, "Cyclom-Y", card);
J
Jiri Slaby 已提交
3851 3852 3853
		if (retval) {
			dev_err(&pdev->dev, "could not allocate IRQ\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3854
		}
3855
		card->num_chips = nchan / CyPORTS_PER_CHIP;
J
Jiri Slaby 已提交
3856
	} else {
3857 3858 3859 3860 3861
		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
		struct ZFW_CTRL __iomem *zfw_ctrl;

		zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);

3862 3863 3864
		card->hw_ver = mailbox;
		card->num_chips = (unsigned int)-1;
		card->board_ctrl = &zfw_ctrl->board_ctrl;
3865
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3866
		/* allocate IRQ only if board has an IRQ */
J
Jiri Slaby 已提交
3867 3868
		if (irq != 0 && irq != 255) {
			retval = request_irq(irq, cyz_interrupt,
3869
					IRQF_SHARED, "Cyclades-Z", card);
J
Jiri Slaby 已提交
3870
			if (retval) {
J
Jiri Slaby 已提交
3871
				dev_err(&pdev->dev, "could not allocate IRQ\n");
J
Jiri Slaby 已提交
3872
				goto err_unmap;
3873
			}
J
Jiri Slaby 已提交
3874
		}
3875
#endif				/* CONFIG_CYZ_INTR */
J
Jiri Slaby 已提交
3876
	}
3877

J
Jiri Slaby 已提交
3878
	/* set cy_card */
3879 3880 3881 3882 3883 3884 3885
	card->base_addr = addr2;
	card->ctl_addr.p9050 = addr0;
	card->irq = irq;
	card->bus_index = 1;
	card->first_line = cy_next_channel;
	card->nports = nchan;
	retval = cy_init_card(card);
J
Jiri Slaby 已提交
3886 3887
	if (retval)
		goto err_null;
J
Jiri Slaby 已提交
3888

3889
	pci_set_drvdata(pdev, card);
J
Jiri Slaby 已提交
3890

J
Jiri Slaby 已提交
3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
		/* enable interrupts in the PCI interface */
		plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
		switch (plx_ver) {
		case PLX_9050:
			cy_writeb(addr0 + 0x4c, 0x43);
			break;

		case PLX_9060:
		case PLX_9080:
		default:	/* Old boards, use PLX_9060 */
3903 3904 3905 3906 3907
		{
			struct RUNTIME_9060 __iomem *ctl_addr = addr0;
			plx_init(pdev, irq, ctl_addr);
			cy_writew(&ctl_addr->intr_ctrl_stat,
				readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
J
Jiri Slaby 已提交
3908 3909
			break;
		}
3910
		}
J
Jiri Slaby 已提交
3911 3912
	}

J
Jiri Slaby 已提交
3913 3914 3915 3916 3917 3918
	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
	for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
		tty_register_device(cy_serial_driver, i, &pdev->dev);
	cy_next_channel += nchan;

J
Jiri Slaby 已提交
3919
	return 0;
J
Jiri Slaby 已提交
3920
err_null:
3921 3922
	card->base_addr = NULL;
	free_irq(irq, card);
J
Jiri Slaby 已提交
3923
err_unmap:
J
Jiri Slaby 已提交
3924
	iounmap(addr0);
J
Jiri Slaby 已提交
3925
	if (addr2)
J
Jiri Slaby 已提交
3926
		iounmap(addr2);
J
Jiri Slaby 已提交
3927 3928 3929 3930 3931 3932
err_reg:
	pci_release_regions(pdev);
err_dis:
	pci_disable_device(pdev);
err:
	return retval;
J
Jiri Slaby 已提交
3933 3934
}

3935
static void __devexit cy_pci_remove(struct pci_dev *pdev)
J
Jiri Slaby 已提交
3936
{
J
Jiri Slaby 已提交
3937
	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3938
	unsigned int i;
J
Jiri Slaby 已提交
3939

3940
	/* non-Z with old PLX */
3941
	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
J
Jiri Slaby 已提交
3942
			PLX_9050)
3943
		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
3944 3945
	else
#ifndef CONFIG_CYZ_INTR
3946
		if (!cy_is_Z(cinfo))
3947
#endif
3948 3949 3950
		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
			~0x0900);
3951

J
Jiri Slaby 已提交
3952
	iounmap(cinfo->base_addr);
3953 3954
	if (cinfo->ctl_addr.p9050)
		iounmap(cinfo->ctl_addr.p9050);
J
Jiri Slaby 已提交
3955 3956
	if (cinfo->irq
#ifndef CONFIG_CYZ_INTR
3957
		&& !cy_is_Z(cinfo)
J
Jiri Slaby 已提交
3958 3959 3960 3961 3962 3963
#endif /* CONFIG_CYZ_INTR */
		)
		free_irq(cinfo->irq, cinfo);
	pci_release_regions(pdev);

	cinfo->base_addr = NULL;
3964 3965 3966
	for (i = cinfo->first_line; i < cinfo->first_line +
			cinfo->nports; i++)
		tty_unregister_device(cy_serial_driver, i);
J
Jiri Slaby 已提交
3967 3968
	cinfo->nports = 0;
	kfree(cinfo->ports);
J
Jiri Slaby 已提交
3969 3970
}

3971 3972 3973 3974 3975 3976 3977 3978
static struct pci_driver cy_pci_driver = {
	.name = "cyclades",
	.id_table = cy_pci_dev_id,
	.probe = cy_pci_probe,
	.remove = __devexit_p(cy_pci_remove)
};
#endif

3979
static int cyclades_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
3980
{
3981
	struct cyclades_port *info;
J
Jiri Slaby 已提交
3982
	unsigned int i, j;
3983 3984
	__u32 cur_jifs = jiffies;

3985
	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
3986 3987 3988
			"IdleIn  Overruns  Ldisc\n");

	/* Output one line for each known port */
J
Jiri Slaby 已提交
3989 3990 3991 3992
	for (i = 0; i < NR_CARDS; i++)
		for (j = 0; j < cy_card[i].nports; j++) {
			info = &cy_card[i].ports[j];

J
Jiri Slaby 已提交
3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006
			if (info->port.count) {
				/* XXX is the ldisc num worth this? */
				struct tty_struct *tty;
				struct tty_ldisc *ld;
				int num = 0;
				tty = tty_port_tty_get(&info->port);
				if (tty) {
					ld = tty_ldisc_ref(tty);
					if (ld) {
						num = ld->ops->num;
						tty_ldisc_deref(ld);
					}
					tty_kref_put(tty);
				}
4007
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4008
					"%10lu %8lu %9lu %6d\n", info->line,
J
Jiri Slaby 已提交
4009 4010 4011 4012 4013 4014
					(cur_jifs - info->idle_stats.in_use) /
					HZ, info->idle_stats.xmit_bytes,
					(cur_jifs - info->idle_stats.xmit_idle)/
					HZ, info->idle_stats.recv_bytes,
					(cur_jifs - info->idle_stats.recv_idle)/
					HZ, info->idle_stats.overruns,
J
Jiri Slaby 已提交
4015 4016
					num);
			} else
4017
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4018 4019
					"%10lu %8lu %9lu %6ld\n",
					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
4020
		}
4021 4022 4023 4024 4025 4026
	return 0;
}

static int cyclades_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cyclades_proc_show, NULL);
L
Linus Torvalds 已提交
4027 4028
}

4029 4030 4031 4032 4033 4034 4035 4036
static const struct file_operations cyclades_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= cyclades_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

L
Linus Torvalds 已提交
4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054
/* The serial driver boot-time initialization code!
    Hardware I/O ports are mapped to character special devices on a
    first found, first allocated manner.  That is, this code searches
    for Cyclom cards in the system.  As each is found, it is probed
    to discover how many chips (and thus how many ports) are present.
    These ports are mapped to the tty ports 32 and upward in monotonic
    fashion.  If an 8-port card is replaced with a 16-port card, the
    port mapping on a following card will shift.

    This approach is different from what is used in the other serial
    device driver because the Cyclom is more properly a multiplexer,
    not just an aggregation of serial ports on one card.

    If there are more cards with more ports than have been
    statically allocated above, a warning is printed and the
    extra ports are ignored.
 */

J
Jeff Dike 已提交
4055
static const struct tty_operations cy_ops = {
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074
	.open = cy_open,
	.close = cy_close,
	.write = cy_write,
	.put_char = cy_put_char,
	.flush_chars = cy_flush_chars,
	.write_room = cy_write_room,
	.chars_in_buffer = cy_chars_in_buffer,
	.flush_buffer = cy_flush_buffer,
	.ioctl = cy_ioctl,
	.throttle = cy_throttle,
	.unthrottle = cy_unthrottle,
	.set_termios = cy_set_termios,
	.stop = cy_stop,
	.start = cy_start,
	.hangup = cy_hangup,
	.break_ctl = cy_break,
	.wait_until_sent = cy_wait_until_sent,
	.tiocmget = cy_tiocmget,
	.tiocmset = cy_tiocmset,
4075
	.get_icount = cy_get_icount,
4076
	.proc_fops = &cyclades_proc_fops,
L
Linus Torvalds 已提交
4077 4078
};

4079
static int __init cy_init(void)
L
Linus Torvalds 已提交
4080
{
J
Jiri Slaby 已提交
4081
	unsigned int nboards;
4082
	int retval = -ENOMEM;
4083 4084 4085

	cy_serial_driver = alloc_tty_driver(NR_PORTS);
	if (!cy_serial_driver)
4086
		goto err;
J
Jiri Slaby 已提交
4087

M
Michal Marek 已提交
4088
	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100

	/* Initialize the tty_driver structure */

	cy_serial_driver->driver_name = "cyclades";
	cy_serial_driver->name = "ttyC";
	cy_serial_driver->major = CYCLADES_MAJOR;
	cy_serial_driver->minor_start = 0;
	cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
	cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
	cy_serial_driver->init_termios = tty_std_termios;
	cy_serial_driver->init_termios.c_cflag =
	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
4101
	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
4102 4103
	tty_set_operations(cy_serial_driver, &cy_ops);

4104 4105 4106 4107 4108
	retval = tty_register_driver(cy_serial_driver);
	if (retval) {
		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
		goto err_frtty;
	}
4109 4110 4111 4112 4113 4114 4115 4116 4117

	/* the code below is responsible to find the boards. Each different
	   type of board has its own detection routine. If a board is found,
	   the next cy_card structure available is set by the detection
	   routine. These functions are responsible for checking the
	   availability of cy_card and cy_port data structures and updating
	   the cy_next_channel. */

	/* look for isa boards */
4118
	nboards = cy_detect_isa();
4119

4120
#ifdef CONFIG_PCI
4121
	/* look for pci boards */
4122
	retval = pci_register_driver(&cy_pci_driver);
4123 4124 4125 4126
	if (retval && !nboards) {
		tty_unregister_driver(cy_serial_driver);
		goto err_frtty;
	}
4127
#endif
4128 4129 4130 4131 4132 4133

	return 0;
err_frtty:
	put_tty_driver(cy_serial_driver);
err:
	return retval;
4134
}				/* cy_init */
L
Linus Torvalds 已提交
4135

4136
static void __exit cy_cleanup_module(void)
L
Linus Torvalds 已提交
4137
{
J
Jiri Slaby 已提交
4138
	struct cyclades_card *card;
J
Jiri Slaby 已提交
4139
	unsigned int i, e1;
L
Linus Torvalds 已提交
4140 4141

#ifndef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
4142
	del_timer_sync(&cyz_timerlist);
L
Linus Torvalds 已提交
4143 4144
#endif /* CONFIG_CYZ_INTR */

A
Alan Cox 已提交
4145 4146
	e1 = tty_unregister_driver(cy_serial_driver);
	if (e1)
J
Jiri Slaby 已提交
4147 4148
		printk(KERN_ERR "failed to unregister Cyclades serial "
				"driver(%d)\n", e1);
L
Linus Torvalds 已提交
4149

4150 4151 4152 4153
#ifdef CONFIG_PCI
	pci_unregister_driver(&cy_pci_driver);
#endif

4154
	for (i = 0; i < NR_CARDS; i++) {
J
Jiri Slaby 已提交
4155 4156
		card = &cy_card[i];
		if (card->base_addr) {
4157
			/* clear interrupt */
J
Jiri Slaby 已提交
4158 4159
			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
			iounmap(card->base_addr);
4160 4161
			if (card->ctl_addr.p9050)
				iounmap(card->ctl_addr.p9050);
J
Jiri Slaby 已提交
4162
			if (card->irq
L
Linus Torvalds 已提交
4163
#ifndef CONFIG_CYZ_INTR
4164
				&& !cy_is_Z(card)
L
Linus Torvalds 已提交
4165
#endif /* CONFIG_CYZ_INTR */
4166
				)
J
Jiri Slaby 已提交
4167
				free_irq(card->irq, card);
J
Jiri Slaby 已提交
4168
			for (e1 = card->first_line; e1 < card->first_line +
J
Jiri Slaby 已提交
4169
					card->nports; e1++)
4170
				tty_unregister_device(cy_serial_driver, e1);
J
Jiri Slaby 已提交
4171
			kfree(card->ports);
4172 4173
		}
	}
4174 4175

	put_tty_driver(cy_serial_driver);
L
Linus Torvalds 已提交
4176 4177 4178 4179 4180 4181
} /* cy_cleanup_module */

module_init(cy_init);
module_exit(cy_cleanup_module);

MODULE_LICENSE("GPL");
4182
MODULE_VERSION(CY_VERSION);
4183
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4184
MODULE_FIRMWARE("cyzfirm.bin");