cyclades.c 111.2 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;
J
Jiri Slaby 已提交
1518 1519
	unsigned int i, line;
	int retval;
L
Linus Torvalds 已提交
1520

1521
	line = tty->index;
A
Alan Cox 已提交
1522
	if (tty->index < 0 || NR_PORTS <= line)
1523
		return -ENODEV;
A
Alan Cox 已提交
1524

J
Jiri Slaby 已提交
1525 1526 1527 1528 1529 1530 1531
	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 已提交
1532
	if (info->line < 0)
1533
		return -ENODEV;
L
Linus Torvalds 已提交
1534

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

1543 1544
		if (!cyz_is_loaded(cinfo)) {
			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
J
Jiri Slaby 已提交
1545 1546
					readl(&firm_id->signature) ==
					ZFIRM_HLT) {
J
Jiri Slaby 已提交
1547 1548 1549 1550
				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
					"need an external power supply for "
					"this number of ports.\nFirmware "
					"halted.\n");
1551
			} else {
J
Jiri Slaby 已提交
1552 1553
				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
					"yet loaded\n");
1554 1555 1556 1557 1558 1559 1560 1561 1562
			}
			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) {
1563
				u16 intr;
1564 1565

				/* Enable interrupts on the PLX chip */
1566 1567 1568 1569
				intr = readw(&cinfo->ctl_addr.p9060->
						intr_ctrl_stat) | 0x0900;
				cy_writew(&cinfo->ctl_addr.p9060->
						intr_ctrl_stat, intr);
1570 1571 1572 1573
				/* Enable interrupts on the FW */
				retval = cyz_issue_cmd(cinfo, 0,
						C_CM_IRQ_ENBL, 0L);
				if (retval != 0) {
J
Jiri Slaby 已提交
1574 1575
					printk(KERN_ERR "cyc:IRQ enable retval "
						"was %x\n", retval);
1576 1577 1578
				}
				cinfo->intr_enabled = 1;
			}
L
Linus Torvalds 已提交
1579
		}
1580 1581 1582 1583
#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 已提交
1584 1585
	}
#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
1586
	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1587
#endif
1588
	tty->driver_data = info;
A
Alan Cox 已提交
1589
	if (serial_paranoia_check(info, tty->name, "cy_open"))
1590
		return -ENODEV;
A
Alan Cox 已提交
1591

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

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

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

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

1627
	info->throttle = 0;
J
Jiri Slaby 已提交
1628
	tty_port_tty_set(&info->port, tty);
L
Linus Torvalds 已提交
1629

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

/*
 * cy_wait_until_sent() --- wait until the transmitter is empty
 */
1639
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
L
Linus Torvalds 已提交
1640
{
1641
	struct cyclades_card *card;
1642
	struct cyclades_port *info = tty->driver_data;
1643 1644 1645 1646 1647 1648 1649 1650
	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 已提交
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 1676 1677 1678 1679
	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;
1680

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

1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715
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);

1716
	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729
					   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 */


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

1738
	card = info->card;
1739
	channel = info->line - card->first_line;
1740
	spin_lock_irqsave(&card->card_lock, flags);
1741

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

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

1776 1777 1778 1779 1780 1781 1782 1783 1784
/*
 * 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);
1785
}				/* cy_close */
L
Linus Torvalds 已提交
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799

/* 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.
 *
 */
1800
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
L
Linus Torvalds 已提交
1801
{
1802
	struct cyclades_port *info = tty->driver_data;
1803 1804
	unsigned long flags;
	int c, ret = 0;
L
Linus Torvalds 已提交
1805 1806

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

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

A
Alan Cox 已提交
1813
	if (!info->port.xmit_buf)
1814
		return 0;
L
Linus Torvalds 已提交
1815

1816
	spin_lock_irqsave(&info->card->card_lock, flags);
1817
	while (1) {
1818 1819
		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
1820 1821 1822 1823

		if (c <= 0)
			break;

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

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

A
Alan Cox 已提交
1837
	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1838
		start_xmit(info);
A
Alan Cox 已提交
1839

1840 1841
	return ret;
}				/* cy_write */
L
Linus Torvalds 已提交
1842 1843 1844 1845 1846 1847 1848 1849

/*
 * 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.
 */
1850
static int cy_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
1851
{
1852
	struct cyclades_port *info = tty->driver_data;
1853
	unsigned long flags;
L
Linus Torvalds 已提交
1854 1855

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

1859
	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1860
		return 0;
L
Linus Torvalds 已提交
1861

A
Alan Cox 已提交
1862
	if (!info->port.xmit_buf)
1863
		return 0;
L
Linus Torvalds 已提交
1864

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

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

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

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

1892 1893
	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
		return;
L
Linus Torvalds 已提交
1894

1895
	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
A
Alan Cox 已提交
1896
			!info->port.xmit_buf)
1897
		return;
L
Linus Torvalds 已提交
1898

1899 1900
	start_xmit(info);
}				/* cy_flush_chars */
L
Linus Torvalds 已提交
1901 1902 1903 1904 1905 1906 1907

