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

/*
 *  linux/drivers/char/cyclades.c
 *
 * 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 已提交
14
 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
L
Linus Torvalds 已提交
15 16 17 18 19
 *
 * 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.
20
 * Converted to pci probing and cleaned up by Jiri Slaby.
L
Linus Torvalds 已提交
21 22 23
 *
 */

J
Jiri Slaby 已提交
24
#define CY_VERSION	"2.6"
J
Jiri Slaby 已提交
25

L
Linus Torvalds 已提交
26 27 28 29
/* 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. */

30
#define NR_CARDS	4
L
Linus Torvalds 已提交
31 32 33 34 35 36

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

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

#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_WAIT_UNTIL_SENT
#undef	CY_DEBUG_INTERRUPTS
#undef	CY_16Y_HACK
#undef	CY_ENABLE_MONITORING
#undef	CY_PCI_DEBUG

/*
A
Alan Cox 已提交
57
 * Include section
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65
 */
#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 已提交
66
#include <linux/tty_flip.h>
L
Linus Torvalds 已提交
67 68 69 70 71 72 73 74 75 76 77 78
#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>
79
#include <linux/firmware.h>
80
#include <linux/device.h>
81
#include <linux/slab.h>
L
Linus Torvalds 已提交
82

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

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

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

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

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

#define STD_COM_FLAGS (0)

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 134 135 136
/* 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 已提交
137 138 139 140 141 142 143 144 145 146 147
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[] = {
148 149 150 151 152 153 154 155 156
	0xD0000,
	0xD2000,
	0xD4000,
	0xD6000,
	0xD8000,
	0xDA000,
	0xDC000,
	0xDE000,
	0, 0, 0, 0, 0, 0, 0, 0
L
Linus Torvalds 已提交
157
};
158

159
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
L
Linus Torvalds 已提交
160

161 162
static long maddr[NR_CARDS];
static int irq[NR_CARDS];
L
Linus Torvalds 已提交
163 164 165 166

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

167
#endif				/* CONFIG_ISA */
L
Linus Torvalds 已提交
168 169 170 171 172 173

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

174
static int cy_next_channel;	/* next minor available */
L
Linus Torvalds 已提交
175 176 177 178

/*
 * 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 已提交
179
 * are accessed via settings in info->port.flags.
L
Linus Torvalds 已提交
180 181 182 183 184
 *      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 已提交
185
static const int baud_table[] = {
186 187 188 189 190
	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 已提交
191
static const char baud_co_25[] = {	/* 25 MHz clock option table */
192 193 194 195 196 197
	/* 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 已提交
198
static const char baud_bpr_25[] = {	/* 25 MHz baud rate period table */
199 200 201 202
	0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
	0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
};

J
Jiri Slaby 已提交
203
static const char baud_co_60[] = {	/* 60 MHz clock option table (CD1400 J) */
204 205 206 207 208 209 210
	/* 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 已提交
211
static const char baud_bpr_60[] = {	/* 60 MHz baud rate period table (CD1400 J) */
212 213 214 215 216
	0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
	0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
	0x21
};

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

/*
 * The Cyclades driver implements HW flow control as any serial driver.
A
Alan Cox 已提交
225 226 227 228 229 230
 * 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 已提交
231 232 233
 * cables.
 */

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

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

/* PCI related definitions */

#ifdef CONFIG_PCI
J
Jiri Slaby 已提交
256
static const struct pci_device_id cy_pci_dev_id[] = {
A
Alan Cox 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
	/* 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) },
273
	{ }			/* end of table */
274
};
275
MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
L
Linus Torvalds 已提交
276 277 278
#endif

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

#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;

291
static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
L
Linus Torvalds 已提交
292

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

298 299 300 301 302 303 304 305 306 307 308 309 310 311
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));
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
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;
}

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

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

/***********************************************************/
/********* 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.
 */
364
static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
L
Linus Torvalds 已提交
365
{
366
	void __iomem *ccr = base_addr + (CyCCR << index);
J
Jiri Slaby 已提交
367
	unsigned int i;
L
Linus Torvalds 已提交
368

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

380
	/* Issue the new command */
381
	cy_writeb(ccr, cmd);
L
Linus Torvalds 已提交
382

J
Jiri Slaby 已提交
383
	return 0;
384 385 386 387 388 389 390
}

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 已提交
391 392 393

#ifdef CONFIG_ISA
/* ISA interrupt detection code */
A
Alan Cox 已提交
394
static unsigned detect_isa_irq(void __iomem *address)
L
Linus Torvalds 已提交
395
{
396 397 398 399 400 401 402 403 404 405 406 407 408 409
	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 已提交
410
	msleep(5);
411 412 413 414

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

	cy_writeb(address + (CyCAR << index), 0);
	cy_writeb(address + (CySRER << index),
419
		  readb(address + (CySRER << index)) | CyTxRdy);
420 421 422
	local_irq_restore(flags);

	/* Wait ... */
J
Jiri Slaby 已提交
423
	msleep(5);
424 425 426 427 428

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

	/* Clean up */
429 430
	save_xir = (u_char) readb(address + (CyTIR << index));
	save_car = readb(address + (CyCAR << index));
431 432
	cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
	cy_writeb(address + (CySRER << index),
433
		  readb(address + (CySRER << index)) & ~CyTxRdy);
434 435 436 437 438 439
	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 已提交
440
}
441
#endif				/* CONFIG_ISA */
L
Linus Torvalds 已提交
442

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

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

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

		/* 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 已提交
490
			tty_kref_put(tty);
491 492 493 494 495 496
			return;
		}
		if (tty_buffer_request_room(tty, 1)) {
			if (data & info->read_status_mask) {
				if (data & CyBREAK) {
					tty_insert_flip_char(tty,
497 498
						cyy_readb(info, CyRDSR),
						TTY_BREAK);
499
					info->icount.rx++;
A
Alan Cox 已提交
500
					if (info->port.flags & ASYNC_SAK)
501 502
						do_SAK(tty);
				} else if (data & CyFRAME) {
A
Alan Cox 已提交
503
					tty_insert_flip_char(tty,
504 505
						cyy_readb(info, CyRDSR),
						TTY_FRAME);
506 507 508 509 510
					info->icount.rx++;
					info->idle_stats.frame_errs++;
				} else if (data & CyPARITY) {
					/* Pieces of seven... */
					tty_insert_flip_char(tty,
511 512
						cyy_readb(info, CyRDSR),
						TTY_PARITY);
513 514 515 516 517 518 519 520 521 522 523
					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,
524 525
						cyy_readb(info, CyRDSR),
						TTY_FRAME);
526 527
					info->icount.rx++;
					info->idle_stats.overruns++;
528 529 530 531 532 533 534 535
				/* 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++;
536
				}
537 538 539 540 541 542 543 544 545 546 547 548
			} 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 */
549
		char_count = cyy_readb(info, CyRDCR);
550 551

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

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

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

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

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

606 607
	/* load the on-chip space for outbound data */
	char_count = info->xmit_fifo_size;
608

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

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

632 633
	while (char_count-- > 0) {
		if (!info->xmit_cnt) {
634 635 636
			if (cyy_readb(info, CySRER) & CyTxMpty) {
				cyy_writeb(info, CySRER,
					cyy_readb(info, CySRER) & ~CyTxMpty);
637
			} else {
638 639
				cyy_writeb(info, CySRER, CyTxMpty |
					(cyy_readb(info, CySRER) & ~CyTxRdy));
640
			}
641 642
			goto done;
		}
A
Alan Cox 已提交
643
		if (info->port.xmit_buf == NULL) {
644 645
			cyy_writeb(info, CySRER,
				cyy_readb(info, CySRER) & ~CyTxRdy);
646 647
			goto done;
		}
J
Jiri Slaby 已提交
648
		if (tty->stopped || tty->hw_stopped) {
649 650
			cyy_writeb(info, CySRER,
				cyy_readb(info, CySRER) & ~CyTxRdy);
651 652 653 654 655 656 657 658 659 660 661
			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 已提交
662
		outch = info->port.xmit_buf[info->xmit_tail];
663 664 665 666
		if (outch) {
			info->xmit_cnt--;
			info->xmit_tail = (info->xmit_tail + 1) &
					(SERIAL_XMIT_SIZE - 1);
667
			cyy_writeb(info, CyTDR, outch);
668 669 670
			info->icount.tx++;
		} else {
			if (char_count > 1) {
671 672
				info->xmit_cnt--;
				info->xmit_tail = (info->xmit_tail + 1) &
673
					(SERIAL_XMIT_SIZE - 1);
674 675
				cyy_writeb(info, CyTDR, outch);
				cyy_writeb(info, CyTDR, 0);
676
				info->icount.tx++;
677
				char_count--;
678
			}
679 680 681
		}
	}

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

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

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

706 707
	mdm_change = cyy_readb(info, CyMISR);
	mdm_status = cyy_readb(info, CyMSVR1);
708

J
Jiri Slaby 已提交
709 710
	tty = tty_port_tty_get(&info->port);
	if (!tty)
711 712 713 714 715 716 717 718 719 720 721 722 723
		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++;

724
		wake_up_interruptible(&info->port.delta_msr_wait);
725 726
	}

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

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

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

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

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

791 792 793 794 795 796 797 798 799 800 801
	/* 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;
802
			while ((status = readb(base_addr +
803 804 805 806 807 808 809
						(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).
			 */
