cyclades.c 111.0 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
	}
H
Huang Shijie 已提交
730
	if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) {
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);
		}
1462
		if (tty->termios.c_cflag & HUPCL)
J
Jiri Slaby 已提交
1463 1464
			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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

		if (c <= 0)
			break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Alan Cox 已提交
2002
	if (info->line == -1)
2003
		return;
A
Alan Cox 已提交
2004

2005 2006
	cflag = tty->termios.c_cflag;
	iflag = tty->termios.c_iflag;
L
Linus Torvalds 已提交
2007

2008 2009 2010
	/*
	 * Set up the tty->alt_speed kludge
	 */
J
Jiri Slaby 已提交
2011 2012 2013 2014 2015 2016 2017 2018
	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;
2019 2020

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

2023
	if (!cy_is_Z(card)) {
2024 2025
		u32 cflags;

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

A
Alan Cox 已提交
2045
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
				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 已提交
2066
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
				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 已提交
2102
		if (cflag & CSTOPB)
2103
			info->cor1 |= Cy_2_STOP;
A
Alan Cox 已提交
2104

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

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

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

2136
		channel &= 0x03;
L
Linus Torvalds 已提交
2137

2138
		spin_lock_irqsave(&card->card_lock, flags);
2139
		cyy_writeb(info, CyCAR, channel);
2140 2141 2142

		/* tx and rx baud rate */

2143 2144 2145 2146
		cyy_writeb(info, CyTCOR, info->tco);
		cyy_writeb(info, CyTBPR, info->tbpr);
		cyy_writeb(info, CyRCOR, info->rco);
		cyy_writeb(info, CyRBPR, info->rbpr);
2147 2148 2149

		/* set line characteristics  according configuration */

2150 2151 2152 2153 2154 2155 2156
		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);
2157

2158 2159
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
				CyCOR3ch);
2160

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

2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
		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);
2179

J
Jiri Slaby 已提交
2180 2181 2182 2183
		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 已提交
2184

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

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

2193
		if (!cyz_is_loaded(card))
2194
			return;
L
Linus Torvalds 已提交
2195

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/*
 * 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 已提交
2393
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
L
Linus Torvalds 已提交
2394
{
2395
	struct cyclades_card *card = info->card;
2396 2397
	unsigned int result;
	unsigned long flags;
2398
	u8 status;
L
Linus Torvalds 已提交
2399

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

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

2418
	if (serial_paranoia_check(info, tty->name, __func__))
2419
		return -ENODEV;
L
Linus Torvalds 已提交
2420

2421
	card = info->card;
J
Jiri Slaby 已提交
2422

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

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

		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 已提交
2445
	} else {
J
Jiri Slaby 已提交
2446 2447 2448 2449 2450
		u32 lstatus;

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

J
Jiri Slaby 已提交
2453 2454 2455 2456 2457 2458 2459
		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);
2460
	}
J
Jiri Slaby 已提交
2461
end:
2462 2463
	return result;
}				/* cy_tiomget */
L
Linus Torvalds 已提交
2464 2465

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

2473
	if (serial_paranoia_check(info, tty->name, __func__))
2474 2475 2476
		return -ENODEV;

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

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

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

2532 2533 2534
	card = info->card;

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

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

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

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

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

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

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

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

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

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

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

J
Jiri Slaby 已提交
2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655
	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 已提交
2656 2657 2658 2659 2660 2661 2662

/*
 * 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
2663
cy_ioctl(struct tty_struct *tty,
2664
	 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2665
{
2666
	struct cyclades_port *info = tty->driver_data;
J
Jiri Slaby 已提交
2667
	struct cyclades_icount cnow;	/* kernel counter temps */
2668 2669 2670 2671 2672 2673
	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 已提交
2674 2675

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

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

2767 2768 2769 2770 2771 2772 2773 2774 2775
		/*
		 * 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 已提交
2776 2777

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

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

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

J
Jiri Slaby 已提交
2822
	cy_set_line_char(info, tty);
2823 2824

	if ((old_termios->c_cflag & CRTSCTS) &&
2825
			!(tty->termios.c_cflag & CRTSCTS)) {
2826 2827 2828
		tty->hw_stopped = 0;
		cy_start(tty);
	}
L
Linus Torvalds 已提交
2829
#if 0
2830 2831 2832 2833 2834 2835 2836
	/*
	 * 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) &&
2837
	    (tty->termios.c_cflag & CLOCAL))
A
Alan Cox 已提交
2838
		wake_up_interruptible(&info->port.open_wait);
L
Linus Torvalds 已提交
2839
#endif
2840
}				/* cy_set_termios */
L
Linus Torvalds 已提交
2841 2842 2843 2844

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