/*
 * 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.
 */
1908
static int cy_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
1909
{
1910
	struct cyclades_port *info = tty->driver_data;
1911 1912
	int ret;

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

1917 1918 1919 1920 1921 1922 1923
	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 已提交
1924

1925
static int cy_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1926
{
1927
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
1928

1929 1930 1931
	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
		return 0;

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

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

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

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

1974 1975 1976 1977
	if (baud == 0) {
		info->tbpr = info->tco = info->rbpr = info->rco = 0;
		return;
	}
L
Linus Torvalds 已提交
1978

1979 1980 1981 1982 1983
	/* 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 已提交
1984

1985 1986 1987
	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
	if (bpr > 255)
		bpr = 255;
L
Linus Torvalds 已提交
1988

1989 1990
	info->tbpr = info->rbpr = bpr;
	info->tco = info->rco = co;
L
Linus Torvalds 已提交
1991 1992 1993 1994 1995 1996
}

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

J
Jiri Slaby 已提交
2006
	if (!tty->termios) /* XXX can this happen at all? */
2007
		return;
A
Alan Cox 已提交
2008 2009

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

J
Jiri Slaby 已提交
2012 2013
	cflag = tty->termios->c_cflag;
	iflag = tty->termios->c_iflag;
L
Linus Torvalds 已提交
2014

2015 2016 2017
	/*
	 * Set up the tty->alt_speed kludge
	 */
J
Jiri Slaby 已提交
2018 2019 2020 2021 2022 2023 2024 2025
	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;
2026 2027

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

2030
	if (!cy_is_Z(card)) {
2031 2032
		u32 cflags;

2033
		/* baud rate */
J
Jiri Slaby 已提交
2034
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2035
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
				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 已提交
2046
			if (baud == baud_table[i])
2047 2048
				break;
		}
A
Alan Cox 已提交
2049
		if (i == 20)
2050 2051
			i = 19;	/* CD1400_MAX_SPEED */

A
Alan Cox 已提交
2052
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072
				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 已提交
2073
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
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 2105 2106 2107 2108
				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 已提交
2109
		if (cflag & CSTOPB)
2110
			info->cor1 |= Cy_2_STOP;
A
Alan Cox 已提交
2111

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

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

	 /***********************************************
	    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.
	 ***********************************************/

2143
		channel &= 0x03;
L
Linus Torvalds 已提交
2144

2145
		spin_lock_irqsave(&card->card_lock, flags);
2146
		cyy_writeb(info, CyCAR, channel);
2147 2148 2149

		/* tx and rx baud rate */

2150 2151 2152 2153
		cyy_writeb(info, CyTCOR, info->tco);
		cyy_writeb(info, CyTBPR, info->tbpr);
		cyy_writeb(info, CyRCOR, info->rco);
		cyy_writeb(info, CyRBPR, info->rbpr);
2154 2155 2156

		/* set line characteristics  according configuration */

2157 2158 2159 2160 2161 2162 2163
		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);
2164

2165 2166
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
				CyCOR3ch);
2167

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

2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
		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);
2186

J
Jiri Slaby 已提交
2187 2188 2189 2190
		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 已提交
2191

J
Jiri Slaby 已提交
2192
		clear_bit(TTY_IO_ERROR, &tty->flags);
2193
		spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
2194 2195

	} else {
2196
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
K
Klaus Kudielka 已提交
2197
		__u32 sw_flow;
2198
		int retval;
L
Linus Torvalds 已提交
2199

2200
		if (!cyz_is_loaded(card))
2201
			return;
L
Linus Torvalds 已提交
2202

2203
		/* baud rate */
J
Jiri Slaby 已提交
2204
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2205
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
				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 已提交
2220
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230
				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 已提交
2231

2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248
		/* 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,
2249
				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
2250 2251
		} else {
			cy_writel(&ch_ctrl->comm_data_l,
2252
				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
2253 2254
		}
		if (cflag & PARENB) {
A
Alan Cox 已提交
2255
			if (cflag & PARODD)
2256
				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
A
Alan Cox 已提交
2257
			else
2258
				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
A
Alan Cox 已提交
2259
		} else
2260
			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
L
Linus Torvalds 已提交
2261

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

		/* 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);

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

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

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

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

J
Jiri Slaby 已提交
2315
		clear_bit(TTY_IO_ERROR, &tty->flags);
L
Linus Torvalds 已提交
2316
	}
2317
}				/* set_line_char */
L
Linus Torvalds 已提交
2318

J
Jiri Slaby 已提交
2319
static int cy_get_serial_info(struct cyclades_port *info,
A
Alan Cox 已提交
2320
		struct serial_struct __user *retinfo)
L
Linus Torvalds 已提交
2321
{
2322
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
	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,		/*!!! */
	};
2336
	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
J
Jiri Slaby 已提交
2337
}
L
Linus Torvalds 已提交
2338 2339

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

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