810
				if (1000 < too_many++)
811
					break;
812
				spin_lock(&cinfo->card_lock);
813 814 815 816 817 818
				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);
819
				spin_unlock(&cinfo->card_lock);
820 821 822 823 824 825 826 827 828 829 830
			}
		}
	} 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 已提交
831

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

	channel &= 0x03;

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

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

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

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

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

913
	if (!cyz_is_loaded(cinfo))
J
Jiri Slaby 已提交
914
		return -1;
A
Alan Cox 已提交
915

916
	index = 0;
917
	pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
918
	while ((readl(pci_doorbell) & 0xff) != 0) {
A
Alan Cox 已提交
919
		if (index++ == 1000)
920
			return (int)(readl(pci_doorbell) & 0xff);
921 922 923 924 925 926
		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 已提交
927
	return 0;
928
}				/* cyz_issue_cmd */
L
Linus Torvalds 已提交
929

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

943 944 945 946
	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);
947 948 949 950
	if (rx_put >= rx_get)
		char_count = rx_put - rx_get;
	else
		char_count = rx_put - rx_get + rx_bufsize;
L
Linus Torvalds 已提交
951

952
	if (char_count) {
L
Linus Torvalds 已提交
953
#ifdef CY_ENABLE_MONITORING
954 955 956 957 958
		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 已提交
959
#endif
J
Jiri Slaby 已提交
960
		if (tty == NULL) {
961 962 963 964 965
			/* flush received characters */
			new_rx_get = (new_rx_get + char_count) &
					(rx_bufsize - 1);
			info->rflush_count++;
		} else {
L
Linus Torvalds 已提交
966
#ifdef BLOCKMOVE
967 968 969
		/* 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 已提交
970 971 972 973 974 975 976 977 978 979 980 981 982
			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) &
983
						(rx_bufsize - 1);
J
Jiri Slaby 已提交
984 985 986
				char_count -= len;
				info->icount.rx += len;
				info->idle_stats.recv_bytes += len;
987
			}
L
Linus Torvalds 已提交
988
#else
989 990
			len = tty_buffer_request_room(tty, char_count);
			while (len--) {
991
				data = readb(cinfo->base_addr + rx_bufaddr +
992
						new_rx_get);
A
Alan Cox 已提交
993 994
				new_rx_get = (new_rx_get + 1) &
							(rx_bufsize - 1);
995 996 997 998
				tty_insert_flip_char(tty, data, TTY_NORMAL);
				info->idle_stats.recv_bytes++;
				info->icount.rx++;
			}
L
Linus Torvalds 已提交
999 1000
#endif
#ifdef CONFIG_CYZ_INTR
1001 1002
		/* Recalculate the number of chars in the RX buffer and issue
		   a cmd in case it's higher than the RX high water mark */
1003
			rx_put = readl(&buf_ctrl->rx_put);
1004 1005 1006 1007
			if (rx_put >= rx_get)
				char_count = rx_put - rx_get;
			else
				char_count = rx_put - rx_get + rx_bufsize;
J
Jiri Slaby 已提交
1008
			if (char_count >= readl(&buf_ctrl->rx_threshold) &&
1009 1010 1011 1012
					!timer_pending(&cyz_rx_full_timer[
							info->line]))
				mod_timer(&cyz_rx_full_timer[info->line],
						jiffies + 1);
L
Linus Torvalds 已提交
1013
#endif
1014 1015 1016 1017 1018
			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 已提交
1019 1020 1021
	}
}

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

1033 1034
	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
		return;
L
Linus Torvalds 已提交
1035

1036 1037 1038 1039
	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);
1040 1041 1042 1043
	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 已提交
1044

1045
	if (char_count) {
L
Linus Torvalds 已提交
1046

J
Jiri Slaby 已提交
1047
		if (tty == NULL)
1048
			goto ztxdone;
L
Linus Torvalds 已提交
1049

1050 1051
		if (info->x_char) {	/* send special char */
			data = info->x_char;
L
Linus Torvalds 已提交
1052

1053 1054 1055 1056 1057 1058
			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 已提交
1059
#ifdef BLOCKMOVE
1060 1061 1062 1063 1064 1065 1066 1067
		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 已提交
1068
					&info->port.xmit_buf[info->xmit_tail],
1069 1070 1071 1072 1073 1074 1075 1076 1077
					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 已提交
1078
#else
1079
		while (info->xmit_cnt && char_count) {
A
Alan Cox 已提交
1080
			data = info->port.xmit_buf[info->xmit_tail];
1081 1082 1083 1084 1085 1086 1087 1088 1089
			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 已提交
1090
#endif
1091
		tty_wakeup(tty);
1092
ztxdone:
1093 1094
		/* Update tx_put */
		cy_writel(&buf_ctrl->tx_put, tx_put);
L
Linus Torvalds 已提交
1095 1096 1097
	}
}

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

1108
	fw_ver = readl(&board_ctrl->fw_version);
1109 1110 1111 1112

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

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

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

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

1212 1213
	/* Handle the interrupts */
	cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1214

1215 1216
	return IRQ_HANDLED;
}				/* cyz_interrupt */
L
Linus Torvalds 已提交
1217

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

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

1235
#else				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1236

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

1244 1245 1246
	for (card = 0; card < NR_CARDS; card++) {
		cinfo = &cy_card[card];

1247
		if (!cy_is_Z(cinfo))
1248
			continue;
1249
		if (!cyz_is_loaded(cinfo))
1250 1251
			continue;

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

1258
		cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1259

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

J
Jiri Slaby 已提交
1263
			info = &cinfo->ports[port];
J
Jiri Slaby 已提交
1264 1265 1266 1267
			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. */

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

1279
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1280 1281 1282 1283 1284 1285 1286

/********** 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 已提交
1287
static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1288
{
1289
	struct cyclades_card *card;
1290 1291
	unsigned long flags;
	int retval = 0;
J
Jiri Slaby 已提交
1292
	int channel;
1293
	unsigned long page;
L
Linus Torvalds 已提交
1294

1295
	card = info->card;
1296
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1297

1298 1299 1300
	page = get_zeroed_page(GFP_KERNEL);
	if (!page)
		return -ENOMEM;
L
Linus Torvalds 已提交
1301

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

J
Jiri Slaby 已提交
1304
	if (info->port.flags & ASYNC_INITIALIZED)
1305
		goto errout;
L
Linus Torvalds 已提交
1306

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

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

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

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

1321
	if (!cy_is_Z(card)) {
1322
		channel &= 0x03;
L
Linus Torvalds 已提交
1323

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

1326
		cyy_writeb(info, CyCAR, channel);
L
Linus Torvalds 已提交
1327

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

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

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

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

1340
		if (!cyz_is_loaded(card))
1341
			return -ENODEV;
L
Linus Torvalds 已提交
1342 1343

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

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

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

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

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

1386
		/* enable send, recv, modem !!! */
J
Jiri Slaby 已提交
1387
	}
1388

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

J
Jiri Slaby 已提交
1391 1392 1393 1394 1395 1396 1397 1398 1399
	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 已提交
1400 1401

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

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

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

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

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

/*
 * 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 已提交
1444
static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1445
{
1446
	struct cyclades_card *card;
1447
	unsigned long flags;
1448
	int channel;
1449

A
Alan Cox 已提交
1450
	if (!(info->port.flags & ASYNC_INITIALIZED))
1451 1452 1453
		return;

	card = info->card;
1454
	channel = info->line - card->first_line;
1455
	if (!cy_is_Z(card)) {
1456
		spin_lock_irqsave(&card->card_lock, flags);
1457 1458

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

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

1470
		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
1471 1472 1473
		/* it may be appropriate to clear _XMIT at
		   some later date (after testing)!!! */

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

1483
		if (!cyz_is_loaded(card))
1484
			return;
L
Linus Torvalds 已提交
1485

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

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

J
Jiri Slaby 已提交
1495 1496
		if (tty->termios->c_cflag & HUPCL)
			tty_port_lower_dtr_rts(&info->port);
L
Linus Torvalds 已提交
1497

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

1501
		spin_unlock_irqrestore(&card->card_lock, flags);
1502
	}
L
Linus Torvalds 已提交
1503 1504

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

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

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

1525
	line = tty->index;
A
Alan Cox 已提交
1526
	if (tty->index < 0 || NR_PORTS <= line)
1527
		return -ENODEV;
A
Alan Cox 已提交
1528

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

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

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

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

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

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

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

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

1631
	info->throttle = 0;
J
Jiri Slaby 已提交
1632
	tty_port_tty_set(&info->port, tty);
L
Linus Torvalds 已提交
1633

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

/*
 * cy_wait_until_sent() --- wait until the transmitter is empty
 */
1643
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
L
Linus Torvalds 已提交
1644
{
1645
	struct cyclades_card *card;
1646
	struct cyclades_port *info = tty->driver_data;
1647 1648 1649 1650 1651 1652 1653 1654
	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 已提交
1655

1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
	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;
L
Linus Torvalds 已提交
1684
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
J
Jiri Slaby 已提交
1685 1686
	printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
		timeout, char_time, jiffies);
L
Linus Torvalds 已提交
1687
#endif
1688
	card = info->card;