2851
	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
L
Linus Torvalds 已提交
2852 2853
		return;

2854
	info->x_char = ch;
L
Linus Torvalds 已提交
2855 2856

	if (ch)
2857
		cy_start(tty);
L
Linus Torvalds 已提交
2858 2859

	card = info->card;
2860
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
2861

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

/* 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.
 */
2874
static void cy_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2875
{
2876
	struct cyclades_port *info = tty->driver_data;
2877
	struct cyclades_card *card;
2878
	unsigned long flags;
L
Linus Torvalds 已提交
2879 2880

#ifdef CY_DEBUG_THROTTLE
2881
	char buf[64];
L
Linus Torvalds 已提交
2882

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

A
Alan Cox 已提交
2887
	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2888 2889 2890 2891 2892
		return;

	card = info->card;

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

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

/*
 * 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.
 */
2915
static void cy_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2916
{
2917
	struct cyclades_port *info = tty->driver_data;
2918
	struct cyclades_card *card;
2919
	unsigned long flags;
L
Linus Torvalds 已提交
2920 2921

#ifdef CY_DEBUG_THROTTLE
2922 2923
	char buf[64];

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

A
Alan Cox 已提交
2928
	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2929
		return;
L
Linus Torvalds 已提交
2930

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

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

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

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

2964 2965
	if (serial_paranoia_check(info, tty->name, "cy_stop"))
		return;
L
Linus Torvalds 已提交
2966

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

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

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

2988 2989
	if (serial_paranoia_check(info, tty->name, "cy_start"))
		return;
L
Linus Torvalds 已提交
2990

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

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

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

3012 3013
	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
		return;
L
Linus Torvalds 已提交
3014

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

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

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

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

3067
	rs = readl(&ch_ctrl->rs_control);
J
Jiri Slaby 已提交
3068 3069 3070 3071
	if (raise)
		rs |= C_RS_RTS | C_RS_DTR;
	else
		rs &= ~(C_RS_RTS | C_RS_DTR);
3072
	cy_writel(&ch_ctrl->rs_control, rs);
J
Jiri Slaby 已提交
3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084
	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,
3085
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3086 3087 3088 3089 3090
};

static const struct tty_port_operations cyz_port_ops = {
	.carrier_raised = cyz_carrier_raised,
	.dtr_rts = cyz_dtr_rts,
3091
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3092 3093
};

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

B
Bill Pemberton 已提交
3102
static int cy_init_card(struct cyclades_card *cinfo)
3103 3104
{
	struct cyclades_port *info;
3105
	unsigned int channel, port;
3106

3107
	spin_lock_init(&cinfo->card_lock);
J
Jiri Slaby 已提交
3108
	cinfo->intr_enabled = 0;
3109

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

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

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

3130
		if (cy_is_Z(cinfo)) {
3131 3132 3133
			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
			struct ZFW_CTRL *zfw_ctrl;

J
Jiri Slaby 已提交
3134
			info->port.ops = &cyz_port_ops;
3135
			info->type = PORT_STARTECH;
3136 3137 3138 3139 3140 3141

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

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

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

			if (info->chip_rev >= CD1400_REV_J) {
3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179
				/* 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;
			}
3180 3181
			info->read_status_mask = CyTIMEOUT | CySPECHAR |
				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3182
		}
3183

3184
	}
3185 3186

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

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

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

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

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

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

3295
	nboard = 0;
L
Linus Torvalds 已提交
3296 3297

	/* Check for module parameters */
3298 3299 3300 3301 3302 3303 3304
	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 已提交
3305 3306
	}

3307 3308 3309
	/* 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 已提交
3310
		if (isa_address == 0x0000)
J
Jiri Slaby 已提交
3311
			return nboard;
L
Linus Torvalds 已提交
3312

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

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

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

		/* allocate IRQ */
		if (request_irq(cy_isa_irq, cyy_interrupt,
3365
				0, "Cyclom-Y", card)) {
J
Jiri Slaby 已提交
3366 3367 3368
			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 已提交
3369
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3370
			return nboard;
3371 3372 3373
		}

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

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

J
Jiri Slaby 已提交
3395 3396 3397 3398
		for (k = 0, j = cy_next_channel;
				j < cy_next_channel + cy_isa_nchan; j++, k++)
			tty_port_register_device(&card->ports[k].port,
					cy_serial_driver, j, NULL);
3399 3400
		cy_next_channel += cy_isa_nchan;
	}
J
Jiri Slaby 已提交
3401
	return nboard;
L
Linus Torvalds 已提交
3402
#else
J
Jiri Slaby 已提交
3403
	return 0;
3404 3405
#endif				/* CONFIG_ISA */
}				/* cy_detect_isa */
L
Linus Torvalds 已提交
3406

J
Jiri Slaby 已提交
3407
#ifdef CONFIG_PCI
B
Bill Pemberton 已提交
3408
static inline int cyc_isfwstr(const char *str, unsigned int size)
3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422
{
	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;
}

B
Bill Pemberton 已提交
3423
static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3424 3425 3426 3427 3428 3429 3430 3431
		unsigned int size)
{
	for (; size > 0; size--) {
		cy_writel(fpga, *data++);
		udelay(10);
	}
}

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

	/* Reload Config. Registers from EEPROM */