A
Alan Cox 已提交
2349
	mutex_lock(&info->port.mutex);
2350
	if (!capable(CAP_SYS_ADMIN)) {
A
Alan Cox 已提交
2351
		if (new_serial.close_delay != info->port.close_delay ||
2352 2353 2354
				new_serial.baud_base != info->baud ||
				(new_serial.flags & ASYNC_FLAGS &
					~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
2355
				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
A
Alan Cox 已提交
2356 2357
		{
			mutex_unlock(&info->port.mutex);
2358
			return -EPERM;
A
Alan Cox 已提交
2359
		}
A
Alan Cox 已提交
2360
		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373
				(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 已提交
2374
	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
2375
			(new_serial.flags & ASYNC_FLAGS);
A
Alan Cox 已提交
2376 2377
	info->port.close_delay = new_serial.close_delay * HZ / 100;
	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
L
Linus Torvalds 已提交
2378 2379

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

/*
 * 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 已提交
2400
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
L
Linus Torvalds 已提交
2401
{
2402
	struct cyclades_card *card = info->card;
2403 2404
	unsigned int result;
	unsigned long flags;
2405
	u8 status;
L
Linus Torvalds 已提交
2406

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

2419
static int cy_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
2420
{
2421
	struct cyclades_port *info = tty->driver_data;
2422
	struct cyclades_card *card;
2423
	int result;
2424

2425
	if (serial_paranoia_check(info, tty->name, __func__))
2426
		return -ENODEV;
L
Linus Torvalds 已提交
2427

2428
	card = info->card;
J
Jiri Slaby 已提交
2429

2430
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2431
		unsigned long flags;
2432 2433
		int channel = info->line - card->first_line;
		u8 status;
L
Linus Torvalds 已提交
2434

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

		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 已提交
2452
	} else {
J
Jiri Slaby 已提交
2453 2454 2455 2456 2457
		u32 lstatus;

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

J
Jiri Slaby 已提交
2460 2461 2462 2463 2464 2465 2466
		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);
2467
	}
J
Jiri Slaby 已提交
2468
end:
2469 2470
	return result;
}				/* cy_tiomget */
L
Linus Torvalds 已提交
2471 2472

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

2480
	if (serial_paranoia_check(info, tty->name, __func__))
2481 2482 2483
		return -ENODEV;

	card = info->card;
2484
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2485 2486 2487
		spin_lock_irqsave(&card->card_lock, flags);
		cyy_change_rts_dtr(info, set, clear);
		spin_unlock_irqrestore(&card->card_lock, flags);
2488
	} else {
J
Jiri Slaby 已提交
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
		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 已提交
2504
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2505
			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
L
Linus Torvalds 已提交
2506
#endif
J
Jiri Slaby 已提交
2507 2508 2509
		}
		if (clear & TIOCM_DTR) {
			rs &= ~C_RS_DTR;
L
Linus Torvalds 已提交
2510
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2511 2512
			printk(KERN_DEBUG "cyc:set_modem_info clearing "
				"Z DTR\n");
L
Linus Torvalds 已提交
2513
#endif
2514
		}
J
Jiri Slaby 已提交
2515
		cy_writel(&ch_ctrl->rs_control, rs);
2516
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
J
Jiri Slaby 已提交
2517
		spin_unlock_irqrestore(&card->card_lock, flags);
2518
		if (retval != 0) {
J
Jiri Slaby 已提交
2519 2520
			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
				"was %x\n", info->line, retval);
2521
		}
L
Linus Torvalds 已提交
2522
	}
2523
	return 0;
J
Jiri Slaby 已提交
2524
}
L
Linus Torvalds 已提交
2525 2526 2527 2528

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

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

2539 2540 2541
	card = info->card;

	spin_lock_irqsave(&card->card_lock, flags);