1689
	if (!cy_is_Z(card)) {
1690
		while (cyy_readb(info, CySRER) & CyTxRdy) {
L
Linus Torvalds 已提交
1691
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
J
Jiri Slaby 已提交
1692
			printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
L
Linus Torvalds 已提交
1693
#endif
1694 1695 1696 1697 1698 1699
			if (msleep_interruptible(jiffies_to_msecs(char_time)))
				break;
			if (timeout && time_after(jiffies, orig_jiffies +
					timeout))
				break;
		}
L
Linus Torvalds 已提交
1700
	}
1701 1702
	/* Run one more char cycle */
	msleep_interruptible(jiffies_to_msecs(char_time * 5));
L
Linus Torvalds 已提交
1703
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
J
Jiri Slaby 已提交
1704
	printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
L
Linus Torvalds 已提交
1705 1706 1707
#endif
}

1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
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);

1729
	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742
					   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 */


1743
static void cy_do_close(struct tty_port *port)
L
Linus Torvalds 已提交
1744
{
1745 1746
	struct cyclades_port *info = container_of(port, struct cyclades_port,
								port);
1747
	struct cyclades_card *card;
1748
	unsigned long flags;
1749
	int channel;
L
Linus Torvalds 已提交
1750

1751
	card = info->card;
1752
	channel = info->line - card->first_line;
1753
	spin_lock_irqsave(&card->card_lock, flags);
1754

1755
	if (!cy_is_Z(card)) {
1756
		/* Stop accepting input */
1757 1758
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
A
Alan Cox 已提交
1759
		if (info->port.flags & ASYNC_INITIALIZED) {
A
Alan Cox 已提交
1760 1761
			/* Waiting for on-board buffers to be empty before
			   closing the port */
1762
			spin_unlock_irqrestore(&card->card_lock, flags);
1763
			cy_wait_until_sent(port->tty, info->timeout);
1764
			spin_lock_irqsave(&card->card_lock, flags);
1765 1766 1767
		}
	} else {
#ifdef Z_WAKE
A
Alan Cox 已提交
1768 1769
		/* Waiting for on-board buffers to be empty before closing
		   the port */
1770
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
1771 1772
		int retval;

1773
		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
1774
			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
1775
			if (retval != 0) {
J
Jiri Slaby 已提交
1776 1777
				printk(KERN_DEBUG "cyc:cy_close retval on "
					"ttyC%d was %x\n", info->line, retval);
1778
			}
1779
			spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1780
			wait_for_completion_interruptible(&info->shutdown_wait);
1781
			spin_lock_irqsave(&card->card_lock, flags);
1782
		}
L
Linus Torvalds 已提交
1783
#endif
1784
	}
1785
	spin_unlock_irqrestore(&card->card_lock, flags);
1786 1787
	cy_shutdown(info, port->tty);
}
L
Linus Torvalds 已提交
1788

1789 1790 1791 1792 1793 1794 1795 1796 1797
/*
 * 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);
1798
}				/* cy_close */
L
Linus Torvalds 已提交
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812

/* 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.
 *
 */
1813
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
L
Linus Torvalds 已提交
1814
{
1815
	struct cyclades_port *info = tty->driver_data;
1816 1817
	unsigned long flags;
	int c, ret = 0;
L
Linus Torvalds 已提交
1818 1819

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

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

A
Alan Cox 已提交
1826
	if (!info->port.xmit_buf)
1827
		return 0;
L
Linus Torvalds 已提交
1828

1829
	spin_lock_irqsave(&info->card->card_lock, flags);
1830
	while (1) {
1831 1832
		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
1833 1834 1835 1836

		if (c <= 0)
			break;

A
Alan Cox 已提交
1837
		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
1838 1839 1840 1841 1842 1843 1844
		info->xmit_head = (info->xmit_head + c) &
			(SERIAL_XMIT_SIZE - 1);
		info->xmit_cnt += c;
		buf += c;
		count -= c;
		ret += c;
	}
1845
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1846 1847 1848 1849

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

A
Alan Cox 已提交
1850
	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1851
		start_xmit(info);
A
Alan Cox 已提交
1852

1853 1854
	return ret;
}				/* cy_write */
L
Linus Torvalds 已提交
1855 1856 1857 1858 1859 1860 1861 1862

/*
 * 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.
 */
1863
static int cy_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
1864
{
1865
	struct cyclades_port *info = tty->driver_data;
1866
	unsigned long flags;
L
Linus Torvalds 已提交
1867 1868

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

1872
	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1873
		return 0;
L
Linus Torvalds 已提交
1874

A
Alan Cox 已提交
1875
	if (!info->port.xmit_buf)
1876
		return 0;
L
Linus Torvalds 已提交
1877

1878
	spin_lock_irqsave(&info->card->card_lock, flags);
J
Jiri Slaby 已提交
1879
	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
1880
		spin_unlock_irqrestore(&info->card->card_lock, flags);
1881
		return 0;
1882
	}
L
Linus Torvalds 已提交
1883

A
Alan Cox 已提交
1884
	info->port.xmit_buf[info->xmit_head++] = ch;
1885 1886
	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
	info->xmit_cnt++;
L
Linus Torvalds 已提交
1887 1888
	info->idle_stats.xmit_bytes++;
	info->idle_stats.xmit_idle = jiffies;
1889
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1890
	return 1;
1891
}				/* cy_put_char */
L
Linus Torvalds 已提交
1892 1893 1894

/*
 * This routine is called by the kernel after it has written a
A
Alan Cox 已提交
1895
 * series of characters to the tty device using put_char().
L
Linus Torvalds 已提交
1896
 */
1897
static void cy_flush_chars(struct tty_struct *tty)
L
Linus Torvalds 已提交
1898
{
1899
	struct cyclades_port *info = tty->driver_data;
1900

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

1905 1906
	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
		return;
L
Linus Torvalds 已提交
1907

1908
	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
A
Alan Cox 已提交
1909
			!info->port.xmit_buf)
1910
		return;
L
Linus Torvalds 已提交
1911

1912 1913
	start_xmit(info);
}				/* cy_flush_chars */
L
Linus Torvalds 已提交
1914 1915 1916 1917 1918 1919 1920

/*
 * 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.
 */
1921
static int cy_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
1922
{
1923
	struct cyclades_port *info = tty->driver_data;
1924 1925
	int ret;

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

1930 1931 1932 1933 1934 1935 1936
	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 已提交
1937

1938
static int cy_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1939
{
1940
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
1941

1942 1943 1944
	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
		return 0;

L
Linus Torvalds 已提交
1945
#ifdef Z_EXT_CHARS_IN_BUFFER
1946
	if (!cy_is_Z(info->card)) {
1947
#endif				/* Z_EXT_CHARS_IN_BUFFER */
L
Linus Torvalds 已提交
1948
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1949 1950
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt);
L
Linus Torvalds 已提交
1951
#endif
1952
		return info->xmit_cnt;
L
Linus Torvalds 已提交
1953
#ifdef Z_EXT_CHARS_IN_BUFFER
1954
	} else {
1955
		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1956
		int char_count;
J
Jiri Slaby 已提交
1957
		__u32 tx_put, tx_get, tx_bufsize;
1958

1959 1960 1961
		tx_get = readl(&buf_ctrl->tx_get);
		tx_put = readl(&buf_ctrl->tx_put);
		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1962 1963 1964 1965
		if (tx_put >= tx_get)
			char_count = tx_put - tx_get;
		else
			char_count = tx_put - tx_get + tx_bufsize;
L
Linus Torvalds 已提交
1966
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1967 1968
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt + char_count);
L
Linus Torvalds 已提交
1969
#endif
J
Jiri Slaby 已提交
1970
		return info->xmit_cnt + char_count;
1971 1972 1973
	}
#endif				/* Z_EXT_CHARS_IN_BUFFER */
}				/* cy_chars_in_buffer */
L
Linus Torvalds 已提交
1974 1975 1976 1977 1978 1979 1980

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

K
Klaus Kudielka 已提交
1981
static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
L
Linus Torvalds 已提交
1982
{
1983
	int co, co_val, bpr;
K
Klaus Kudielka 已提交
1984
	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
1985
			25000000);
L
Linus Torvalds 已提交
1986

1987 1988 1989 1990
	if (baud == 0) {
		info->tbpr = info->tco = info->rbpr = info->rco = 0;
		return;
	}
L
Linus Torvalds 已提交
1991

1992 1993 1994 1995 1996
	/* 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 已提交
1997

1998 1999 2000
	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
	if (bpr > 255)
		bpr = 255;
L
Linus Torvalds 已提交
2001

2002 2003
	info->tbpr = info->rbpr = bpr;
	info->tco = info->rco = co;
L
Linus Torvalds 已提交
2004 2005 2006 2007 2008 2009
}

/*
 * This routine finds or computes the various line characteristics.
 * It used to be called config_setup
 */