3441
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3442
	udelay(100L);
3443 3444 3445 3446 3447 3448 3449 3450 3451
	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);
}

B
Bill Pemberton 已提交
3452
static int __cyz_load_fw(const struct firmware *fw,
3453 3454 3455
		const char *name, const u32 mailbox, void __iomem *base,
		void __iomem *fpga)
{
3456 3457 3458 3459
	const void *ptr = fw->data;
	const struct zfile_header *h = ptr;
	const struct zfile_config *c, *cs;
	const struct zfile_block *b, *bs;
3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528
	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;
}

B
Bill Pemberton 已提交
3529
static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3530 3531 3532 3533 3534 3535
		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 已提交
3536
	void __iomem *tmp;
J
Jiri Slaby 已提交
3537
	u32 mailbox, status, nchan;
3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548
	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 */
3549
	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567
		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);

3568
	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583
		/* 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;
3584
		if (!__cyz_fpga_loaded(ctl_addr)) {
3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597
			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 已提交
3598
	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3599 3600 3601 3602
		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 已提交
3603
		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642
			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");

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

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

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

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

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

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

J
Jiri Slaby 已提交
3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743
#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 已提交
3744 3745
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
J
Jiri Slaby 已提交
3746
		card_name = "Cyclom-Y";
L
Linus Torvalds 已提交
3747

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

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

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

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

3781
		plx_init(pdev, irq, addr0);
3782

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

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

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

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

	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++) {
3833 3834
		card = &cy_card[card_no];
		if (card->base_addr == NULL)
J
Jiri Slaby 已提交
3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847
			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,
3848
				IRQF_SHARED, "Cyclom-Y", card);
J
Jiri Slaby 已提交
3849 3850 3851
		if (retval) {
			dev_err(&pdev->dev, "could not allocate IRQ\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3852
		}
3853
		card->num_chips = nchan / CyPORTS_PER_CHIP;
J
Jiri Slaby 已提交
3854
	} else {
3855 3856 3857 3858 3859
		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
		struct ZFW_CTRL __iomem *zfw_ctrl;

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

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

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

3887
	pci_set_drvdata(pdev, card);
J
Jiri Slaby 已提交
3888

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

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

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

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

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

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

	cinfo->base_addr = NULL;
3963 3964
	for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
			cinfo->nports; i++, channel++) {
3965
		tty_unregister_device(cy_serial_driver, i);
3966 3967
		tty_port_destroy(&cinfo->ports[channel].port);
	}
J
Jiri Slaby 已提交
3968 3969
	cinfo->nports = 0;
	kfree(cinfo->ports);
J
Jiri Slaby 已提交
3970 3971
}

3972 3973 3974 3975
static struct pci_driver cy_pci_driver = {
	.name = "cyclades",
	.id_table = cy_pci_dev_id,
	.probe = cy_pci_probe,
B
Bill Pemberton 已提交
3976
	.remove = cy_pci_remove
3977 3978 3979
};
#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

	/* Initialize the tty_driver structure */

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

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

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

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

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

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

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

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

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

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

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

module_init(cy_init);
module_exit(cy_cleanup_module);

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