2542
	if (!cy_is_Z(card)) {
2543 2544 2545 2546 2547 2548 2549
		/* 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) {
2550
					spin_unlock_irqrestore(&card->card_lock, flags);
2551
					start_xmit(info);
2552
					spin_lock_irqsave(&card->card_lock, flags);
2553 2554 2555 2556 2557 2558
				}
			}
		} else {
			if (!info->breakoff) {
				info->breakoff = 1;
				if (!info->xmit_cnt) {
2559
					spin_unlock_irqrestore(&card->card_lock, flags);
2560
					start_xmit(info);
2561
					spin_lock_irqsave(&card->card_lock, flags);
2562 2563
				}
			}
L
Linus Torvalds 已提交
2564 2565
		}
	} else {
2566
		if (break_state == -1) {
2567 2568
			retval = cyz_issue_cmd(card,
				info->line - card->first_line,
2569 2570
				C_CM_SET_BREAK, 0L);
			if (retval != 0) {
J
Jiri Slaby 已提交
2571 2572
				printk(KERN_ERR "cyc:cy_break (set) retval on "
					"ttyC%d was %x\n", info->line, retval);
2573 2574
			}
		} else {
2575 2576
			retval = cyz_issue_cmd(card,
				info->line - card->first_line,
2577 2578
				C_CM_CLR_BREAK, 0L);
			if (retval != 0) {
J
Jiri Slaby 已提交
2579 2580 2581
				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
					"on ttyC%d was %x\n", info->line,
					retval);
2582
			}
L
Linus Torvalds 已提交
2583 2584
		}
	}
2585
	spin_unlock_irqrestore(&card->card_lock, flags);
A
Alan Cox 已提交
2586
	return retval;
2587
}				/* cy_break */
L
Linus Torvalds 已提交
2588

2589
static int set_threshold(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2590
{
2591
	struct cyclades_card *card = info->card;
2592
	unsigned long flags;
L
Linus Torvalds 已提交
2593

2594
	if (!cy_is_Z(card)) {
2595 2596
		info->cor3 &= ~CyREC_FIFO;
		info->cor3 |= value & CyREC_FIFO;
L
Linus Torvalds 已提交
2597

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

A
Alan Cox 已提交
2606 2607
static int get_threshold(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2608
{
2609
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2610

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

2618
static int set_timeout(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2619
{
2620
	struct cyclades_card *card = info->card;
2621
	unsigned long flags;
L
Linus Torvalds 已提交
2622

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

A
Alan Cox 已提交
2631 2632
static int get_timeout(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2633
{
2634
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2635

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

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

J
Jiri Slaby 已提交
2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662
	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 已提交
2663 2664 2665 2666 2667 2668 2669

/*
 * 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
2670
cy_ioctl(struct tty_struct *tty,
2671
	 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2672
{
2673
	struct cyclades_port *info = tty->driver_data;
J
Jiri Slaby 已提交
2674
	struct cyclades_icount cnow;	/* kernel counter temps */
2675 2676 2677 2678 2679 2680
	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 已提交
2681 2682

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

2687 2688
	switch (cmd) {
	case CYGETMON:
J
Jiri Slaby 已提交
2689 2690 2691 2692 2693
		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
			ret_val = -EFAULT;
			break;
		}
		memset(&info->mon, 0, sizeof(info->mon));
2694 2695 2696 2697 2698 2699 2700 2701
		break;
	case CYGETTHRESH:
		ret_val = get_threshold(info, argp);
		break;
	case CYSETTHRESH:
		ret_val = set_threshold(info, arg);
		break;
	case CYGETDEFTHRESH:
J
Jiri Slaby 已提交
2702 2703
		ret_val = put_user(info->default_threshold,
				(unsigned long __user *)argp);
2704 2705
		break;
	case CYSETDEFTHRESH:
J
Jiri Slaby 已提交
2706
		info->default_threshold = arg & 0x0f;
2707 2708 2709 2710 2711 2712 2713 2714
		break;
	case CYGETTIMEOUT:
		ret_val = get_timeout(info, argp);
		break;
	case CYSETTIMEOUT:
		ret_val = set_timeout(info, arg);
		break;
	case CYGETDEFTIMEOUT:
J
Jiri Slaby 已提交
2715 2716
		ret_val = put_user(info->default_timeout,
				(unsigned long __user *)argp);
2717 2718
		break;
	case CYSETDEFTIMEOUT:
J
Jiri Slaby 已提交
2719
		info->default_timeout = arg & 0xff;
2720
		break;
L
Linus Torvalds 已提交
2721
	case CYSETRFLOW:
2722 2723
		info->rflow = (int)arg;
		break;
L
Linus Torvalds 已提交
2724
	case CYGETRFLOW:
2725 2726
		ret_val = info->rflow;
		break;
L
Linus Torvalds 已提交
2727
	case CYSETRTSDTR_INV:
2728 2729
		info->rtsdtr_inv = (int)arg;
		break;
L
Linus Torvalds 已提交
2730
	case CYGETRTSDTR_INV:
2731 2732
		ret_val = info->rtsdtr_inv;
		break;
L
Linus Torvalds 已提交
2733
	case CYGETCD1400VER:
2734 2735
		ret_val = info->chip_rev;
		break;
L
Linus Torvalds 已提交
2736 2737
#ifndef CONFIG_CYZ_INTR
	case CYZSETPOLLCYCLE:
2738 2739
		cyz_polling_cycle = (arg * HZ) / 1000;
		break;
L
Linus Torvalds 已提交
2740
	case CYZGETPOLLCYCLE:
2741 2742 2743
		ret_val = (cyz_polling_cycle * 1000) / HZ;
		break;
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
2744
	case CYSETWAIT:
A
Alan Cox 已提交
2745
		info->port.closing_wait = (unsigned short)arg * HZ / 100;
2746
		break;
L
Linus Torvalds 已提交
2747
	case CYGETWAIT:
A
Alan Cox 已提交
2748
		ret_val = info->port.closing_wait / (HZ / 100);
2749 2750
		break;
	case TIOCGSERIAL:
J
Jiri Slaby 已提交
2751
		ret_val = cy_get_serial_info(info, argp);
2752 2753
		break;
	case TIOCSSERIAL:
J
Jiri Slaby 已提交
2754
		ret_val = cy_set_serial_info(info, tty, argp);
2755 2756 2757 2758 2759 2760 2761 2762 2763 2764
		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 已提交
2765
	case TIOCMIWAIT:
2766
		spin_lock_irqsave(&info->card->card_lock, flags);
2767
		/* note the counters on entry */
J
Jiri Slaby 已提交
2768
		cnow = info->icount;
2769
		spin_unlock_irqrestore(&info->card->card_lock, flags);
2770
		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
J
Jiri Slaby 已提交
2771
				cy_cflags_changed(info, arg, &cnow));
J
Jiri Slaby 已提交
2772
		break;
L
Linus Torvalds 已提交
2773

2774 2775 2776 2777 2778 2779 2780 2781 2782
		/*
		 * 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 已提交
2783 2784

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2785
	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
L
Linus Torvalds 已提交
2786
#endif
2787 2788
	return ret_val;
}				/* cy_ioctl */
L
Linus Torvalds 已提交
2789

2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814
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 已提交
2815 2816 2817 2818 2819 2820
/*
 * 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.
 */
2821
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
L
Linus Torvalds 已提交
2822
{
2823
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
2824 2825

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

J
Jiri Slaby 已提交
2829
	cy_set_line_char(info, tty);
2830 2831 2832 2833 2834 2835

	if ((old_termios->c_cflag & CRTSCTS) &&
			!(tty->termios->c_cflag & CRTSCTS)) {
		tty->hw_stopped = 0;
		cy_start(tty);
	}
L
Linus Torvalds 已提交
2836
#if 0
2837 2838 2839 2840 2841 2842 2843 2844
	/*
	 * 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 已提交
2845
		wake_up_interruptible(&info->port.open_wait);
L
Linus Torvalds 已提交
2846
#endif
2847
}				/* cy_set_termios */
L
Linus Torvalds 已提交
2848 2849 2850 2851

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

2858
	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
L
Linus Torvalds 已提交
2859 2860
		return;

2861
	info->x_char = ch;
L
Linus Torvalds 已提交
2862 2863

	if (ch)
2864
		cy_start(tty);
L
Linus Torvalds 已提交
2865 2866

	card = info->card;
2867
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
2868

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

/* 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.
 */
2881
static void cy_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2882
{
2883
	struct cyclades_port *info = tty->driver_data;
2884
	struct cyclades_card *card;
2885
	unsigned long flags;
L
Linus Torvalds 已提交
2886 2887

#ifdef CY_DEBUG_THROTTLE
2888
	char buf[64];
L
Linus Torvalds 已提交
2889

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

A
Alan Cox 已提交
2894
	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2895 2896 2897 2898 2899
		return;

	card = info->card;

	if (I_IXOFF(tty)) {
2900
		if (!cy_is_Z(card))
2901 2902 2903 2904
			cy_send_xchar(tty, STOP_CHAR(tty));
		else
			info->throttle = 1;
	}
L
Linus Torvalds 已提交
2905

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

/*
 * 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.
 */
2922
static void cy_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2923
{
2924
	struct cyclades_port *info = tty->driver_data;
2925
	struct cyclades_card *card;
2926
	unsigned long flags;
L
Linus Torvalds 已提交
2927 2928

#ifdef CY_DEBUG_THROTTLE
2929 2930
	char buf[64];

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

A
Alan Cox 已提交
2935
	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2936
		return;
L
Linus Torvalds 已提交
2937

2938 2939 2940 2941 2942
	if (I_IXOFF(tty)) {
		if (info->x_char)
			info->x_char = 0;
		else
			cy_send_xchar(tty, START_CHAR(tty));
L
Linus Torvalds 已提交
2943 2944
	}

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

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

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

2971 2972
	if (serial_paranoia_check(info, tty->name, "cy_stop"))
		return;
L
Linus Torvalds 已提交
2973

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

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

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

2995 2996
	if (serial_paranoia_check(info, tty->name, "cy_start"))
		return;
L
Linus Torvalds 已提交
2997

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

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

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

3019 3020
	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
		return;
L
Linus Torvalds 已提交
3021

3022
	cy_flush_buffer(tty);
J
Jiri Slaby 已提交
3023
	cy_shutdown(info, tty);
J
Jiri Slaby 已提交
3024
	tty_port_hangup(&info->port);
3025
}				/* cy_hangup */
L
Linus Torvalds 已提交
3026

J
Jiri Slaby 已提交
3027 3028 3029 3030 3031 3032 3033 3034 3035 3036
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);
3037 3038
	cyy_writeb(info, CyCAR, channel & 0x03);
	cd = cyy_readb(info, CyMSVR1) & CyDCD;
J
Jiri Slaby 已提交
3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051
	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 已提交
3052 3053
	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
J
Jiri Slaby 已提交
3054 3055 3056 3057 3058 3059 3060 3061
	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);

3062
	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
J
Jiri Slaby 已提交
3063 3064 3065 3066 3067 3068 3069
}

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;
3070
	struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
J
Jiri Slaby 已提交
3071 3072 3073
	int ret, channel = info->line - cinfo->first_line;
	u32 rs;

3074
	rs = readl(&ch_ctrl->rs_control);
J
Jiri Slaby 已提交
3075 3076 3077 3078
	if (raise)
		rs |= C_RS_RTS | C_RS_DTR;
	else
		rs &= ~(C_RS_RTS | C_RS_DTR);
3079
	cy_writel(&ch_ctrl->rs_control, rs);
J
Jiri Slaby 已提交
3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091
	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,
3092
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3093 3094 3095 3096 3097
};

static const struct tty_port_operations cyz_port_ops = {
	.carrier_raised = cyz_carrier_raised,
	.dtr_rts = cyz_dtr_rts,
3098
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3099 3100
};

L
Linus Torvalds 已提交
3101 3102 3103 3104 3105 3106 3107 3108
/*
 * ---------------------------------------------------------------------
 * cy_init() and friends
 *
 * cy_init() is called at boot-time to initialize the serial driver.
 * ---------------------------------------------------------------------
 */

J
Jiri Slaby 已提交
3109
static int __devinit cy_init_card(struct cyclades_card *cinfo)
3110 3111
{
	struct cyclades_port *info;
3112
	unsigned int channel, port;
3113

3114
	spin_lock_init(&cinfo->card_lock);
J
Jiri Slaby 已提交
3115
	cinfo->intr_enabled = 0;
3116

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

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

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

3137
		if (cy_is_Z(cinfo)) {
3138 3139 3140
			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
			struct ZFW_CTRL *zfw_ctrl;

J
Jiri Slaby 已提交
3141
			info->port.ops = &cyz_port_ops;
3142
			info->type = PORT_STARTECH;
3143 3144 3145 3146 3147 3148

			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 已提交
3149
			if (cinfo->hw_ver == ZO_V1)
3150 3151
				info->xmit_fifo_size = CYZ_FIFO_SIZE;
			else
3152
				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
3153
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3154 3155
			setup_timer(&cyz_rx_full_timer[port],
				cyz_rx_restart, (unsigned long)info);
3156
#endif
3157
		} else {
3158
			unsigned short chip_number;
J
Jiri Slaby 已提交
3159
			int index = cinfo->bus_index;
3160

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

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

			if (info->chip_rev >= CD1400_REV_J) {
3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186
				/* 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;
			}
3187 3188
			info->read_status_mask = CyTIMEOUT | CySPECHAR |
				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3189
		}
3190

3191
	}
3192 3193

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

L
Linus Torvalds 已提交
3204 3205
/* initialize chips on Cyclom-Y card -- return number of valid
   chips (which is number of ports/4) */
3206 3207
static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
		int index)
L
Linus Torvalds 已提交
3208
{
3209 3210 3211 3212 3213 3214 3215 3216 3217
	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 已提交
3218 3219
	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
							chip_number++) {
3220 3221 3222
		base_addr =
		    true_base_addr + (cy_chip_offset[chip_number] << index);
		mdelay(1);
3223
		if (readb(base_addr + (CyCCR << index)) != 0x00) {
3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239
			/*************
			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.
		 */
3240
		if (chip_number == 4 && readb(true_base_addr +
3241 3242 3243 3244 3245 3246 3247 3248
				(cy_chip_offset[0] << index) +
				(CyGFRCR << index)) == 0) {
			return chip_number;
		}

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

3249
		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
3250 3251 3252 3253 3254 3255 3256
			/*
			   printk(" chip #%d at %#6lx is not responding ",
			   chip_number, (unsigned long)base_addr);
			   printk("(GFRCR stayed 0)\n",
			 */
			return chip_number;
		}
3257
		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
3258 3259 3260 3261 3262 3263 3264 3265 3266 3267
				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);
3268
		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
3269 3270 3271 3272 3273 3274 3275 3276
			/* 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 已提交
3277

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

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

3301
	nboard = 0;
L
Linus Torvalds 已提交
3302 3303

	/* Check for module parameters */
3304 3305 3306 3307 3308 3309 3310
	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 已提交
3311 3312
	}

3313 3314 3315
	/* 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 已提交
3316
		if (isa_address == 0x0000)
J
Jiri Slaby 已提交
3317
			return nboard;
L
Linus Torvalds 已提交
3318

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

R
Roel Kluin 已提交
3333
		if (isparam && i < NR_CARDS && irq[i])
3334
			cy_isa_irq = irq[i];
L
Linus Torvalds 已提交
3335
		else
3336 3337 3338
			/* 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 已提交
3339 3340
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
				"IRQ could not be detected.\n",
3341
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3342
			iounmap(cy_isa_address);
3343 3344 3345 3346
			continue;
		}

		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
J
Jiri Slaby 已提交
3347 3348 3349
			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",
3350
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3351
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3352
			return nboard;
3353 3354 3355
		}
		/* fill the next cy_card structure available */
		for (j = 0; j < NR_CARDS; j++) {
J
Jiri Slaby 已提交
3356
			if (cy_card[j].base_addr == NULL)
3357 3358 3359
				break;
		}
		if (j == NR_CARDS) {	/* no more cy_cards available */
J
Jiri Slaby 已提交
3360 3361 3362
			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",
3363
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3364
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3365
			return nboard;
3366 3367 3368 3369
		}

		/* allocate IRQ */
		if (request_irq(cy_isa_irq, cyy_interrupt,
Y
Yong Zhang 已提交
3370
				0, "Cyclom-Y", &cy_card[j])) {
J
Jiri Slaby 已提交
3371 3372 3373
			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 已提交
3374
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3375
			return nboard;
3376 3377 3378 3379
		}

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

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

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

J
Jiri Slaby 已提交
3411
#ifdef CONFIG_PCI
3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426
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;
}

3427
static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3428 3429 3430 3431 3432 3433 3434 3435 3436 3437
		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 已提交
3438
{
3439
	/* Reset PLX */
3440
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
3441
	udelay(100L);
3442
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
3443 3444

	/* Reload Config. Registers from EEPROM */
3445
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3446
	udelay(100L);
3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459
	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)
{
3460 3461 3462 3463
	const void *ptr = fw->data;
	const struct zfile_header *h = ptr;
	const struct zfile_config *c, *cs;
	const struct zfile_block *b, *bs;
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 3538 3539
	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 已提交
3540
	void __iomem *tmp;
J
Jiri Slaby 已提交
3541
	u32 mailbox, status, nchan;
3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
	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 */
3553
	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571
		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);

3572
	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587
		/* 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;
3588
		if (!__cyz_fpga_loaded(ctl_addr)) {
3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601
			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 已提交
3602
	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3603 3604 3605 3606
		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 已提交
3607
		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
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 3645 3646
			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");

3647
			if (__cyz_fpga_loaded(ctl_addr))
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661
				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 已提交
3662
	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3663
	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
J
Jiri Slaby 已提交
3664
		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3665

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

3671
		if (__cyz_fpga_loaded(ctl_addr))
3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691
			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 已提交
3692
	return nchan;
3693 3694 3695 3696
err_rel:
	release_firmware(fw);
err:
	return retval;
L
Linus Torvalds 已提交
3697 3698
}

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

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

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

J
Jiri Slaby 已提交
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 3746
#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 已提交
3747 3748
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
J
Jiri Slaby 已提交
3749
		card_name = "Cyclom-Y";
L
Linus Torvalds 已提交
3750

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

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

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

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

3784
		plx_init(pdev, irq, addr0);
3785

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

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

		if (mailbox == ZE_V1) {
J
Jiri Slaby 已提交
3796
			card_name = "Cyclades-Ze";
J
Jiri Slaby 已提交
3797
		} else {
J
Jiri Slaby 已提交
3798
			card_name = "Cyclades-8Zo";
L
Linus Torvalds 已提交
3799
#ifdef CY_PCI_DEBUG
J
Jiri Slaby 已提交
3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812
			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 已提交
3813
#endif
J
Jiri Slaby 已提交
3814 3815 3816 3817 3818 3819
			/* 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 已提交
3820
		}
3821 3822

		retval = cyz_load_fw(pdev, addr2, addr0, irq);
J
Jiri Slaby 已提交
3823
		if (retval <= 0)
3824
			goto err_unmap;
J
Jiri Slaby 已提交
3825
		nchan = retval;
J
Jiri Slaby 已提交
3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853
	}

	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++) {
		if (cy_card[card_no].base_addr == NULL)
			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,
				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
		if (retval) {
			dev_err(&pdev->dev, "could not allocate IRQ\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3854
		}
J
Jiri Slaby 已提交
3855
		cy_card[card_no].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);

J
Jiri Slaby 已提交
3862 3863
		cy_card[card_no].hw_ver = mailbox;
		cy_card[card_no].num_chips = (unsigned int)-1;
3864
		cy_card[card_no].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,
J
Jiri Slaby 已提交
3869
					IRQF_SHARED, "Cyclades-Z",
J
Jiri Slaby 已提交
3870
					&cy_card[card_no]);
J
Jiri Slaby 已提交
3871
			if (retval) {
J
Jiri Slaby 已提交
3872
				dev_err(&pdev->dev, "could not allocate IRQ\n");
J
Jiri Slaby 已提交
3873
				goto err_unmap;
3874
			}
J
Jiri Slaby 已提交
3875
		}
3876
#endif				/* CONFIG_CYZ_INTR */
J
Jiri Slaby 已提交
3877
	}
3878

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

J
Jiri Slaby 已提交
3890
	pci_set_drvdata(pdev, &cy_card[card_no]);
J
Jiri Slaby 已提交
3891

J
Jiri Slaby 已提交
3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903
	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 */
3904 3905 3906 3907 3908
		{
			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 已提交
3909 3910
			break;
		}
3911
		}
J
Jiri Slaby 已提交
3912 3913
	}

J
Jiri Slaby 已提交
3914 3915 3916 3917 3918 3919
	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 已提交
3920
	return 0;
J
Jiri Slaby 已提交
3921 3922 3923 3924
err_null:
	cy_card[card_no].base_addr = NULL;
	free_irq(irq, &cy_card[card_no]);
err_unmap:
J
Jiri Slaby 已提交
3925
	iounmap(addr0);
J
Jiri Slaby 已提交
3926
	if (addr2)
J
Jiri Slaby 已提交
3927
		iounmap(addr2);
J
Jiri Slaby 已提交
3928 3929 3930 3931 3932 3933
err_reg:
	pci_release_regions(pdev);
err_dis:
	pci_disable_device(pdev);
err:
	return retval;
J
Jiri Slaby 已提交
3934 3935
}

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

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

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

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

3972 3973 3974 3975 3976 3977 3978 3979
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

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

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

	/* Output one line for each known port */
J
Jiri Slaby 已提交
3990 3991 3992 3993
	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 已提交
3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007
			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);
				}
4008
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4009
					"%10lu %8lu %9lu %6d\n", info->line,
J
Jiri Slaby 已提交
4010 4011 4012 4013 4014 4015
					(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 已提交
4016 4017
					num);
			} else
4018
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4019 4020
					"%10lu %8lu %9lu %6ld\n",
					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
4021
		}
4022 4023 4024 4025 4026 4027
	return 0;
}

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

4030 4031 4032 4033 4034 4035 4036 4037
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 已提交
4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055
/* 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 已提交
4056
static const struct tty_operations cy_ops = {
4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075
	.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,
4076
	.get_icount = cy_get_icount,
4077
	.proc_fops = &cyclades_proc_fops,
L
Linus Torvalds 已提交
4078 4079
};

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

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

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

	/* Initialize the tty_driver structure */

	cy_serial_driver->owner = THIS_MODULE;
	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;
4103
	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
4104 4105
	tty_set_operations(cy_serial_driver, &cy_ops);

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

	/* 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 */
4120
	nboards = cy_detect_isa();
4121

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

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

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

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

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

4152 4153 4154 4155
#ifdef CONFIG_PCI
	pci_unregister_driver(&cy_pci_driver);
#endif

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

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

module_init(cy_init);
module_exit(cy_cleanup_module);

MODULE_LICENSE("GPL");
4184
MODULE_VERSION(CY_VERSION);
4185
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4186
MODULE_FIRMWARE("cyzfirm.bin");