J
Jiri Slaby 已提交
2010
static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
2011
{
2012
	struct cyclades_card *card;
2013
	unsigned long flags;
2014
	int channel;
2015 2016 2017 2018
	unsigned cflag, iflag;
	int baud, baud_rate = 0;
	int i;

J
Jiri Slaby 已提交
2019
	if (!tty->termios) /* XXX can this happen at all? */
2020
		return;
A
Alan Cox 已提交
2021 2022

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

J
Jiri Slaby 已提交
2025 2026
	cflag = tty->termios->c_cflag;
	iflag = tty->termios->c_iflag;
L
Linus Torvalds 已提交
2027

2028 2029 2030
	/*
	 * Set up the tty->alt_speed kludge
	 */
J
Jiri Slaby 已提交
2031 2032 2033 2034 2035 2036 2037 2038
	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;
2039 2040

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

2043
	if (!cy_is_Z(card)) {
2044 2045
		u32 cflags;

2046
		/* baud rate */
J
Jiri Slaby 已提交
2047
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2048
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058
				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 已提交
2059
			if (baud == baud_table[i])
2060 2061
				break;
		}
A
Alan Cox 已提交
2062
		if (i == 20)
2063 2064
			i = 19;	/* CD1400_MAX_SPEED */

A
Alan Cox 已提交
2065
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085
				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 已提交
2086
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121
				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 已提交
2122
		if (cflag & CSTOPB)
2123
			info->cor1 |= Cy_2_STOP;
A
Alan Cox 已提交
2124

2125
		if (cflag & PARENB) {
A
Alan Cox 已提交
2126
			if (cflag & PARODD)
2127
				info->cor1 |= CyPARITY_O;
A
Alan Cox 已提交
2128
			else
2129
				info->cor1 |= CyPARITY_E;
A
Alan Cox 已提交
2130
		} else
2131 2132 2133 2134
			info->cor1 |= CyPARITY_NONE;

		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
A
Alan Cox 已提交
2135
			info->port.flags |= ASYNC_CTS_FLOW;
2136 2137
			info->cor2 |= CyCtsAE;
		} else {
A
Alan Cox 已提交
2138
			info->port.flags &= ~ASYNC_CTS_FLOW;
2139 2140 2141
			info->cor2 &= ~CyCtsAE;
		}
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2142
			info->port.flags &= ~ASYNC_CHECK_CD;
2143
		else
A
Alan Cox 已提交
2144
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155

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

2156
		channel &= 0x03;
L
Linus Torvalds 已提交
2157

2158
		spin_lock_irqsave(&card->card_lock, flags);
2159
		cyy_writeb(info, CyCAR, channel);
2160 2161 2162

		/* tx and rx baud rate */

2163 2164 2165 2166
		cyy_writeb(info, CyTCOR, info->tco);
		cyy_writeb(info, CyTBPR, info->tbpr);
		cyy_writeb(info, CyRCOR, info->rco);
		cyy_writeb(info, CyRBPR, info->rbpr);
2167 2168 2169

		/* set line characteristics  according configuration */

2170 2171 2172 2173 2174 2175 2176
		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);
2177

2178 2179
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
				CyCOR3ch);
2180

A
Alan Cox 已提交
2181
		/* !!! Is this needed? */
2182 2183
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, CyRTPR,
2184 2185 2186
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */

2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198
		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);
2199

J
Jiri Slaby 已提交
2200 2201 2202 2203
		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 已提交
2204

J
Jiri Slaby 已提交
2205
		clear_bit(TTY_IO_ERROR, &tty->flags);
2206
		spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
2207 2208

	} else {
2209
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
K
Klaus Kudielka 已提交
2210
		__u32 sw_flow;
2211
		int retval;
L
Linus Torvalds 已提交
2212

2213
		if (!cyz_is_loaded(card))
2214
			return;
L
Linus Torvalds 已提交
2215

2216
		/* baud rate */
J
Jiri Slaby 已提交
2217
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2218
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
				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 已提交
2233
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2234 2235 2236 2237 2238 2239 2240 2241 2242 2243
				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 已提交
2244

2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
		/* 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,
2262
				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
2263 2264
		} else {
			cy_writel(&ch_ctrl->comm_data_l,
2265
				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
2266 2267
		}
		if (cflag & PARENB) {
A
Alan Cox 已提交
2268
			if (cflag & PARODD)
2269
				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
A
Alan Cox 已提交
2270
			else
2271
				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
A
Alan Cox 已提交
2272
		} else
2273
			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
L
Linus Torvalds 已提交
2274

2275 2276 2277
		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
			cy_writel(&ch_ctrl->hw_flow,
2278
				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
2279
		} else {
2280 2281
			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
					~(C_RS_CTS | C_RS_RTS));
2282 2283 2284
		}
		/* As the HW flow control is done in firmware, the driver
		   doesn't need to care about it */
A
Alan Cox 已提交
2285
		info->port.flags &= ~ASYNC_CTS_FLOW;
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295

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

2296
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
2297
		if (retval != 0) {
J
Jiri Slaby 已提交
2298 2299
			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
				"was %x\n", info->line, retval);
2300 2301 2302
		}

		/* CD sensitivity */
A
Alan Cox 已提交
2303
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2304
			info->port.flags &= ~ASYNC_CHECK_CD;
A
Alan Cox 已提交
2305
		else
A
Alan Cox 已提交
2306
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2307

2308 2309
		if (baud == 0) {	/* baud rate is zero, turn off line */
			cy_writel(&ch_ctrl->rs_control,
2310
				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
L
Linus Torvalds 已提交
2311
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2312
			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
L
Linus Torvalds 已提交
2313
#endif
2314 2315
		} else {
			cy_writel(&ch_ctrl->rs_control,
2316
				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
L
Linus Torvalds 已提交
2317
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2318
			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
L
Linus Torvalds 已提交
2319
#endif
2320
		}
L
Linus Torvalds 已提交
2321

A
Alan Cox 已提交
2322
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
2323
		if (retval != 0) {
J
Jiri Slaby 已提交
2324 2325
			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
				"was %x\n", info->line, retval);
2326
		}
L
Linus Torvalds 已提交
2327

J
Jiri Slaby 已提交
2328
		clear_bit(TTY_IO_ERROR, &tty->flags);
L
Linus Torvalds 已提交
2329
	}
2330
}				/* set_line_char */
L
Linus Torvalds 已提交
2331

J
Jiri Slaby 已提交
2332
static int cy_get_serial_info(struct cyclades_port *info,
A
Alan Cox 已提交
2333
		struct serial_struct __user *retinfo)
L
Linus Torvalds 已提交
2334
{
2335
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348
	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,		/*!!! */
	};
2349
	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
J
Jiri Slaby 已提交
2350
}
L
Linus Torvalds 已提交
2351 2352

static int
J
Jiri Slaby 已提交
2353
cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
A
Alan Cox 已提交
2354
		struct serial_struct __user *new_info)
L
Linus Torvalds 已提交
2355
{
2356
	struct serial_struct new_serial;
A
Alan Cox 已提交
2357
	int ret;
2358 2359 2360 2361

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

A
Alan Cox 已提交
2362
	mutex_lock(&info->port.mutex);
2363
	if (!capable(CAP_SYS_ADMIN)) {
A
Alan Cox 已提交
2364
		if (new_serial.close_delay != info->port.close_delay ||
2365 2366 2367
				new_serial.baud_base != info->baud ||
				(new_serial.flags & ASYNC_FLAGS &
					~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
2368
				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
A
Alan Cox 已提交
2369 2370
		{
			mutex_unlock(&info->port.mutex);
2371
			return -EPERM;
A
Alan Cox 已提交
2372
		}
A
Alan Cox 已提交
2373
		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
				(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 已提交
2387
	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
2388
			(new_serial.flags & ASYNC_FLAGS);
A
Alan Cox 已提交
2389 2390
	info->port.close_delay = new_serial.close_delay * HZ / 100;
	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
L
Linus Torvalds 已提交
2391 2392

check_and_exit:
A
Alan Cox 已提交
2393
	if (info->port.flags & ASYNC_INITIALIZED) {
J
Jiri Slaby 已提交
2394
		cy_set_line_char(info, tty);
A
Alan Cox 已提交
2395
		ret = 0;
2396
	} else {
A
Alan Cox 已提交
2397
		ret = cy_startup(info, tty);
2398
	}
A
Alan Cox 已提交
2399 2400
	mutex_unlock(&info->port.mutex);
	return ret;
2401
}				/* set_serial_info */
L
Linus Torvalds 已提交
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412

/*
 * 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 已提交
2413
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
L
Linus Torvalds 已提交
2414
{
2415
	struct cyclades_card *card = info->card;
2416 2417
	unsigned int result;
	unsigned long flags;
2418
	u8 status;
L
Linus Torvalds 已提交
2419

2420
	if (!cy_is_Z(card)) {
2421
		spin_lock_irqsave(&card->card_lock, flags);
2422
		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
2423
		spin_unlock_irqrestore(&card->card_lock, flags);
2424 2425 2426 2427 2428 2429
		result = (status ? 0 : TIOCSER_TEMT);
	} else {
		/* Not supported yet */
		return -EINVAL;
	}
	return put_user(result, (unsigned long __user *)value);
L
Linus Torvalds 已提交
2430 2431
}

2432
static int cy_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
2433
{
2434
	struct cyclades_port *info = tty->driver_data;
2435
	struct cyclades_card *card;
2436
	int result;
2437

2438
	if (serial_paranoia_check(info, tty->name, __func__))
2439
		return -ENODEV;
L
Linus Torvalds 已提交
2440

2441
	card = info->card;
J
Jiri Slaby 已提交
2442

2443
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2444
		unsigned long flags;
2445 2446
		int channel = info->line - card->first_line;
		u8 status;
L
Linus Torvalds 已提交
2447

2448
		spin_lock_irqsave(&card->card_lock, flags);
2449 2450 2451
		cyy_writeb(info, CyCAR, channel & 0x03);
		status = cyy_readb(info, CyMSVR1);
		status |= cyy_readb(info, CyMSVR2);
2452
		spin_unlock_irqrestore(&card->card_lock, flags);
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464

		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 已提交
2465
	} else {
J
Jiri Slaby 已提交
2466 2467 2468 2469 2470
		u32 lstatus;

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

J
Jiri Slaby 已提交
2473 2474 2475 2476 2477 2478 2479
		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);
2480
	}
J
Jiri Slaby 已提交
2481
end:
2482 2483
	return result;
}				/* cy_tiomget */
L
Linus Torvalds 已提交
2484 2485

static int
2486
cy_tiocmset(struct tty_struct *tty,
2487
		unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
2488
{
2489
	struct cyclades_port *info = tty->driver_data;
2490
	struct cyclades_card *card;
2491 2492
	unsigned long flags;

2493
	if (serial_paranoia_check(info, tty->name, __func__))
2494 2495 2496
		return -ENODEV;

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

/*
 * cy_break() --- routine which turns the break handling on or off
 */
A
Alan Cox 已提交
2542
static int cy_break(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
2543
{
2544
	struct cyclades_port *info = tty->driver_data;
2545
	struct cyclades_card *card;
2546
	unsigned long flags;
A
Alan Cox 已提交
2547
	int retval = 0;
L
Linus Torvalds 已提交
2548

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

2552 2553 2554
	card = info->card;

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

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

2607
	if (!cy_is_Z(card)) {
2608 2609
		info->cor3 &= ~CyREC_FIFO;
		info->cor3 |= value & CyREC_FIFO;
L
Linus Torvalds 已提交
2610

2611
		spin_lock_irqsave(&card->card_lock, flags);
2612 2613
		cyy_writeb(info, CyCOR3, info->cor3);
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
2614
		spin_unlock_irqrestore(&card->card_lock, flags);
2615 2616 2617
	}
	return 0;
}				/* set_threshold */
L
Linus Torvalds 已提交
2618

A
Alan Cox 已提交
2619 2620
static int get_threshold(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2621
{
2622
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2623

2624
	if (!cy_is_Z(card)) {
2625
		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
2626 2627
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2628
	return 0;
2629
}				/* get_threshold */
L
Linus Torvalds 已提交
2630

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

2636
	if (!cy_is_Z(card)) {
2637
		spin_lock_irqsave(&card->card_lock, flags);
2638
		cyy_writeb(info, CyRTPR, value & 0xff);
2639
		spin_unlock_irqrestore(&card->card_lock, flags);
2640 2641 2642
	}
	return 0;
}				/* set_timeout */
L
Linus Torvalds 已提交
2643

A
Alan Cox 已提交
2644 2645
static int get_timeout(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2646
{
2647
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2648

2649
	if (!cy_is_Z(card)) {
2650
		u8 tmp = cyy_readb(info, CyRTPR);
2651 2652
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2653
	return 0;
2654
}				/* get_timeout */
L
Linus Torvalds 已提交
2655

J
Jiri Slaby 已提交
2656 2657
static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
		struct cyclades_icount *cprev)
L
Linus Torvalds 已提交
2658
{
J
Jiri Slaby 已提交
2659 2660 2661
	struct cyclades_icount cnow;
	unsigned long flags;
	int ret;
L
Linus Torvalds 已提交
2662

J
Jiri Slaby 已提交
2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675
	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 已提交
2676 2677 2678 2679 2680 2681 2682

/*
 * 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
2683
cy_ioctl(struct tty_struct *tty,
2684
	 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2685
{
2686
	struct cyclades_port *info = tty->driver_data;
J
Jiri Slaby 已提交
2687
	struct cyclades_icount cnow;	/* kernel counter temps */
2688 2689 2690 2691 2692 2693
	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 已提交
2694 2695

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

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

2787 2788 2789 2790 2791 2792 2793 2794 2795
		/*
		 * 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 已提交
2796 2797

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2798
	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
L
Linus Torvalds 已提交
2799
#endif
2800 2801
	return ret_val;
}				/* cy_ioctl */
L
Linus Torvalds 已提交
2802

2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827
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 已提交
2828 2829 2830 2831 2832 2833
/*
 * 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.
 */
2834
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
L
Linus Torvalds 已提交
2835
{
2836
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
2837 2838

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

J
Jiri Slaby 已提交
2842
	cy_set_line_char(info, tty);
2843 2844 2845 2846 2847 2848

	if ((old_termios->c_cflag & CRTSCTS) &&
			!(tty->termios->c_cflag & CRTSCTS)) {
		tty->hw_stopped = 0;
		cy_start(tty);
	}
L
Linus Torvalds 已提交
2849
#if 0
2850 2851 2852 2853 2854 2855 2856 2857
	/*
	 * No need to wake up processes in open wait, since they
	 * sample the CLOCAL flag once, and don't recheck it.
	 * XXX  It's not clear whether the current behavior is correct
	 * or not.  Hence, this may change.....
	 */
	if (!(old_termios->c_cflag & CLOCAL) &&
	    (tty->termios->c_cflag & CLOCAL))
A
Alan Cox 已提交
2858
		wake_up_interruptible(&info->port.open_wait);
L
Linus Torvalds 已提交
2859
#endif
2860
}				/* cy_set_termios */
L
Linus Torvalds 已提交
2861 2862 2863 2864

/* This function is used to send a high-priority XON/XOFF character to
   the device.
*/
2865
static void cy_send_xchar(struct tty_struct *tty, char ch)
L
Linus Torvalds 已提交
2866
{
2867
	struct cyclades_port *info = tty->driver_data;
2868 2869
	struct cyclades_card *card;
	int channel;
L
Linus Torvalds 已提交
2870

2871
	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
L
Linus Torvalds 已提交
2872 2873
		return;

2874
	info->x_char = ch;
L
Linus Torvalds 已提交
2875 2876

	if (ch)
2877
		cy_start(tty);
L
Linus Torvalds 已提交
2878 2879

	card = info->card;
2880
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
2881

2882
	if (cy_is_Z(card)) {
2883
		if (ch == STOP_CHAR(tty))
2884
			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
2885
		else if (ch == START_CHAR(tty))
2886
			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
L
Linus Torvalds 已提交
2887 2888 2889 2890 2891 2892 2893
	}
}

/* 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.
 */
2894
static void cy_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2895
{
2896
	struct cyclades_port *info = tty->driver_data;
2897
	struct cyclades_card *card;
2898
	unsigned long flags;
L
Linus Torvalds 已提交
2899 2900

#ifdef CY_DEBUG_THROTTLE
2901
	char buf[64];
L
Linus Torvalds 已提交
2902

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

A
Alan Cox 已提交
2907
	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2908 2909 2910 2911 2912
		return;

	card = info->card;

	if (I_IXOFF(tty)) {
2913
		if (!cy_is_Z(card))
2914 2915 2916 2917
			cy_send_xchar(tty, STOP_CHAR(tty));
		else
			info->throttle = 1;
	}
L
Linus Torvalds 已提交
2918

2919
	if (tty->termios->c_cflag & CRTSCTS) {
2920
		if (!cy_is_Z(card)) {
2921
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2922
			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
2923
			spin_unlock_irqrestore(&card->card_lock, flags);
2924 2925 2926 2927 2928
		} else {
			info->throttle = 1;
		}
	}
}				/* cy_throttle */
L
Linus Torvalds 已提交
2929 2930 2931 2932 2933 2934

/*
 * 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.
 */
2935
static void cy_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2936
{
2937
	struct cyclades_port *info = tty->driver_data;
2938
	struct cyclades_card *card;
2939
	unsigned long flags;
L
Linus Torvalds 已提交
2940 2941

#ifdef CY_DEBUG_THROTTLE
2942 2943
	char buf[64];

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

A
Alan Cox 已提交
2948
	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2949
		return;
L
Linus Torvalds 已提交
2950

2951 2952 2953 2954 2955
	if (I_IXOFF(tty)) {
		if (info->x_char)
			info->x_char = 0;
		else
			cy_send_xchar(tty, START_CHAR(tty));
L
Linus Torvalds 已提交
2956 2957
	}

2958 2959
	if (tty->termios->c_cflag & CRTSCTS) {
		card = info->card;
2960
		if (!cy_is_Z(card)) {
2961
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2962
			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
2963
			spin_unlock_irqrestore(&card->card_lock, flags);
2964 2965 2966 2967 2968
		} else {
			info->throttle = 0;
		}
	}
}				/* cy_unthrottle */
L
Linus Torvalds 已提交
2969 2970 2971 2972

/* cy_start and cy_stop provide software output flow control as a
   function of XON/XOFF, software CTS, and other such stuff.
*/
2973
static void cy_stop(struct tty_struct *tty)
L
Linus Torvalds 已提交
2974
{
2975
	struct cyclades_card *cinfo;
2976
	struct cyclades_port *info = tty->driver_data;
2977
	int channel;
2978
	unsigned long flags;
L
Linus Torvalds 已提交
2979 2980

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

2984 2985
	if (serial_paranoia_check(info, tty->name, "cy_stop"))
		return;
L
Linus Torvalds 已提交
2986

2987
	cinfo = info->card;
2988
	channel = info->line - cinfo->first_line;
2989
	if (!cy_is_Z(cinfo)) {
2990
		spin_lock_irqsave(&cinfo->card_lock, flags);
2991 2992
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
2993
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2994 2995
	}
}				/* cy_stop */
L
Linus Torvalds 已提交
2996

2997
static void cy_start(struct tty_struct *tty)
L
Linus Torvalds 已提交
2998
{
2999
	struct cyclades_card *cinfo;
3000
	struct cyclades_port *info = tty->driver_data;
3001
	int channel;
3002
	unsigned long flags;
L
Linus Torvalds 已提交
3003 3004

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

3008 3009
	if (serial_paranoia_check(info, tty->name, "cy_start"))
		return;
L
Linus Torvalds 已提交
3010

3011
	cinfo = info->card;
3012
	channel = info->line - cinfo->first_line;
3013
	if (!cy_is_Z(cinfo)) {
3014
		spin_lock_irqsave(&cinfo->card_lock, flags);
3015 3016
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
3017
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
3018 3019
	}
}				/* cy_start */
L
Linus Torvalds 已提交
3020 3021 3022 3023

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

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

3032 3033
	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
		return;
L
Linus Torvalds 已提交
3034

3035
	cy_flush_buffer(tty);
J
Jiri Slaby 已提交
3036
	cy_shutdown(info, tty);
J
Jiri Slaby 已提交
3037
	tty_port_hangup(&info->port);
3038
}				/* cy_hangup */
L
Linus Torvalds 已提交
3039

J
Jiri Slaby 已提交
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
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);
3050 3051
	cyy_writeb(info, CyCAR, channel & 0x03);
	cd = cyy_readb(info, CyMSVR1) & CyDCD;
J
Jiri Slaby 已提交
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
	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 已提交
3065 3066
	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
J
Jiri Slaby 已提交
3067 3068 3069 3070 3071 3072 3073 3074
	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);

3075
	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
J
Jiri Slaby 已提交
3076 3077 3078 3079 3080 3081 3082
}

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

3087
	rs = readl(&ch_ctrl->rs_control);
J
Jiri Slaby 已提交
3088 3089 3090 3091
	if (raise)
		rs |= C_RS_RTS | C_RS_DTR;
	else
		rs &= ~(C_RS_RTS | C_RS_DTR);
3092
	cy_writel(&ch_ctrl->rs_control, rs);
J
Jiri Slaby 已提交
3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104
	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,
3105
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3106 3107 3108 3109 3110
};

static const struct tty_port_operations cyz_port_ops = {
	.carrier_raised = cyz_carrier_raised,
	.dtr_rts = cyz_dtr_rts,
3111
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3112 3113
};

L
Linus Torvalds 已提交
3114 3115 3116 3117 3118 3119 3120 3121
/*
 * ---------------------------------------------------------------------
 * cy_init() and friends
 *
 * cy_init() is called at boot-time to initialize the serial driver.
 * ---------------------------------------------------------------------
 */

J
Jiri Slaby 已提交
3122
static int __devinit cy_init_card(struct cyclades_card *cinfo)
3123 3124
{
	struct cyclades_port *info;
3125
	unsigned int channel, port;
3126

3127
	spin_lock_init(&cinfo->card_lock);
J
Jiri Slaby 已提交
3128
	cinfo->intr_enabled = 0;
3129

J
Jiri Slaby 已提交
3130 3131
	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
			GFP_KERNEL);
J
Jiri Slaby 已提交
3132 3133 3134 3135 3136
	if (cinfo->ports == NULL) {
		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
		return -ENOMEM;
	}

3137 3138 3139
	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
			channel++, port++) {
		info = &cinfo->ports[channel];
A
Alan Cox 已提交
3140
		tty_port_init(&info->port);
3141
		info->magic = CYCLADES_MAGIC;
3142
		info->card = cinfo;
3143 3144
		info->line = port;

A
Alan Cox 已提交
3145 3146
		info->port.closing_wait = CLOSING_WAIT_DELAY;
		info->port.close_delay = 5 * HZ / 10;
A
Alan Cox 已提交
3147
		info->port.flags = STD_COM_FLAGS;
J
Jiri Slaby 已提交
3148
		init_completion(&info->shutdown_wait);
3149

3150
		if (cy_is_Z(cinfo)) {
3151 3152 3153
			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
			struct ZFW_CTRL *zfw_ctrl;

J
Jiri Slaby 已提交
3154
			info->port.ops = &cyz_port_ops;
3155
			info->type = PORT_STARTECH;
3156 3157 3158 3159 3160 3161

			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 已提交
3162
			if (cinfo->hw_ver == ZO_V1)
3163 3164
				info->xmit_fifo_size = CYZ_FIFO_SIZE;
			else
3165
				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
3166
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3167 3168
			setup_timer(&cyz_rx_full_timer[port],
				cyz_rx_restart, (unsigned long)info);
3169
#endif
3170
		} else {
3171
			unsigned short chip_number;
J
Jiri Slaby 已提交
3172
			int index = cinfo->bus_index;
3173

J
Jiri Slaby 已提交
3174
			info->port.ops = &cyy_port_ops;
3175 3176
			info->type = PORT_CIRRUS;
			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
3177
			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
3178 3179
			info->cor2 = CyETC;
			info->cor3 = 0x08;	/* _very_ small rcv threshold */
3180

3181
			chip_number = channel / CyPORTS_PER_CHIP;
3182 3183 3184
			info->u.cyy.base_addr = cinfo->base_addr +
				(cy_chip_offset[chip_number] << index);
			info->chip_rev = cyy_readb(info, CyGFRCR);
A
Alan Cox 已提交
3185 3186

			if (info->chip_rev >= CD1400_REV_J) {
3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199
				/* 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;
			}
3200 3201
			info->read_status_mask = CyTIMEOUT | CySPECHAR |
				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3202
		}
3203

3204
	}
3205 3206

#ifndef CONFIG_CYZ_INTR
3207
	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
3208 3209 3210 3211 3212 3213
		mod_timer(&cyz_timerlist, jiffies + 1);
#ifdef CY_PCI_DEBUG
		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
#endif
	}
#endif
J
Jiri Slaby 已提交
3214
	return 0;
3215 3216
}

L
Linus Torvalds 已提交
3217 3218
/* initialize chips on Cyclom-Y card -- return number of valid
   chips (which is number of ports/4) */
3219 3220
static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
		int index)
L
Linus Torvalds 已提交
3221
{
3222 3223 3224 3225 3226 3227 3228 3229 3230
	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 已提交
3231 3232
	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
							chip_number++) {
3233 3234 3235
		base_addr =
		    true_base_addr + (cy_chip_offset[chip_number] << index);
		mdelay(1);
3236
		if (readb(base_addr + (CyCCR << index)) != 0x00) {
3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252
			/*************
			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.
		 */
3253
		if (chip_number == 4 && readb(true_base_addr +
3254 3255 3256 3257 3258 3259 3260 3261
				(cy_chip_offset[0] << index) +
				(CyGFRCR << index)) == 0) {
			return chip_number;
		}

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

3262
		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
3263 3264 3265 3266 3267 3268 3269
			/*
			   printk(" chip #%d at %#6lx is not responding ",
			   chip_number, (unsigned long)base_addr);
			   printk("(GFRCR stayed 0)\n",
			 */
			return chip_number;
		}
3270
		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
3271 3272 3273 3274 3275 3276 3277 3278 3279 3280
				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);
3281
		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
3282 3283 3284 3285 3286 3287 3288 3289
			/* 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 已提交
3290

3291 3292 3293
		/*
		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
		   chip_number, (unsigned long)base_addr,
3294
		   readb(base_addr+(CyGFRCR<<index)));
3295 3296 3297 3298
		 */
	}
	return chip_number;
}				/* cyy_init_card */
L
Linus Torvalds 已提交
3299 3300 3301 3302 3303 3304 3305

/*
 * ---------------------------------------------------------------------
 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
 * sets global variables and return the number of ISA boards found.
 * ---------------------------------------------------------------------
 */
3306
static int __init cy_detect_isa(void)
L
Linus Torvalds 已提交
3307 3308
{
#ifdef CONFIG_ISA
3309 3310 3311 3312
	unsigned short cy_isa_irq, nboard;
	void __iomem *cy_isa_address;
	unsigned short i, j, cy_isa_nchan;
	int isparam = 0;
L
Linus Torvalds 已提交
3313

3314
	nboard = 0;
L
Linus Torvalds 已提交
3315 3316

	/* Check for module parameters */
3317 3318 3319 3320 3321 3322 3323
	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 已提交
3324 3325
	}

3326 3327 3328
	/* 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 已提交
3329
		if (isa_address == 0x0000)
J
Jiri Slaby 已提交
3330
			return nboard;
L
Linus Torvalds 已提交
3331

3332
		/* probe for CD1400... */
3333
		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
J
Jiri Slaby 已提交
3334 3335 3336 3337 3338
		if (cy_isa_address == NULL) {
			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
					"address\n");
			continue;
		}
3339 3340 3341
		cy_isa_nchan = CyPORTS_PER_CHIP *
			cyy_init_card(cy_isa_address, 0);
		if (cy_isa_nchan == 0) {
J
Jiri Slaby 已提交
3342
			iounmap(cy_isa_address);
3343 3344
			continue;
		}
3345

R
Roel Kluin 已提交
3346
		if (isparam && i < NR_CARDS && irq[i])
3347
			cy_isa_irq = irq[i];
L
Linus Torvalds 已提交
3348
		else
3349 3350 3351
			/* 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 已提交
3352 3353
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
				"IRQ could not be detected.\n",
3354
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3355
			iounmap(cy_isa_address);
3356 3357 3358 3359
			continue;
		}

		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
J
Jiri Slaby 已提交
3360 3361 3362
			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",
3363
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3364
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3365
			return nboard;
3366 3367 3368
		}
		/* fill the next cy_card structure available */
		for (j = 0; j < NR_CARDS; j++) {
J
Jiri Slaby 已提交
3369
			if (cy_card[j].base_addr == NULL)
3370 3371 3372
				break;
		}
		if (j == NR_CARDS) {	/* no more cy_cards available */
J
Jiri Slaby 已提交
3373 3374 3375
			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",
3376
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3377
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3378
			return nboard;
3379 3380 3381 3382 3383
		}

		/* allocate IRQ */
		if (request_irq(cy_isa_irq, cyy_interrupt,
				IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
J
Jiri Slaby 已提交
3384 3385 3386
			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 已提交
3387
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3388
			return nboard;
3389 3390 3391 3392
		}

		/* set cy_card */
		cy_card[j].base_addr = cy_isa_address;
3393
		cy_card[j].ctl_addr.p9050 = NULL;
3394 3395 3396
		cy_card[j].irq = (int)cy_isa_irq;
		cy_card[j].bus_index = 0;
		cy_card[j].first_line = cy_next_channel;
J
Jiri Slaby 已提交
3397 3398
		cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
		cy_card[j].nports = cy_isa_nchan;
J
Jiri Slaby 已提交
3399 3400 3401 3402 3403 3404
		if (cy_init_card(&cy_card[j])) {
			cy_card[j].base_addr = NULL;
			free_irq(cy_isa_irq, &cy_card[j]);
			iounmap(cy_isa_address);
			continue;
		}
3405 3406
		nboard++;

J
Jiri Slaby 已提交
3407 3408
		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
			"%d channels starting from port %d\n",
3409 3410
			j + 1, (unsigned long)cy_isa_address,
			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
J
Jiri Slaby 已提交
3411 3412
			cy_isa_irq, cy_isa_nchan, cy_next_channel);

3413 3414 3415
		for (j = cy_next_channel;
				j < cy_next_channel + cy_isa_nchan; j++)
			tty_register_device(cy_serial_driver, j, NULL);
3416 3417
		cy_next_channel += cy_isa_nchan;
	}
J
Jiri Slaby 已提交
3418
	return nboard;
L
Linus Torvalds 已提交
3419
#else
J
Jiri Slaby 已提交
3420
	return 0;
3421 3422
#endif				/* CONFIG_ISA */
}				/* cy_detect_isa */
L
Linus Torvalds 已提交
3423

J
Jiri Slaby 已提交
3424
#ifdef CONFIG_PCI
3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439
static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
{
	unsigned int a;

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

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

	return 0;
}

3440
static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3441 3442 3443 3444 3445 3446 3447 3448 3449 3450
		unsigned int size)
{
	for (; size > 0; size--) {
		cy_writel(fpga, *data++);
		udelay(10);
	}
}

static void __devinit plx_init(struct pci_dev *pdev, int irq,
		struct RUNTIME_9060 __iomem *addr)
L
Linus Torvalds 已提交
3451
{
3452
	/* Reset PLX */
3453
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
3454
	udelay(100L);
3455
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
3456 3457

	/* Reload Config. Registers from EEPROM */
3458
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3459
	udelay(100L);
3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);

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

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

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

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

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

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

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

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

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

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

static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
{
	const struct firmware *fw;
	struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
	struct CUSTOM_REG __iomem *cust = base_addr;
	struct ZFW_CTRL __iomem *pt_zfwctrl;
J
Jiri Slaby 已提交
3553
	void __iomem *tmp;
J
Jiri Slaby 已提交
3554
	u32 mailbox, status, nchan;
3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565
	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 */
3566
	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584
		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);

3585
	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600
		/* 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;
3601
		if (!__cyz_fpga_loaded(ctl_addr)) {
3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614
			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 已提交
3615
	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3616 3617 3618 3619
		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 已提交
3620
		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659
			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");

3660
			if (__cyz_fpga_loaded(ctl_addr))
3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674
				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 已提交
3675
	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3676
	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
J
Jiri Slaby 已提交
3677
		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3678

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

3684
		if (__cyz_fpga_loaded(ctl_addr))
3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704
			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 已提交
3705
	return nchan;
3706 3707 3708 3709
err_rel:
	release_firmware(fw);
err:
	return retval;
L
Linus Torvalds 已提交
3710 3711
}

J
Jiri Slaby 已提交
3712 3713
static int __devinit cy_pci_probe(struct pci_dev *pdev,
		const struct pci_device_id *ent)
L
Linus Torvalds 已提交
3714
{
J
Jiri Slaby 已提交
3715 3716
	void __iomem *addr0 = NULL, *addr2 = NULL;
	char *card_name = NULL;
J
Jiri Slaby 已提交
3717
	u32 uninitialized_var(mailbox);
J
Jiri Slaby 已提交
3718 3719 3720
	unsigned int device_id, nchan = 0, card_no, i;
	unsigned char plx_ver;
	int retval, irq;
3721

J
Jiri Slaby 已提交
3722 3723 3724
	retval = pci_enable_device(pdev);
	if (retval) {
		dev_err(&pdev->dev, "cannot enable device\n");
J
Jiri Slaby 已提交
3725
		goto err;
J
Jiri Slaby 已提交
3726
	}
L
Linus Torvalds 已提交
3727

J
Jiri Slaby 已提交
3728
	/* read PCI configuration area */
J
Jiri Slaby 已提交
3729
	irq = pdev->irq;
J
Jiri Slaby 已提交
3730
	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
L
Linus Torvalds 已提交
3731

J
Jiri Slaby 已提交
3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759
#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 已提交
3760 3761
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
J
Jiri Slaby 已提交
3762
		card_name = "Cyclom-Y";
L
Linus Torvalds 已提交
3763

J
Jiri Slaby 已提交
3764 3765
		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Yctl);
J
Jiri Slaby 已提交
3766 3767 3768
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
J
Jiri Slaby 已提交
3769
		}
J
Jiri Slaby 已提交
3770 3771
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				CyPCI_Ywin);
J
Jiri Slaby 已提交
3772 3773 3774
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3775
		}
L
Linus Torvalds 已提交
3776

J
Jiri Slaby 已提交
3777 3778
		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
		if (nchan == 0) {
J
Jiri Slaby 已提交
3779 3780
			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
					"Serial-Modules\n");
3781
			goto err_unmap;
J
Jiri Slaby 已提交
3782 3783
		}
	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
J
Jiri Slaby 已提交
3784
		struct RUNTIME_9060 __iomem *ctl_addr;
J
Jiri Slaby 已提交
3785

J
Jiri Slaby 已提交
3786 3787
		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Zctl);
J
Jiri Slaby 已提交
3788 3789 3790 3791
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
		}
J
Jiri Slaby 已提交
3792 3793

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

3797
		plx_init(pdev, irq, addr0);
3798

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

J
Jiri Slaby 已提交
3801 3802
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
J
Jiri Slaby 已提交
3803 3804 3805
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3806 3807 3808
		}

		if (mailbox == ZE_V1) {
J
Jiri Slaby 已提交
3809
			card_name = "Cyclades-Ze";
J
Jiri Slaby 已提交
3810
		} else {
J
Jiri Slaby 已提交
3811
			card_name = "Cyclades-8Zo";
L
Linus Torvalds 已提交
3812
#ifdef CY_PCI_DEBUG
J
Jiri Slaby 已提交
3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825
			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 已提交
3826
#endif
J
Jiri Slaby 已提交
3827 3828 3829 3830 3831 3832
			/* 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 已提交
3833
		}
3834 3835

		retval = cyz_load_fw(pdev, addr2, addr0, irq);
J
Jiri Slaby 已提交
3836
		if (retval <= 0)
3837
			goto err_unmap;
J
Jiri Slaby 已提交
3838
		nchan = retval;
J
Jiri Slaby 已提交
3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866
	}

	if ((cy_next_channel + nchan) > NR_PORTS) {
		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
			"channels are available. Change NR_PORTS in "
			"cyclades.c and recompile kernel.\n");
		goto err_unmap;
	}
	/* fill the next cy_card structure available */
	for (card_no = 0; card_no < NR_CARDS; card_no++) {
		if (cy_card[card_no].base_addr == NULL)
			break;
	}
	if (card_no == NR_CARDS) {	/* no more cy_cards available */
		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
			"more cards can be used. Change NR_CARDS in "
			"cyclades.c and recompile kernel.\n");
		goto err_unmap;
	}

	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
		/* allocate IRQ */
		retval = request_irq(irq, cyy_interrupt,
				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
		if (retval) {
			dev_err(&pdev->dev, "could not allocate IRQ\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3867
		}
J
Jiri Slaby 已提交
3868
		cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
J
Jiri Slaby 已提交
3869
	} else {
3870 3871 3872 3873 3874
		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
		struct ZFW_CTRL __iomem *zfw_ctrl;

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

J
Jiri Slaby 已提交
3875 3876
		cy_card[card_no].hw_ver = mailbox;
		cy_card[card_no].num_chips = (unsigned int)-1;
3877
		cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
3878
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3879
		/* allocate IRQ only if board has an IRQ */
J
Jiri Slaby 已提交
3880 3881
		if (irq != 0 && irq != 255) {
			retval = request_irq(irq, cyz_interrupt,
J
Jiri Slaby 已提交
3882
					IRQF_SHARED, "Cyclades-Z",
J
Jiri Slaby 已提交
3883
					&cy_card[card_no]);
J
Jiri Slaby 已提交
3884
			if (retval) {
J
Jiri Slaby 已提交
3885
				dev_err(&pdev->dev, "could not allocate IRQ\n");
J
Jiri Slaby 已提交
3886
				goto err_unmap;
3887
			}
J
Jiri Slaby 已提交
3888
		}
3889
#endif				/* CONFIG_CYZ_INTR */
J
Jiri Slaby 已提交
3890
	}
3891

J
Jiri Slaby 已提交
3892 3893
	/* set cy_card */
	cy_card[card_no].base_addr = addr2;
3894
	cy_card[card_no].ctl_addr.p9050 = addr0;
J
Jiri Slaby 已提交
3895 3896 3897
	cy_card[card_no].irq = irq;
	cy_card[card_no].bus_index = 1;
	cy_card[card_no].first_line = cy_next_channel;
J
Jiri Slaby 已提交
3898
	cy_card[card_no].nports = nchan;
J
Jiri Slaby 已提交
3899 3900 3901
	retval = cy_init_card(&cy_card[card_no]);
	if (retval)
		goto err_null;
J
Jiri Slaby 已提交
3902

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

J
Jiri Slaby 已提交
3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916
	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 */
3917 3918 3919 3920 3921
		{
			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 已提交
3922 3923
			break;
		}
3924
		}
J
Jiri Slaby 已提交
3925 3926
	}

J
Jiri Slaby 已提交
3927 3928 3929 3930 3931 3932
	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
	for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
		tty_register_device(cy_serial_driver, i, &pdev->dev);
	cy_next_channel += nchan;

J
Jiri Slaby 已提交
3933
	return 0;
J
Jiri Slaby 已提交
3934 3935 3936 3937
err_null:
	cy_card[card_no].base_addr = NULL;
	free_irq(irq, &cy_card[card_no]);
err_unmap:
J
Jiri Slaby 已提交
3938
	iounmap(addr0);
J
Jiri Slaby 已提交
3939
	if (addr2)
J
Jiri Slaby 已提交
3940
		iounmap(addr2);
J
Jiri Slaby 已提交
3941 3942 3943 3944 3945 3946
err_reg:
	pci_release_regions(pdev);
err_dis:
	pci_disable_device(pdev);
err:
	return retval;
J
Jiri Slaby 已提交
3947 3948
}

3949
static void __devexit cy_pci_remove(struct pci_dev *pdev)
J
Jiri Slaby 已提交
3950
{
J
Jiri Slaby 已提交
3951
	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3952
	unsigned int i;
J
Jiri Slaby 已提交
3953

3954
	/* non-Z with old PLX */
3955
	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
J
Jiri Slaby 已提交
3956
			PLX_9050)
3957
		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
3958 3959
	else
#ifndef CONFIG_CYZ_INTR
3960
		if (!cy_is_Z(cinfo))
3961
#endif
3962 3963 3964
		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
			~0x0900);
3965

J
Jiri Slaby 已提交
3966
	iounmap(cinfo->base_addr);
3967 3968
	if (cinfo->ctl_addr.p9050)
		iounmap(cinfo->ctl_addr.p9050);
J
Jiri Slaby 已提交
3969 3970
	if (cinfo->irq
#ifndef CONFIG_CYZ_INTR
3971
		&& !cy_is_Z(cinfo)
J
Jiri Slaby 已提交
3972 3973 3974 3975 3976 3977
#endif /* CONFIG_CYZ_INTR */
		)
		free_irq(cinfo->irq, cinfo);
	pci_release_regions(pdev);

	cinfo->base_addr = NULL;
3978 3979 3980
	for (i = cinfo->first_line; i < cinfo->first_line +
			cinfo->nports; i++)
		tty_unregister_device(cy_serial_driver, i);
J
Jiri Slaby 已提交
3981 3982
	cinfo->nports = 0;
	kfree(cinfo->ports);
J
Jiri Slaby 已提交
3983 3984
}

3985 3986 3987 3988 3989 3990 3991 3992
static struct pci_driver cy_pci_driver = {
	.name = "cyclades",
	.id_table = cy_pci_dev_id,
	.probe = cy_pci_probe,
	.remove = __devexit_p(cy_pci_remove)
};
#endif

3993
static int cyclades_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
3994
{
3995
	struct cyclades_port *info;
J
Jiri Slaby 已提交
3996
	unsigned int i, j;
3997 3998
	__u32 cur_jifs = jiffies;

3999
	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
4000 4001 4002
			"IdleIn  Overruns  Ldisc\n");

	/* Output one line for each known port */
J
Jiri Slaby 已提交
4003 4004 4005 4006
	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 已提交
4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020
			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);
				}
4021
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4022
					"%10lu %8lu %9lu %6d\n", info->line,
J
Jiri Slaby 已提交
4023 4024 4025 4026 4027 4028
					(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 已提交
4029 4030
					num);
			} else
4031
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4032 4033
					"%10lu %8lu %9lu %6ld\n",
					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
4034
		}
4035 4036 4037 4038 4039 4040
	return 0;
}

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

4043 4044 4045 4046 4047 4048 4049 4050
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 已提交
4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068
/* 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 已提交
4069
static const struct tty_operations cy_ops = {
4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
	.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,
4089
	.get_icount = cy_get_icount,
4090
	.proc_fops = &cyclades_proc_fops,
L
Linus Torvalds 已提交
4091 4092
};

4093
static int __init cy_init(void)
L
Linus Torvalds 已提交
4094
{
J
Jiri Slaby 已提交
4095
	unsigned int nboards;
4096
	int retval = -ENOMEM;
4097 4098 4099

	cy_serial_driver = alloc_tty_driver(NR_PORTS);
	if (!cy_serial_driver)
4100
		goto err;
J
Jiri Slaby 已提交
4101 4102 4103

	printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
			__DATE__, __TIME__);
4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116

	/* Initialize the tty_driver structure */

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

4120 4121 4122 4123 4124
	retval = tty_register_driver(cy_serial_driver);
	if (retval) {
		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
		goto err_frtty;
	}
4125 4126 4127 4128 4129 4130 4131 4132 4133

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

4136
#ifdef CONFIG_PCI
4137
	/* look for pci boards */
4138
	retval = pci_register_driver(&cy_pci_driver);
4139 4140 4141 4142
	if (retval && !nboards) {
		tty_unregister_driver(cy_serial_driver);
		goto err_frtty;
	}
4143
#endif
4144 4145 4146 4147 4148 4149

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

4152
static void __exit cy_cleanup_module(void)
L
Linus Torvalds 已提交
4153
{
J
Jiri Slaby 已提交
4154
	struct cyclades_card *card;
J
Jiri Slaby 已提交
4155
	unsigned int i, e1;
L
Linus Torvalds 已提交
4156 4157

#ifndef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
4158
	del_timer_sync(&cyz_timerlist);
L
Linus Torvalds 已提交
4159 4160
#endif /* CONFIG_CYZ_INTR */

A
Alan Cox 已提交
4161 4162
	e1 = tty_unregister_driver(cy_serial_driver);
	if (e1)
J
Jiri Slaby 已提交
4163 4164
		printk(KERN_ERR "failed to unregister Cyclades serial "
				"driver(%d)\n", e1);
L
Linus Torvalds 已提交
4165

4166 4167 4168 4169
#ifdef CONFIG_PCI
	pci_unregister_driver(&cy_pci_driver);
#endif

4170
	for (i = 0; i < NR_CARDS; i++) {
J
Jiri Slaby 已提交
4171 4172
		card = &cy_card[i];
		if (card->base_addr) {
4173
			/* clear interrupt */
J
Jiri Slaby 已提交
4174 4175
			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
			iounmap(card->base_addr);
4176 4177
			if (card->ctl_addr.p9050)
				iounmap(card->ctl_addr.p9050);
J
Jiri Slaby 已提交
4178
			if (card->irq
L
Linus Torvalds 已提交
4179
#ifndef CONFIG_CYZ_INTR
4180
				&& !cy_is_Z(card)
L
Linus Torvalds 已提交
4181
#endif /* CONFIG_CYZ_INTR */
4182
				)
J
Jiri Slaby 已提交
4183
				free_irq(card->irq, card);
J
Jiri Slaby 已提交
4184
			for (e1 = card->first_line; e1 < card->first_line +
J
Jiri Slaby 已提交
4185
					card->nports; e1++)
4186
				tty_unregister_device(cy_serial_driver, e1);
J
Jiri Slaby 已提交
4187
			kfree(card->ports);
4188 4189
		}
	}
4190 4191

	put_tty_driver(cy_serial_driver);
L
Linus Torvalds 已提交
4192 4193 4194 4195 4196 4197
} /* cy_cleanup_module */

module_init(cy_init);
module_exit(cy_cleanup_module);

MODULE_LICENSE("GPL");
4198
MODULE_VERSION(CY_VERSION);
4199
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4200
MODULE_FIRMWARE("cyzfirm.bin");