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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#define STD_COM_FLAGS (0)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* PCI related definitions */

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

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

#ifndef CONFIG_CYZ_INTR
static void cyz_poll(unsigned long);

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

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

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

295
static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
296 297 298 299 300 301
{
	struct cyclades_card *card = port->card;

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

302
static u8 cyy_readb(struct cyclades_port *port, u32 reg)
303 304 305 306 307 308
{
	struct cyclades_card *card = port->card;

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

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
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);
}

324
static bool cyz_is_loaded(struct cyclades_card *card)
325 326 327 328 329 330 331
{
	struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	/* there is an open port for this data */
461 462
	if (ivr == CyIVRRxEx) {	/* exception */
		data = cyy_readb(info, CyRDSR);
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477

		/* 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++;
			return;
		}
478
		if (tty_buffer_request_room(port, 1)) {
479 480
			if (data & info->read_status_mask) {
				if (data & CyBREAK) {
J
Jiri Slaby 已提交
481
					tty_insert_flip_char(port,
482 483
						cyy_readb(info, CyRDSR),
						TTY_BREAK);
484
					info->icount.rx++;
J
Jiri Slaby 已提交
485 486 487 488 489 490 491 492
					if (port->flags & ASYNC_SAK) {
						struct tty_struct *tty =
							tty_port_tty_get(port);
						if (tty) {
							do_SAK(tty);
							tty_kref_put(tty);
						}
					}
493
				} else if (data & CyFRAME) {
J
Jiri Slaby 已提交
494
					tty_insert_flip_char(port,
495 496
						cyy_readb(info, CyRDSR),
						TTY_FRAME);
497 498 499 500
					info->icount.rx++;
					info->idle_stats.frame_errs++;
				} else if (data & CyPARITY) {
					/* Pieces of seven... */
J
Jiri Slaby 已提交
501
					tty_insert_flip_char(port,
502 503
						cyy_readb(info, CyRDSR),
						TTY_PARITY);
504 505 506
					info->icount.rx++;
					info->idle_stats.parity_errs++;
				} else if (data & CyOVERRUN) {
J
Jiri Slaby 已提交
507
					tty_insert_flip_char(port, 0,
508 509 510 511 512 513
							TTY_OVERRUN);
					info->icount.rx++;
					/* If the flip buffer itself is
					   overflowing, we still lose
					   the next incoming character.
					 */
J
Jiri Slaby 已提交
514
					tty_insert_flip_char(port,
515 516
						cyy_readb(info, CyRDSR),
						TTY_FRAME);
517 518
					info->icount.rx++;
					info->idle_stats.overruns++;
519 520 521 522 523
				/* These two conditions may imply */
				/* a normal read should be done. */
				/* } else if(data & CyTIMEOUT) { */
				/* } else if(data & CySPECHAR) { */
				} else {
J
Jiri Slaby 已提交
524
					tty_insert_flip_char(port, 0,
525 526
							TTY_NORMAL);
					info->icount.rx++;
527
				}
528
			} else {
J
Jiri Slaby 已提交
529
				tty_insert_flip_char(port, 0, TTY_NORMAL);
530 531 532 533 534 535 536 537 538 539
				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 */
540
		char_count = cyy_readb(info, CyRDCR);
541 542

#ifdef CY_ENABLE_MONITORING
543 544 545 546 547
		++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;
548
#endif
549
		len = tty_buffer_request_room(port, char_count);
550
		while (len--) {
551
			data = cyy_readb(info, CyRDSR);
J
Jiri Slaby 已提交
552
			tty_insert_flip_char(port, data, TTY_NORMAL);
553 554
			info->idle_stats.recv_bytes++;
			info->icount.rx++;
555
#ifdef CY_16Y_HACK
556
			udelay(10L);
557 558
#endif
		}
559
		info->idle_stats.recv_idle = jiffies;
560
	}
J
Jiri Slaby 已提交
561 562
	tty_schedule_flip(port);

563
	/* end of service */
564 565
	cyy_writeb(info, CyRIR, save_xir & 0x3f);
	cyy_writeb(info, CyCAR, save_car);
566
}
567

J
Jiri Slaby 已提交
568
static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
569 570 571
		void __iomem *base_addr)
{
	struct cyclades_port *info;
J
Jiri Slaby 已提交
572
	struct tty_struct *tty;
J
Jiri Slaby 已提交
573 574
	int char_count, index = cinfo->bus_index;
	u8 save_xir, channel, save_car, outch;
575 576 577 578

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

583
	/* determine the channel & change to that context */
J
Jiri Slaby 已提交
584 585
	save_xir = readb(base_addr + (CyTIR << index));
	channel = save_xir & CyIRChannel;
586 587 588 589
	save_car = readb(base_addr + (CyCAR << index));
	cy_writeb(base_addr + (CyCAR << index), save_xir);

	info = &cinfo->ports[channel + chip * 4];
J
Jiri Slaby 已提交
590 591
	tty = tty_port_tty_get(&info->port);
	if (tty == NULL) {
592
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
593 594
		goto end;
	}
595

596 597
	/* load the on-chip space for outbound data */
	char_count = info->xmit_fifo_size;
598

599 600
	if (info->x_char) {	/* send special char */
		outch = info->x_char;
601
		cyy_writeb(info, CyTDR, outch);
602 603 604 605
		char_count--;
		info->icount.tx++;
		info->x_char = 0;
	}
606

607 608
	if (info->breakon || info->breakoff) {
		if (info->breakon) {
609 610
			cyy_writeb(info, CyTDR, 0);
			cyy_writeb(info, CyTDR, 0x81);
611 612
			info->breakon = 0;
			char_count -= 2;
613
		}
614
		if (info->breakoff) {
615 616
			cyy_writeb(info, CyTDR, 0);
			cyy_writeb(info, CyTDR, 0x83);
617 618
			info->breakoff = 0;
			char_count -= 2;
619
		}
620
	}
621

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

672
done:
J
Jiri Slaby 已提交
673 674
	tty_wakeup(tty);
	tty_kref_put(tty);
675 676
end:
	/* end of service */
677 678
	cyy_writeb(info, CyTIR, save_xir & 0x3f);
	cyy_writeb(info, CyCAR, save_car);
679
}
680

681 682 683 684
static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
		void __iomem *base_addr)
{
	struct cyclades_port *info;
J
Jiri Slaby 已提交
685
	struct tty_struct *tty;
J
Jiri Slaby 已提交
686 687
	int index = cinfo->bus_index;
	u8 save_xir, channel, save_car, mdm_change, mdm_status;
688 689

	/* determine the channel & change to that context */
J
Jiri Slaby 已提交
690 691
	save_xir = readb(base_addr + (CyMIR << index));
	channel = save_xir & CyIRChannel;
692
	info = &cinfo->ports[channel + chip * 4];
693 694
	save_car = cyy_readb(info, CyCAR);
	cyy_writeb(info, CyCAR, save_xir);
695

696 697
	mdm_change = cyy_readb(info, CyMISR);
	mdm_status = cyy_readb(info, CyMSVR1);
698

J
Jiri Slaby 已提交
699 700
	tty = tty_port_tty_get(&info->port);
	if (!tty)
701 702 703 704 705 706 707 708 709 710 711 712 713
		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++;

714
		wake_up_interruptible(&info->port.delta_msr_wait);
715 716
	}

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

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

J
Jiri Slaby 已提交
766
	if (unlikely(cinfo == NULL)) {
L
Linus Torvalds 已提交
767
#ifdef CY_DEBUG_INTERRUPTS
A
Alan Cox 已提交
768 769
		printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
				irq);
L
Linus Torvalds 已提交
770
#endif
771 772 773 774 775 776
		return IRQ_NONE;	/* spurious interrupt */
	}

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

J
Jiri Slaby 已提交
777 778 779 780
	/* card was not initialized yet (e.g. DEBUG_SHIRQ) */
	if (unlikely(card_base_addr == NULL))
		return IRQ_HANDLED;

781 782 783 784 785 786 787 788 789 790 791
	/* 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;
792
			while ((status = readb(base_addr +
793 794 795 796 797 798 799
						(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).
			 */
800
				if (1000 < too_many++)
801
					break;
802
				spin_lock(&cinfo->card_lock);
803 804 805 806 807 808
				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);
809
				spin_unlock(&cinfo->card_lock);
810 811 812 813 814 815 816 817 818 819 820
			}
		}
	} 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 已提交
821

J
Jiri Slaby 已提交
822 823 824 825
static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
		unsigned int clear)
{
	struct cyclades_card *card = info->card;
826
	int channel = info->line - card->first_line;
J
Jiri Slaby 已提交
827
	u32 rts, dtr, msvrr, msvrd;
J
Jiri Slaby 已提交
828 829 830

	channel &= 0x03;

J
Jiri Slaby 已提交
831 832 833 834 835 836 837 838 839 840 841
	if (info->rtsdtr_inv) {
		msvrr = CyMSVR2;
		msvrd = CyMSVR1;
		rts = CyDTR;
		dtr = CyRTS;
	} else {
		msvrr = CyMSVR1;
		msvrd = CyMSVR2;
		rts = CyRTS;
		dtr = CyDTR;
	}
J
Jiri Slaby 已提交
842
	if (set & TIOCM_RTS) {
843 844
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrr, rts);
J
Jiri Slaby 已提交
845 846
	}
	if (clear & TIOCM_RTS) {
847 848
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrr, ~rts);
J
Jiri Slaby 已提交
849 850
	}
	if (set & TIOCM_DTR) {
851 852
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, msvrd, dtr);
J
Jiri Slaby 已提交
853 854 855
#ifdef CY_DEBUG_DTR
		printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
856 857
			cyy_readb(info, CyMSVR1),
			cyy_readb(info, CyMSVR2));
J
Jiri Slaby 已提交
858 859 860
#endif
	}
	if (clear & 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 dropping 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 871
#endif
	}
}

L
Linus Torvalds 已提交
872 873
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
A
Alan Cox 已提交
874
/******** Start of block of Cyclades-Z specific code *******/
L
Linus Torvalds 已提交
875 876 877
/***********************************************************/

static int
878
cyz_fetch_msg(struct cyclades_card *cinfo,
A
Alan Cox 已提交
879
		__u32 *channel, __u8 *cmd, __u32 *param)
L
Linus Torvalds 已提交
880
{
881
	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
882 883
	unsigned long loc_doorbell;

884
	loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
885 886
	if (loc_doorbell) {
		*cmd = (char)(0xff & loc_doorbell);
887 888
		*channel = readl(&board_ctrl->fwcmd_channel);
		*param = (__u32) readl(&board_ctrl->fwcmd_param);
889
		cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
890 891 892 893
		return 1;
	}
	return 0;
}				/* cyz_fetch_msg */
L
Linus Torvalds 已提交
894 895

static int
896
cyz_issue_cmd(struct cyclades_card *cinfo,
K
Klaus Kudielka 已提交
897
		__u32 channel, __u8 cmd, __u32 param)
L
Linus Torvalds 已提交
898
{
899
	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
K
Klaus Kudielka 已提交
900
	__u32 __iomem *pci_doorbell;
J
Jiri Slaby 已提交
901
	unsigned int index;
902

903
	if (!cyz_is_loaded(cinfo))
J
Jiri Slaby 已提交
904
		return -1;
A
Alan Cox 已提交
905

906
	index = 0;
907
	pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
908
	while ((readl(pci_doorbell) & 0xff) != 0) {
A
Alan Cox 已提交
909
		if (index++ == 1000)
910
			return (int)(readl(pci_doorbell) & 0xff);
911 912 913 914 915 916
		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 已提交
917
	return 0;
918
}				/* cyz_issue_cmd */
L
Linus Torvalds 已提交
919

920
static void cyz_handle_rx(struct cyclades_port *info)
L
Linus Torvalds 已提交
921
{
922
	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
923
	struct cyclades_card *cinfo = info->card;
924
	struct tty_port *port = &info->port;
J
Jiri Slaby 已提交
925
	unsigned int char_count;
926
	int len;
L
Linus Torvalds 已提交
927
#ifdef BLOCKMOVE
J
Jiri Slaby 已提交
928
	unsigned char *buf;
L
Linus Torvalds 已提交
929
#else
930
	char data;
L
Linus Torvalds 已提交
931
#endif
J
Jiri Slaby 已提交
932
	__u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
L
Linus Torvalds 已提交
933

934 935 936 937
	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);
938 939 940 941
	if (rx_put >= rx_get)
		char_count = rx_put - rx_get;
	else
		char_count = rx_put - rx_get + rx_bufsize;
L
Linus Torvalds 已提交
942

943 944 945
	if (!char_count)
		return;

L
Linus Torvalds 已提交
946
#ifdef CY_ENABLE_MONITORING
947 948 949 950 951
	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 已提交
952
#endif
953

L
Linus Torvalds 已提交
954
#ifdef BLOCKMOVE
955 956 957 958 959 960 961 962
	/* 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 */
	while (1) {
		len = tty_prepare_flip_string(port, &buf,
				char_count);
		if (!len)
			break;
J
Jiri Slaby 已提交
963

964 965
		len = min_t(unsigned int, min(len, char_count),
				rx_bufsize - new_rx_get);
J
Jiri Slaby 已提交
966

967 968
		memcpy_fromio(buf, cinfo->base_addr +
				rx_bufaddr + new_rx_get, len);
J
Jiri Slaby 已提交
969

970 971 972 973 974 975
		new_rx_get = (new_rx_get + len) &
				(rx_bufsize - 1);
		char_count -= len;
		info->icount.rx += len;
		info->idle_stats.recv_bytes += len;
	}
L
Linus Torvalds 已提交
976
#else
977 978 979 980 981 982 983 984 985 986
	len = tty_buffer_request_room(port, char_count);
	while (len--) {
		data = readb(cinfo->base_addr + rx_bufaddr +
				new_rx_get);
		new_rx_get = (new_rx_get + 1) &
					(rx_bufsize - 1);
		tty_insert_flip_char(port, data, TTY_NORMAL);
		info->idle_stats.recv_bytes++;
		info->icount.rx++;
	}
L
Linus Torvalds 已提交
987 988
#endif
#ifdef CONFIG_CYZ_INTR
989 990 991 992 993 994 995 996 997 998 999 1000
	/* Recalculate the number of chars in the RX buffer and issue
	   a cmd in case it's higher than the RX high water mark */
	rx_put = readl(&buf_ctrl->rx_put);
	if (rx_put >= rx_get)
		char_count = rx_put - rx_get;
	else
		char_count = rx_put - rx_get + rx_bufsize;
	if (char_count >= readl(&buf_ctrl->rx_threshold) &&
			!timer_pending(&cyz_rx_full_timer[
					info->line]))
		mod_timer(&cyz_rx_full_timer[info->line],
				jiffies + 1);
L
Linus Torvalds 已提交
1001
#endif
1002 1003 1004 1005 1006
	info->idle_stats.recv_idle = jiffies;
	tty_schedule_flip(&info->port);

	/* Update rx_get */
	cy_writel(&buf_ctrl->rx_get, new_rx_get);
L
Linus Torvalds 已提交
1007 1008
}

1009
static void cyz_handle_tx(struct cyclades_port *info)
L
Linus Torvalds 已提交
1010
{
1011
	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1012
	struct cyclades_card *cinfo = info->card;
1013
	struct tty_struct *tty;
J
Jiri Slaby 已提交
1014 1015
	u8 data;
	unsigned int char_count;
L
Linus Torvalds 已提交
1016
#ifdef BLOCKMOVE
1017
	int small_count;
L
Linus Torvalds 已提交
1018
#endif
J
Jiri Slaby 已提交
1019
	__u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
L
Linus Torvalds 已提交
1020

1021 1022
	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
		return;
L
Linus Torvalds 已提交
1023

1024 1025 1026 1027
	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);
1028 1029 1030 1031
	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 已提交
1032

1033 1034 1035 1036 1037 1038
	if (!char_count)
		return;
		
	tty = tty_port_tty_get(&info->port);
	if (tty == NULL)
		goto ztxdone;
L
Linus Torvalds 已提交
1039

1040 1041
	if (info->x_char) {	/* send special char */
		data = info->x_char;
L
Linus Torvalds 已提交
1042

1043 1044 1045 1046 1047 1048
		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 已提交
1049
#ifdef BLOCKMOVE
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	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),
				&info->port.xmit_buf[info->xmit_tail],
				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 已提交
1067
#else
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
	while (info->xmit_cnt && char_count) {
		data = info->port.xmit_buf[info->xmit_tail];
		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 已提交
1079
#endif
1080 1081
	tty_wakeup(tty);
	tty_kref_put(tty);
1082
ztxdone:
1083 1084
	/* Update tx_put */
	cy_writel(&buf_ctrl->tx_put, tx_put);
L
Linus Torvalds 已提交
1085 1086
}

1087
static void cyz_handle_cmd(struct cyclades_card *cinfo)
L
Linus Torvalds 已提交
1088
{
1089
	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
1090
	struct cyclades_port *info;
J
Jiri Slaby 已提交
1091
	__u32 channel, param, fw_ver;
K
Klaus Kudielka 已提交
1092
	__u8 cmd;
1093 1094 1095
	int special_count;
	int delta_count;

1096
	fw_ver = readl(&board_ctrl->fw_version);
1097 1098 1099 1100

	while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
		special_count = 0;
		delta_count = 0;
J
Jiri Slaby 已提交
1101
		info = &cinfo->ports[channel];
J
Jiri Slaby 已提交
1102

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

#ifdef CONFIG_CYZ_INTR
1184
static irqreturn_t cyz_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
1185
{
J
Jiri Slaby 已提交
1186
	struct cyclades_card *cinfo = dev_id;
L
Linus Torvalds 已提交
1187

1188
	if (unlikely(!cyz_is_loaded(cinfo))) {
L
Linus Torvalds 已提交
1189
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1190 1191
		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
				"(IRQ%d).\n", irq);
L
Linus Torvalds 已提交
1192
#endif
1193 1194
		return IRQ_NONE;
	}
L
Linus Torvalds 已提交
1195

1196 1197
	/* Handle the interrupts */
	cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1198

1199 1200
	return IRQ_HANDLED;
}				/* cyz_interrupt */
L
Linus Torvalds 已提交
1201

1202
static void cyz_rx_restart(unsigned long arg)
L
Linus Torvalds 已提交
1203
{
1204
	struct cyclades_port *info = (struct cyclades_port *)arg;
1205
	struct cyclades_card *card = info->card;
1206
	int retval;
1207
	__u32 channel = info->line - card->first_line;
1208 1209
	unsigned long flags;

1210
	spin_lock_irqsave(&card->card_lock, flags);
1211
	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
1212
	if (retval != 0) {
J
Jiri Slaby 已提交
1213
		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
1214 1215
			info->line, retval);
	}
1216
	spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
1217 1218
}

1219
#else				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1220

1221
static void cyz_poll(unsigned long arg)
L
Linus Torvalds 已提交
1222
{
1223 1224
	struct cyclades_card *cinfo;
	struct cyclades_port *info;
J
Jiri Slaby 已提交
1225
	unsigned long expires = jiffies + HZ;
J
Jiri Slaby 已提交
1226
	unsigned int port, card;
L
Linus Torvalds 已提交
1227

1228 1229 1230
	for (card = 0; card < NR_CARDS; card++) {
		cinfo = &cy_card[card];

1231
		if (!cy_is_Z(cinfo))
1232
			continue;
1233
		if (!cyz_is_loaded(cinfo))
1234 1235
			continue;

L
Linus Torvalds 已提交
1236
	/* Skip first polling cycle to avoid racing conditions with the FW */
1237 1238 1239 1240
		if (!cinfo->intr_enabled) {
			cinfo->intr_enabled = 1;
			continue;
		}
L
Linus Torvalds 已提交
1241

1242
		cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1243

1244
		for (port = 0; port < cinfo->nports; port++) {
J
Jiri Slaby 已提交
1245
			info = &cinfo->ports[port];
J
Jiri Slaby 已提交
1246

1247
			if (!info->throttle)
1248 1249
				cyz_handle_rx(info);
			cyz_handle_tx(info);
1250 1251
		}
		/* poll every 'cyz_polling_cycle' period */
J
Jiri Slaby 已提交
1252
		expires = jiffies + cyz_polling_cycle;
L
Linus Torvalds 已提交
1253
	}
J
Jiri Slaby 已提交
1254
	mod_timer(&cyz_timerlist, expires);
1255
}				/* cyz_poll */
L
Linus Torvalds 已提交
1256

1257
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1258 1259 1260 1261 1262 1263 1264

/********** 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 已提交
1265
static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1266
{
1267
	struct cyclades_card *card;
1268 1269
	unsigned long flags;
	int retval = 0;
J
Jiri Slaby 已提交
1270
	int channel;
1271
	unsigned long page;
L
Linus Torvalds 已提交
1272

1273
	card = info->card;
1274
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1275

1276 1277 1278
	page = get_zeroed_page(GFP_KERNEL);
	if (!page)
		return -ENOMEM;
L
Linus Torvalds 已提交
1279

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

J
Jiri Slaby 已提交
1282
	if (info->port.flags & ASYNC_INITIALIZED)
1283
		goto errout;
L
Linus Torvalds 已提交
1284

1285
	if (!info->type) {
J
Jiri Slaby 已提交
1286
		set_bit(TTY_IO_ERROR, &tty->flags);
1287 1288
		goto errout;
	}
L
Linus Torvalds 已提交
1289

A
Alan Cox 已提交
1290
	if (info->port.xmit_buf)
1291 1292
		free_page(page);
	else
A
Alan Cox 已提交
1293
		info->port.xmit_buf = (unsigned char *)page;
L
Linus Torvalds 已提交
1294

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

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

1299
	if (!cy_is_Z(card)) {
1300
		channel &= 0x03;
L
Linus Torvalds 已提交
1301

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

1304
		cyy_writeb(info, CyCAR, channel);
L
Linus Torvalds 已提交
1305

1306
		cyy_writeb(info, CyRTPR,
1307 1308
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */
L
Linus Torvalds 已提交
1309

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

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

1314
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
1315
	} else {
1316
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
L
Linus Torvalds 已提交
1317

1318
		if (!cyz_is_loaded(card))
1319
			return -ENODEV;
L
Linus Torvalds 已提交
1320 1321

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1322
		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1323
			"base_addr %p\n", card, channel, card->base_addr);
L
Linus Torvalds 已提交
1324
#endif
1325
		spin_lock_irqsave(&card->card_lock, flags);
L
Linus Torvalds 已提交
1326

1327
		cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
L
Linus Torvalds 已提交
1328 1329
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
1330
		cy_writel(&ch_ctrl->intr_enable,
1331 1332
			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
L
Linus Torvalds 已提交
1333
#else
1334
		cy_writel(&ch_ctrl->intr_enable,
1335 1336
			  C_IN_IOCTLW | C_IN_MDCD);
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1337 1338
#else
#ifdef CONFIG_CYZ_INTR
1339
		cy_writel(&ch_ctrl->intr_enable,
1340 1341
			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
			  C_IN_RXNNDT | C_IN_MDCD);
L
Linus Torvalds 已提交
1342
#else
1343
		cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
1344 1345 1346
#endif				/* CONFIG_CYZ_INTR */
#endif				/* Z_WAKE */

1347
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
1348
		if (retval != 0) {
J
Jiri Slaby 已提交
1349 1350
			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
				"%x\n", info->line, retval);
1351
		}
L
Linus Torvalds 已提交
1352

1353
		/* Flush RX buffers before raising DTR and RTS */
1354
		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
1355
		if (retval != 0) {
J
Jiri Slaby 已提交
1356 1357
			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
				"%x\n", info->line, retval);
1358
		}
L
Linus Torvalds 已提交
1359

1360 1361
		/* set timeout !!! */
		/* set RTS and DTR !!! */
J
Jiri Slaby 已提交
1362
		tty_port_raise_dtr_rts(&info->port);
L
Linus Torvalds 已提交
1363

1364
		/* enable send, recv, modem !!! */
J
Jiri Slaby 已提交
1365
	}
1366

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

J
Jiri Slaby 已提交
1369 1370 1371 1372 1373 1374 1375 1376 1377
	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 已提交
1378 1379

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1380
	printk(KERN_DEBUG "cyc startup done\n");
L
Linus Torvalds 已提交
1381 1382 1383 1384
#endif
	return 0;

errout:
1385
	spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1386
	free_page(page);
L
Linus Torvalds 已提交
1387
	return retval;
1388
}				/* startup */
L
Linus Torvalds 已提交
1389

1390
static void start_xmit(struct cyclades_port *info)
L
Linus Torvalds 已提交
1391
{
1392
	struct cyclades_card *card = info->card;
1393
	unsigned long flags;
1394
	int channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1395

1396
	if (!cy_is_Z(card)) {
1397
		spin_lock_irqsave(&card->card_lock, flags);
1398 1399
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
1400
		spin_unlock_irqrestore(&card->card_lock, flags);
1401
	} else {
L
Linus Torvalds 已提交
1402
#ifdef CONFIG_CYZ_INTR
1403
		int retval;
L
Linus Torvalds 已提交
1404

1405
		spin_lock_irqsave(&card->card_lock, flags);
1406
		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
1407
		if (retval != 0) {
J
Jiri Slaby 已提交
1408 1409
			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
				"%x\n", info->line, retval);
1410
		}
1411
		spin_unlock_irqrestore(&card->card_lock, flags);
1412 1413 1414 1415 1416
#else				/* CONFIG_CYZ_INTR */
		/* Don't have to do anything at this time */
#endif				/* CONFIG_CYZ_INTR */
	}
}				/* start_xmit */
L
Linus Torvalds 已提交
1417 1418 1419 1420 1421

/*
 * 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 已提交
1422
static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1423
{
1424
	struct cyclades_card *card;
1425 1426
	unsigned long flags;

A
Alan Cox 已提交
1427
	if (!(info->port.flags & ASYNC_INITIALIZED))
1428 1429 1430
		return;

	card = info->card;
1431
	if (!cy_is_Z(card)) {
1432
		spin_lock_irqsave(&card->card_lock, flags);
1433 1434

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

A
Alan Cox 已提交
1437
		if (info->port.xmit_buf) {
1438
			unsigned char *temp;
A
Alan Cox 已提交
1439 1440
			temp = info->port.xmit_buf;
			info->port.xmit_buf = NULL;
1441 1442
			free_page((unsigned long)temp);
		}
1443
		if (tty->termios.c_cflag & HUPCL)
J
Jiri Slaby 已提交
1444 1445
			cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);

1446
		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
1447 1448 1449
		/* it may be appropriate to clear _XMIT at
		   some later date (after testing)!!! */

J
Jiri Slaby 已提交
1450
		set_bit(TTY_IO_ERROR, &tty->flags);
A
Alan Cox 已提交
1451
		info->port.flags &= ~ASYNC_INITIALIZED;
1452
		spin_unlock_irqrestore(&card->card_lock, flags);
1453
	} else {
L
Linus Torvalds 已提交
1454
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1455
		int channel = info->line - card->first_line;
J
Jiri Slaby 已提交
1456
		printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
1457
			"base_addr %p\n", card, channel, card->base_addr);
L
Linus Torvalds 已提交
1458 1459
#endif

1460
		if (!cyz_is_loaded(card))
1461
			return;
L
Linus Torvalds 已提交
1462

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

A
Alan Cox 已提交
1465
		if (info->port.xmit_buf) {
1466
			unsigned char *temp;
A
Alan Cox 已提交
1467 1468
			temp = info->port.xmit_buf;
			info->port.xmit_buf = NULL;
1469
			free_page((unsigned long)temp);
L
Linus Torvalds 已提交
1470
		}
1471

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

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

1478
		spin_unlock_irqrestore(&card->card_lock, flags);
1479
	}
L
Linus Torvalds 已提交
1480 1481

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1482
	printk(KERN_DEBUG "cyc shutdown done\n");
L
Linus Torvalds 已提交
1483
#endif
1484
}				/* shutdown */
L
Linus Torvalds 已提交
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495

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

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

J
Jiri Slaby 已提交
1502 1503 1504 1505 1506 1507 1508
	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 已提交
1509
	if (info->line < 0)
1510
		return -ENODEV;
L
Linus Torvalds 已提交
1511

1512 1513 1514 1515
	/* If the card's firmware hasn't been loaded,
	   treat it as absent from the system.  This
	   will make the user pay attention.
	 */
1516
	if (cy_is_Z(info->card)) {
1517
		struct cyclades_card *cinfo = info->card;
1518 1519
		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;

1520 1521
		if (!cyz_is_loaded(cinfo)) {
			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
J
Jiri Slaby 已提交
1522 1523
					readl(&firm_id->signature) ==
					ZFIRM_HLT) {
J
Jiri Slaby 已提交
1524 1525 1526 1527
				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
					"need an external power supply for "
					"this number of ports.\nFirmware "
					"halted.\n");
1528
			} else {
J
Jiri Slaby 已提交
1529 1530
				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
					"yet loaded\n");
1531 1532 1533 1534 1535 1536 1537 1538 1539
			}
			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) {
1540
				u16 intr;
1541 1542

				/* Enable interrupts on the PLX chip */
1543 1544 1545 1546
				intr = readw(&cinfo->ctl_addr.p9060->
						intr_ctrl_stat) | 0x0900;
				cy_writew(&cinfo->ctl_addr.p9060->
						intr_ctrl_stat, intr);
1547 1548 1549 1550
				/* Enable interrupts on the FW */
				retval = cyz_issue_cmd(cinfo, 0,
						C_CM_IRQ_ENBL, 0L);
				if (retval != 0) {
J
Jiri Slaby 已提交
1551 1552
					printk(KERN_ERR "cyc:IRQ enable retval "
						"was %x\n", retval);
1553 1554 1555
				}
				cinfo->intr_enabled = 1;
			}
L
Linus Torvalds 已提交
1556
		}
1557 1558 1559 1560
#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 已提交
1561 1562
	}
#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
1563
	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
L
Linus Torvalds 已提交
1564
#endif
1565
	tty->driver_data = info;
A
Alan Cox 已提交
1566
	if (serial_paranoia_check(info, tty->name, "cy_open"))
1567
		return -ENODEV;
A
Alan Cox 已提交
1568

L
Linus Torvalds 已提交
1569
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1570
	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
A
Alan Cox 已提交
1571
			info->port.count);
L
Linus Torvalds 已提交
1572
#endif
A
Alan Cox 已提交
1573
	info->port.count++;
L
Linus Torvalds 已提交
1574
#ifdef CY_DEBUG_COUNT
J
Jiri Slaby 已提交
1575
	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
A
Alan Cox 已提交
1576
		current->pid, info->port.count);
L
Linus Torvalds 已提交
1577 1578
#endif

1579 1580 1581
	/*
	 * Start up serial port
	 */
J
Jiri Slaby 已提交
1582
	retval = cy_startup(info, tty);
A
Alan Cox 已提交
1583
	if (retval)
1584
		return retval;
L
Linus Torvalds 已提交
1585

J
Jiri Slaby 已提交
1586
	retval = tty_port_block_til_ready(&info->port, tty, filp);
1587
	if (retval) {
L
Linus Torvalds 已提交
1588
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1589 1590
		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
			"with %d\n", retval);
L
Linus Torvalds 已提交
1591
#endif
1592 1593
		return retval;
	}
L
Linus Torvalds 已提交
1594

1595
	info->throttle = 0;
J
Jiri Slaby 已提交
1596
	tty_port_tty_set(&info->port, tty);
L
Linus Torvalds 已提交
1597

1598
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1599
	printk(KERN_DEBUG "cyc:cy_open done\n");
1600 1601 1602
#endif
	return 0;
}				/* cy_open */
L
Linus Torvalds 已提交
1603 1604 1605 1606

/*
 * cy_wait_until_sent() --- wait until the transmitter is empty
 */
1607
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
L
Linus Torvalds 已提交
1608
{
1609
	struct cyclades_card *card;
1610
	struct cyclades_port *info = tty->driver_data;
1611 1612 1613 1614 1615 1616 1617 1618
	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 已提交
1619

1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
	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;
1648

1649
	card = info->card;
1650
	if (!cy_is_Z(card)) {
1651
		while (cyy_readb(info, CySRER) & CyTxRdy) {
1652 1653 1654 1655 1656 1657
			if (msleep_interruptible(jiffies_to_msecs(char_time)))
				break;
			if (timeout && time_after(jiffies, orig_jiffies +
					timeout))
				break;
		}
L
Linus Torvalds 已提交
1658
	}
1659 1660
	/* Run one more char cycle */
	msleep_interruptible(jiffies_to_msecs(char_time * 5));
L
Linus Torvalds 已提交
1661 1662
}

1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
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);

1684
	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
					   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 */


1698
static void cy_do_close(struct tty_port *port)
L
Linus Torvalds 已提交
1699
{
1700 1701
	struct cyclades_port *info = container_of(port, struct cyclades_port,
								port);
1702
	struct cyclades_card *card;
1703
	unsigned long flags;
1704
	int channel;
L
Linus Torvalds 已提交
1705

1706
	card = info->card;
1707
	channel = info->line - card->first_line;
1708
	spin_lock_irqsave(&card->card_lock, flags);
1709

1710
	if (!cy_is_Z(card)) {
1711
		/* Stop accepting input */
1712 1713
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
A
Alan Cox 已提交
1714
		if (info->port.flags & ASYNC_INITIALIZED) {
A
Alan Cox 已提交
1715 1716
			/* Waiting for on-board buffers to be empty before
			   closing the port */
1717
			spin_unlock_irqrestore(&card->card_lock, flags);
1718
			cy_wait_until_sent(port->tty, info->timeout);
1719
			spin_lock_irqsave(&card->card_lock, flags);
1720 1721 1722
		}
	} else {
#ifdef Z_WAKE
A
Alan Cox 已提交
1723 1724
		/* Waiting for on-board buffers to be empty before closing
		   the port */
1725
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
1726 1727
		int retval;

1728
		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
1729
			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
1730
			if (retval != 0) {
J
Jiri Slaby 已提交
1731 1732
				printk(KERN_DEBUG "cyc:cy_close retval on "
					"ttyC%d was %x\n", info->line, retval);
1733
			}
1734
			spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1735
			wait_for_completion_interruptible(&info->shutdown_wait);
1736
			spin_lock_irqsave(&card->card_lock, flags);
1737
		}
L
Linus Torvalds 已提交
1738
#endif
1739
	}
1740
	spin_unlock_irqrestore(&card->card_lock, flags);
1741 1742
	cy_shutdown(info, port->tty);
}
L
Linus Torvalds 已提交
1743

1744 1745 1746 1747 1748 1749 1750 1751 1752
/*
 * 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);
1753
}				/* cy_close */
L
Linus Torvalds 已提交
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767

/* 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.
 *
 */
1768
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
L
Linus Torvalds 已提交
1769
{
1770
	struct cyclades_port *info = tty->driver_data;
1771 1772
	unsigned long flags;
	int c, ret = 0;
L
Linus Torvalds 已提交
1773 1774

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

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

A
Alan Cox 已提交
1781
	if (!info->port.xmit_buf)
1782
		return 0;
L
Linus Torvalds 已提交
1783

1784
	spin_lock_irqsave(&info->card->card_lock, flags);
1785
	while (1) {
1786 1787
		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
1788 1789 1790 1791

		if (c <= 0)
			break;

A
Alan Cox 已提交
1792
		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
1793 1794 1795 1796 1797 1798 1799
		info->xmit_head = (info->xmit_head + c) &
			(SERIAL_XMIT_SIZE - 1);
		info->xmit_cnt += c;
		buf += c;
		count -= c;
		ret += c;
	}
1800
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1801 1802 1803 1804

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

A
Alan Cox 已提交
1805
	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1806
		start_xmit(info);
A
Alan Cox 已提交
1807

1808 1809
	return ret;
}				/* cy_write */
L
Linus Torvalds 已提交
1810 1811 1812 1813 1814 1815 1816 1817

/*
 * 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.
 */
1818
static int cy_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
1819
{
1820
	struct cyclades_port *info = tty->driver_data;
1821
	unsigned long flags;
L
Linus Torvalds 已提交
1822 1823

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

1827
	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1828
		return 0;
L
Linus Torvalds 已提交
1829

A
Alan Cox 已提交
1830
	if (!info->port.xmit_buf)
1831
		return 0;
L
Linus Torvalds 已提交
1832

1833
	spin_lock_irqsave(&info->card->card_lock, flags);
J
Jiri Slaby 已提交
1834
	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
1835
		spin_unlock_irqrestore(&info->card->card_lock, flags);
1836
		return 0;
1837
	}
L
Linus Torvalds 已提交
1838

A
Alan Cox 已提交
1839
	info->port.xmit_buf[info->xmit_head++] = ch;
1840 1841
	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
	info->xmit_cnt++;
L
Linus Torvalds 已提交
1842 1843
	info->idle_stats.xmit_bytes++;
	info->idle_stats.xmit_idle = jiffies;
1844
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1845
	return 1;
1846
}				/* cy_put_char */
L
Linus Torvalds 已提交
1847 1848 1849

/*
 * This routine is called by the kernel after it has written a
A
Alan Cox 已提交
1850
 * series of characters to the tty device using put_char().
L
Linus Torvalds 已提交
1851
 */
1852
static void cy_flush_chars(struct tty_struct *tty)
L
Linus Torvalds 已提交
1853
{
1854
	struct cyclades_port *info = tty->driver_data;
1855

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

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

1863
	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
A
Alan Cox 已提交
1864
			!info->port.xmit_buf)
1865
		return;
L
Linus Torvalds 已提交
1866

1867 1868
	start_xmit(info);
}				/* cy_flush_chars */
L
Linus Torvalds 已提交
1869 1870 1871 1872 1873 1874 1875

/*
 * 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.
 */
1876
static int cy_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
1877
{
1878
	struct cyclades_port *info = tty->driver_data;
1879 1880
	int ret;

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

1885 1886 1887 1888 1889 1890 1891
	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 已提交
1892

1893
static int cy_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1894
{
1895
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
1896

1897 1898 1899
	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
		return 0;

L
Linus Torvalds 已提交
1900
#ifdef Z_EXT_CHARS_IN_BUFFER
1901
	if (!cy_is_Z(info->card)) {
1902
#endif				/* Z_EXT_CHARS_IN_BUFFER */
L
Linus Torvalds 已提交
1903
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1904 1905
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt);
L
Linus Torvalds 已提交
1906
#endif
1907
		return info->xmit_cnt;
L
Linus Torvalds 已提交
1908
#ifdef Z_EXT_CHARS_IN_BUFFER
1909
	} else {
1910
		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1911
		int char_count;
J
Jiri Slaby 已提交
1912
		__u32 tx_put, tx_get, tx_bufsize;
1913

1914 1915 1916
		tx_get = readl(&buf_ctrl->tx_get);
		tx_put = readl(&buf_ctrl->tx_put);
		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1917 1918 1919 1920
		if (tx_put >= tx_get)
			char_count = tx_put - tx_get;
		else
			char_count = tx_put - tx_get + tx_bufsize;
L
Linus Torvalds 已提交
1921
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1922 1923
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt + char_count);
L
Linus Torvalds 已提交
1924
#endif
J
Jiri Slaby 已提交
1925
		return info->xmit_cnt + char_count;
1926 1927 1928
	}
#endif				/* Z_EXT_CHARS_IN_BUFFER */
}				/* cy_chars_in_buffer */
L
Linus Torvalds 已提交
1929 1930 1931 1932 1933 1934 1935

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

K
Klaus Kudielka 已提交
1936
static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
L
Linus Torvalds 已提交
1937
{
1938
	int co, co_val, bpr;
K
Klaus Kudielka 已提交
1939
	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
1940
			25000000);
L
Linus Torvalds 已提交
1941

1942 1943 1944 1945
	if (baud == 0) {
		info->tbpr = info->tco = info->rbpr = info->rco = 0;
		return;
	}
L
Linus Torvalds 已提交
1946

1947 1948 1949 1950 1951
	/* 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 已提交
1952

1953 1954 1955
	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
	if (bpr > 255)
		bpr = 255;
L
Linus Torvalds 已提交
1956

1957 1958
	info->tbpr = info->rbpr = bpr;
	info->tco = info->rco = co;
L
Linus Torvalds 已提交
1959 1960 1961 1962 1963 1964
}

/*
 * This routine finds or computes the various line characteristics.
 * It used to be called config_setup
 */
J
Jiri Slaby 已提交
1965
static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1966
{
1967
	struct cyclades_card *card;
1968
	unsigned long flags;
1969
	int channel;
1970 1971 1972 1973
	unsigned cflag, iflag;
	int baud, baud_rate = 0;
	int i;

A
Alan Cox 已提交
1974
	if (info->line == -1)
1975
		return;
A
Alan Cox 已提交
1976

1977 1978
	cflag = tty->termios.c_cflag;
	iflag = tty->termios.c_iflag;
L
Linus Torvalds 已提交
1979

1980 1981 1982
	/*
	 * Set up the tty->alt_speed kludge
	 */
J
Jiri Slaby 已提交
1983 1984 1985 1986 1987 1988 1989 1990
	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;
1991 1992

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

1995
	if (!cy_is_Z(card)) {
1996 1997
		u32 cflags;

1998
		/* baud rate */
J
Jiri Slaby 已提交
1999
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2000
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
				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 已提交
2011
			if (baud == baud_table[i])
2012 2013
				break;
		}
A
Alan Cox 已提交
2014
		if (i == 20)
2015 2016
			i = 19;	/* CD1400_MAX_SPEED */

A
Alan Cox 已提交
2017
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
				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 已提交
2038
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
				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 已提交
2074
		if (cflag & CSTOPB)
2075
			info->cor1 |= Cy_2_STOP;
A
Alan Cox 已提交
2076

2077
		if (cflag & PARENB) {
A
Alan Cox 已提交
2078
			if (cflag & PARODD)
2079
				info->cor1 |= CyPARITY_O;
A
Alan Cox 已提交
2080
			else
2081
				info->cor1 |= CyPARITY_E;
A
Alan Cox 已提交
2082
		} else
2083 2084 2085 2086
			info->cor1 |= CyPARITY_NONE;

		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
A
Alan Cox 已提交
2087
			info->port.flags |= ASYNC_CTS_FLOW;
2088 2089
			info->cor2 |= CyCtsAE;
		} else {
A
Alan Cox 已提交
2090
			info->port.flags &= ~ASYNC_CTS_FLOW;
2091 2092 2093
			info->cor2 &= ~CyCtsAE;
		}
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2094
			info->port.flags &= ~ASYNC_CHECK_CD;
2095
		else
A
Alan Cox 已提交
2096
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107

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

2108
		channel &= 0x03;
L
Linus Torvalds 已提交
2109

2110
		spin_lock_irqsave(&card->card_lock, flags);
2111
		cyy_writeb(info, CyCAR, channel);
2112 2113 2114

		/* tx and rx baud rate */

2115 2116 2117 2118
		cyy_writeb(info, CyTCOR, info->tco);
		cyy_writeb(info, CyTBPR, info->tbpr);
		cyy_writeb(info, CyRCOR, info->rco);
		cyy_writeb(info, CyRBPR, info->rbpr);
2119 2120 2121

		/* set line characteristics  according configuration */

2122 2123 2124 2125 2126 2127 2128
		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);
2129

2130 2131
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
				CyCOR3ch);
2132

A
Alan Cox 已提交
2133
		/* !!! Is this needed? */
2134 2135
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, CyRTPR,
2136 2137 2138
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */

2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150
		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);
2151

J
Jiri Slaby 已提交
2152 2153 2154 2155
		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 已提交
2156

J
Jiri Slaby 已提交
2157
		clear_bit(TTY_IO_ERROR, &tty->flags);
2158
		spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
2159 2160

	} else {
2161
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
K
Klaus Kudielka 已提交
2162
		__u32 sw_flow;
2163
		int retval;
L
Linus Torvalds 已提交
2164

2165
		if (!cyz_is_loaded(card))
2166
			return;
L
Linus Torvalds 已提交
2167

2168
		/* baud rate */
J
Jiri Slaby 已提交
2169
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2170
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184
				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 已提交
2185
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195
				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 已提交
2196

2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
		/* 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,
2214
				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
2215 2216
		} else {
			cy_writel(&ch_ctrl->comm_data_l,
2217
				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
2218 2219
		}
		if (cflag & PARENB) {
A
Alan Cox 已提交
2220
			if (cflag & PARODD)
2221
				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
A
Alan Cox 已提交
2222
			else
2223
				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
A
Alan Cox 已提交
2224
		} else
2225
			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
L
Linus Torvalds 已提交
2226

2227 2228 2229
		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
			cy_writel(&ch_ctrl->hw_flow,
2230
				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
2231
		} else {
2232 2233
			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
					~(C_RS_CTS | C_RS_RTS));
2234 2235 2236
		}
		/* As the HW flow control is done in firmware, the driver
		   doesn't need to care about it */
A
Alan Cox 已提交
2237
		info->port.flags &= ~ASYNC_CTS_FLOW;
2238 2239 2240 2241 2242 2243 2244 2245 2246 2247

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

2248
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
2249
		if (retval != 0) {
J
Jiri Slaby 已提交
2250 2251
			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
				"was %x\n", info->line, retval);
2252 2253 2254
		}

		/* CD sensitivity */
A
Alan Cox 已提交
2255
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2256
			info->port.flags &= ~ASYNC_CHECK_CD;
A
Alan Cox 已提交
2257
		else
A
Alan Cox 已提交
2258
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2259

2260 2261
		if (baud == 0) {	/* baud rate is zero, turn off line */
			cy_writel(&ch_ctrl->rs_control,
2262
				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
L
Linus Torvalds 已提交
2263
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2264
			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
L
Linus Torvalds 已提交
2265
#endif
2266 2267
		} else {
			cy_writel(&ch_ctrl->rs_control,
2268
				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
L
Linus Torvalds 已提交
2269
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2270
			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
L
Linus Torvalds 已提交
2271
#endif
2272
		}
L
Linus Torvalds 已提交
2273

A
Alan Cox 已提交
2274
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
2275
		if (retval != 0) {
J
Jiri Slaby 已提交
2276 2277
			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
				"was %x\n", info->line, retval);
2278
		}
L
Linus Torvalds 已提交
2279

J
Jiri Slaby 已提交
2280
		clear_bit(TTY_IO_ERROR, &tty->flags);
L
Linus Torvalds 已提交
2281
	}
2282
}				/* set_line_char */
L
Linus Torvalds 已提交
2283

J
Jiri Slaby 已提交
2284
static int cy_get_serial_info(struct cyclades_port *info,
A
Alan Cox 已提交
2285
		struct serial_struct __user *retinfo)
L
Linus Torvalds 已提交
2286
{
2287
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300
	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,		/*!!! */
	};
2301
	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
J
Jiri Slaby 已提交
2302
}
L
Linus Torvalds 已提交
2303 2304

static int
J
Jiri Slaby 已提交
2305
cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
A
Alan Cox 已提交
2306
		struct serial_struct __user *new_info)
L
Linus Torvalds 已提交
2307
{
2308
	struct serial_struct new_serial;
A
Alan Cox 已提交
2309
	int ret;
2310 2311 2312 2313

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

A
Alan Cox 已提交
2314
	mutex_lock(&info->port.mutex);
2315
	if (!capable(CAP_SYS_ADMIN)) {
A
Alan Cox 已提交
2316
		if (new_serial.close_delay != info->port.close_delay ||
2317 2318 2319
				new_serial.baud_base != info->baud ||
				(new_serial.flags & ASYNC_FLAGS &
					~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
2320
				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
A
Alan Cox 已提交
2321 2322
		{
			mutex_unlock(&info->port.mutex);
2323
			return -EPERM;
A
Alan Cox 已提交
2324
		}
A
Alan Cox 已提交
2325
		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
				(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 已提交
2339
	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
2340
			(new_serial.flags & ASYNC_FLAGS);
A
Alan Cox 已提交
2341 2342
	info->port.close_delay = new_serial.close_delay * HZ / 100;
	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
L
Linus Torvalds 已提交
2343 2344

check_and_exit:
A
Alan Cox 已提交
2345
	if (info->port.flags & ASYNC_INITIALIZED) {
J
Jiri Slaby 已提交
2346
		cy_set_line_char(info, tty);
A
Alan Cox 已提交
2347
		ret = 0;
2348
	} else {
A
Alan Cox 已提交
2349
		ret = cy_startup(info, tty);
2350
	}
A
Alan Cox 已提交
2351 2352
	mutex_unlock(&info->port.mutex);
	return ret;
2353
}				/* set_serial_info */
L
Linus Torvalds 已提交
2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364

/*
 * 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 已提交
2365
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
L
Linus Torvalds 已提交
2366
{
2367
	struct cyclades_card *card = info->card;
2368 2369
	unsigned int result;
	unsigned long flags;
2370
	u8 status;
L
Linus Torvalds 已提交
2371

2372
	if (!cy_is_Z(card)) {
2373
		spin_lock_irqsave(&card->card_lock, flags);
2374
		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
2375
		spin_unlock_irqrestore(&card->card_lock, flags);
2376 2377 2378 2379 2380
		result = (status ? 0 : TIOCSER_TEMT);
	} else {
		/* Not supported yet */
		return -EINVAL;
	}
2381
	return put_user(result, value);
L
Linus Torvalds 已提交
2382 2383
}

2384
static int cy_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
2385
{
2386
	struct cyclades_port *info = tty->driver_data;
2387
	struct cyclades_card *card;
2388
	int result;
2389

2390
	if (serial_paranoia_check(info, tty->name, __func__))
2391
		return -ENODEV;
L
Linus Torvalds 已提交
2392

2393
	card = info->card;
J
Jiri Slaby 已提交
2394

2395
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2396
		unsigned long flags;
2397 2398
		int channel = info->line - card->first_line;
		u8 status;
L
Linus Torvalds 已提交
2399

2400
		spin_lock_irqsave(&card->card_lock, flags);
2401 2402 2403
		cyy_writeb(info, CyCAR, channel & 0x03);
		status = cyy_readb(info, CyMSVR1);
		status |= cyy_readb(info, CyMSVR2);
2404
		spin_unlock_irqrestore(&card->card_lock, flags);
2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416

		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 已提交
2417
	} else {
J
Jiri Slaby 已提交
2418 2419 2420 2421 2422
		u32 lstatus;

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

J
Jiri Slaby 已提交
2425 2426 2427 2428 2429 2430 2431
		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);
2432
	}
J
Jiri Slaby 已提交
2433
end:
2434 2435
	return result;
}				/* cy_tiomget */
L
Linus Torvalds 已提交
2436 2437

static int
2438
cy_tiocmset(struct tty_struct *tty,
2439
		unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
2440
{
2441
	struct cyclades_port *info = tty->driver_data;
2442
	struct cyclades_card *card;
2443 2444
	unsigned long flags;

2445
	if (serial_paranoia_check(info, tty->name, __func__))
2446 2447 2448
		return -ENODEV;

	card = info->card;
2449
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2450 2451 2452
		spin_lock_irqsave(&card->card_lock, flags);
		cyy_change_rts_dtr(info, set, clear);
		spin_unlock_irqrestore(&card->card_lock, flags);
2453
	} else {
J
Jiri Slaby 已提交
2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
		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 已提交
2469
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2470
			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
L
Linus Torvalds 已提交
2471
#endif
J
Jiri Slaby 已提交
2472 2473 2474
		}
		if (clear & TIOCM_DTR) {
			rs &= ~C_RS_DTR;
L
Linus Torvalds 已提交
2475
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2476 2477
			printk(KERN_DEBUG "cyc:set_modem_info clearing "
				"Z DTR\n");
L
Linus Torvalds 已提交
2478
#endif
2479
		}
J
Jiri Slaby 已提交
2480
		cy_writel(&ch_ctrl->rs_control, rs);
2481
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
J
Jiri Slaby 已提交
2482
		spin_unlock_irqrestore(&card->card_lock, flags);
2483
		if (retval != 0) {
J
Jiri Slaby 已提交
2484 2485
			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
				"was %x\n", info->line, retval);
2486
		}
L
Linus Torvalds 已提交
2487
	}
2488
	return 0;
J
Jiri Slaby 已提交
2489
}
L
Linus Torvalds 已提交
2490 2491 2492 2493

/*
 * cy_break() --- routine which turns the break handling on or off
 */
A
Alan Cox 已提交
2494
static int cy_break(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
2495
{
2496
	struct cyclades_port *info = tty->driver_data;
2497
	struct cyclades_card *card;
2498
	unsigned long flags;
A
Alan Cox 已提交
2499
	int retval = 0;
L
Linus Torvalds 已提交
2500

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

2504 2505 2506
	card = info->card;

	spin_lock_irqsave(&card->card_lock, flags);
2507
	if (!cy_is_Z(card)) {
2508 2509 2510 2511 2512 2513 2514
		/* 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) {
2515
					spin_unlock_irqrestore(&card->card_lock, flags);
2516
					start_xmit(info);
2517
					spin_lock_irqsave(&card->card_lock, flags);
2518 2519 2520 2521 2522 2523
				}
			}
		} else {
			if (!info->breakoff) {
				info->breakoff = 1;
				if (!info->xmit_cnt) {
2524
					spin_unlock_irqrestore(&card->card_lock, flags);
2525
					start_xmit(info);
2526
					spin_lock_irqsave(&card->card_lock, flags);
2527 2528
				}
			}
L
Linus Torvalds 已提交
2529 2530
		}
	} else {
2531
		if (break_state == -1) {
2532 2533
			retval = cyz_issue_cmd(card,
				info->line - card->first_line,
2534 2535
				C_CM_SET_BREAK, 0L);
			if (retval != 0) {
J
Jiri Slaby 已提交
2536 2537
				printk(KERN_ERR "cyc:cy_break (set) retval on "
					"ttyC%d was %x\n", info->line, retval);
2538 2539
			}
		} else {
2540 2541
			retval = cyz_issue_cmd(card,
				info->line - card->first_line,
2542 2543
				C_CM_CLR_BREAK, 0L);
			if (retval != 0) {
J
Jiri Slaby 已提交
2544 2545 2546
				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
					"on ttyC%d was %x\n", info->line,
					retval);
2547
			}
L
Linus Torvalds 已提交
2548 2549
		}
	}
2550
	spin_unlock_irqrestore(&card->card_lock, flags);
A
Alan Cox 已提交
2551
	return retval;
2552
}				/* cy_break */
L
Linus Torvalds 已提交
2553

2554
static int set_threshold(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2555
{
2556
	struct cyclades_card *card = info->card;
2557
	unsigned long flags;
L
Linus Torvalds 已提交
2558

2559
	if (!cy_is_Z(card)) {
2560 2561
		info->cor3 &= ~CyREC_FIFO;
		info->cor3 |= value & CyREC_FIFO;
L
Linus Torvalds 已提交
2562

2563
		spin_lock_irqsave(&card->card_lock, flags);
2564 2565
		cyy_writeb(info, CyCOR3, info->cor3);
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
2566
		spin_unlock_irqrestore(&card->card_lock, flags);
2567 2568 2569
	}
	return 0;
}				/* set_threshold */
L
Linus Torvalds 已提交
2570

A
Alan Cox 已提交
2571 2572
static int get_threshold(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2573
{
2574
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2575

2576
	if (!cy_is_Z(card)) {
2577
		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
2578 2579
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2580
	return 0;
2581
}				/* get_threshold */
L
Linus Torvalds 已提交
2582

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

2588
	if (!cy_is_Z(card)) {
2589
		spin_lock_irqsave(&card->card_lock, flags);
2590
		cyy_writeb(info, CyRTPR, value & 0xff);
2591
		spin_unlock_irqrestore(&card->card_lock, flags);
2592 2593 2594
	}
	return 0;
}				/* set_timeout */
L
Linus Torvalds 已提交
2595

A
Alan Cox 已提交
2596 2597
static int get_timeout(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2598
{
2599
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2600

2601
	if (!cy_is_Z(card)) {
2602
		u8 tmp = cyy_readb(info, CyRTPR);
2603 2604
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2605
	return 0;
2606
}				/* get_timeout */
L
Linus Torvalds 已提交
2607

J
Jiri Slaby 已提交
2608 2609
static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
		struct cyclades_icount *cprev)
L
Linus Torvalds 已提交
2610
{
J
Jiri Slaby 已提交
2611 2612 2613
	struct cyclades_icount cnow;
	unsigned long flags;
	int ret;
L
Linus Torvalds 已提交
2614

J
Jiri Slaby 已提交
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627
	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 已提交
2628 2629 2630 2631 2632 2633 2634

/*
 * 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
2635
cy_ioctl(struct tty_struct *tty,
2636
	 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2637
{
2638
	struct cyclades_port *info = tty->driver_data;
J
Jiri Slaby 已提交
2639
	struct cyclades_icount cnow;	/* kernel counter temps */
2640 2641 2642 2643 2644 2645
	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 已提交
2646 2647

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

2652 2653
	switch (cmd) {
	case CYGETMON:
J
Jiri Slaby 已提交
2654 2655 2656 2657 2658
		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
			ret_val = -EFAULT;
			break;
		}
		memset(&info->mon, 0, sizeof(info->mon));
2659 2660 2661 2662 2663 2664 2665 2666
		break;
	case CYGETTHRESH:
		ret_val = get_threshold(info, argp);
		break;
	case CYSETTHRESH:
		ret_val = set_threshold(info, arg);
		break;
	case CYGETDEFTHRESH:
J
Jiri Slaby 已提交
2667 2668
		ret_val = put_user(info->default_threshold,
				(unsigned long __user *)argp);
2669 2670
		break;
	case CYSETDEFTHRESH:
J
Jiri Slaby 已提交
2671
		info->default_threshold = arg & 0x0f;
2672 2673 2674 2675 2676 2677 2678 2679
		break;
	case CYGETTIMEOUT:
		ret_val = get_timeout(info, argp);
		break;
	case CYSETTIMEOUT:
		ret_val = set_timeout(info, arg);
		break;
	case CYGETDEFTIMEOUT:
J
Jiri Slaby 已提交
2680 2681
		ret_val = put_user(info->default_timeout,
				(unsigned long __user *)argp);
2682 2683
		break;
	case CYSETDEFTIMEOUT:
J
Jiri Slaby 已提交
2684
		info->default_timeout = arg & 0xff;
2685
		break;
L
Linus Torvalds 已提交
2686
	case CYSETRFLOW:
2687 2688
		info->rflow = (int)arg;
		break;
L
Linus Torvalds 已提交
2689
	case CYGETRFLOW:
2690 2691
		ret_val = info->rflow;
		break;
L
Linus Torvalds 已提交
2692
	case CYSETRTSDTR_INV:
2693 2694
		info->rtsdtr_inv = (int)arg;
		break;
L
Linus Torvalds 已提交
2695
	case CYGETRTSDTR_INV:
2696 2697
		ret_val = info->rtsdtr_inv;
		break;
L
Linus Torvalds 已提交
2698
	case CYGETCD1400VER:
2699 2700
		ret_val = info->chip_rev;
		break;
L
Linus Torvalds 已提交
2701 2702
#ifndef CONFIG_CYZ_INTR
	case CYZSETPOLLCYCLE:
2703 2704
		if (arg > LONG_MAX / HZ)
			return -ENODEV;
2705 2706
		cyz_polling_cycle = (arg * HZ) / 1000;
		break;
L
Linus Torvalds 已提交
2707
	case CYZGETPOLLCYCLE:
2708 2709 2710
		ret_val = (cyz_polling_cycle * 1000) / HZ;
		break;
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
2711
	case CYSETWAIT:
A
Alan Cox 已提交
2712
		info->port.closing_wait = (unsigned short)arg * HZ / 100;
2713
		break;
L
Linus Torvalds 已提交
2714
	case CYGETWAIT:
A
Alan Cox 已提交
2715
		ret_val = info->port.closing_wait / (HZ / 100);
2716 2717
		break;
	case TIOCGSERIAL:
J
Jiri Slaby 已提交
2718
		ret_val = cy_get_serial_info(info, argp);
2719 2720
		break;
	case TIOCSSERIAL:
J
Jiri Slaby 已提交
2721
		ret_val = cy_set_serial_info(info, tty, argp);
2722 2723 2724 2725 2726 2727 2728 2729 2730 2731
		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 已提交
2732
	case TIOCMIWAIT:
2733
		spin_lock_irqsave(&info->card->card_lock, flags);
2734
		/* note the counters on entry */
J
Jiri Slaby 已提交
2735
		cnow = info->icount;
2736
		spin_unlock_irqrestore(&info->card->card_lock, flags);
2737
		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
J
Jiri Slaby 已提交
2738
				cy_cflags_changed(info, arg, &cnow));
J
Jiri Slaby 已提交
2739
		break;
L
Linus Torvalds 已提交
2740

2741 2742 2743 2744 2745 2746 2747 2748 2749
		/*
		 * 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 已提交
2750 2751

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2752
	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
L
Linus Torvalds 已提交
2753
#endif
2754 2755
	return ret_val;
}				/* cy_ioctl */
L
Linus Torvalds 已提交
2756

2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781
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 已提交
2782 2783 2784 2785 2786 2787
/*
 * 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.
 */
2788
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
L
Linus Torvalds 已提交
2789
{
2790
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
2791 2792

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

J
Jiri Slaby 已提交
2796
	cy_set_line_char(info, tty);
2797 2798

	if ((old_termios->c_cflag & CRTSCTS) &&
2799
			!(tty->termios.c_cflag & CRTSCTS)) {
2800 2801 2802
		tty->hw_stopped = 0;
		cy_start(tty);
	}
L
Linus Torvalds 已提交
2803
#if 0
2804 2805 2806 2807 2808 2809 2810
	/*
	 * 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) &&
2811
	    (tty->termios.c_cflag & CLOCAL))
A
Alan Cox 已提交
2812
		wake_up_interruptible(&info->port.open_wait);
L
Linus Torvalds 已提交
2813
#endif
2814
}				/* cy_set_termios */
L
Linus Torvalds 已提交
2815 2816 2817 2818

/* This function is used to send a high-priority XON/XOFF character to
   the device.
*/
2819
static void cy_send_xchar(struct tty_struct *tty, char ch)
L
Linus Torvalds 已提交
2820
{
2821
	struct cyclades_port *info = tty->driver_data;
2822 2823
	struct cyclades_card *card;
	int channel;
L
Linus Torvalds 已提交
2824

2825
	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
L
Linus Torvalds 已提交
2826 2827
		return;

2828
	info->x_char = ch;
L
Linus Torvalds 已提交
2829 2830

	if (ch)
2831
		cy_start(tty);
L
Linus Torvalds 已提交
2832 2833

	card = info->card;
2834
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
2835

2836
	if (cy_is_Z(card)) {
2837
		if (ch == STOP_CHAR(tty))
2838
			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
2839
		else if (ch == START_CHAR(tty))
2840
			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
L
Linus Torvalds 已提交
2841 2842 2843 2844 2845 2846 2847
	}
}

/* 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.
 */
2848
static void cy_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2849
{
2850
	struct cyclades_port *info = tty->driver_data;
2851
	struct cyclades_card *card;
2852
	unsigned long flags;
L
Linus Torvalds 已提交
2853 2854

#ifdef CY_DEBUG_THROTTLE
2855 2856
	printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
			 info->line);
L
Linus Torvalds 已提交
2857 2858
#endif

A
Alan Cox 已提交
2859
	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2860 2861 2862 2863 2864
		return;

	card = info->card;

	if (I_IXOFF(tty)) {
2865
		if (!cy_is_Z(card))
2866 2867 2868 2869
			cy_send_xchar(tty, STOP_CHAR(tty));
		else
			info->throttle = 1;
	}
L
Linus Torvalds 已提交
2870

2871
	if (tty->termios.c_cflag & CRTSCTS) {
2872
		if (!cy_is_Z(card)) {
2873
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2874
			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
2875
			spin_unlock_irqrestore(&card->card_lock, flags);
2876 2877 2878 2879 2880
		} else {
			info->throttle = 1;
		}
	}
}				/* cy_throttle */
L
Linus Torvalds 已提交
2881 2882 2883 2884 2885 2886

/*
 * 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.
 */
2887
static void cy_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2888
{
2889
	struct cyclades_port *info = tty->driver_data;
2890
	struct cyclades_card *card;
2891
	unsigned long flags;
L
Linus Torvalds 已提交
2892 2893

#ifdef CY_DEBUG_THROTTLE
2894 2895
	printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
		tty_name(tty), info->line);
L
Linus Torvalds 已提交
2896 2897
#endif

A
Alan Cox 已提交
2898
	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2899
		return;
L
Linus Torvalds 已提交
2900

2901 2902 2903 2904 2905
	if (I_IXOFF(tty)) {
		if (info->x_char)
			info->x_char = 0;
		else
			cy_send_xchar(tty, START_CHAR(tty));
L
Linus Torvalds 已提交
2906 2907
	}

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

/* cy_start and cy_stop provide software output flow control as a
   function of XON/XOFF, software CTS, and other such stuff.
*/
2923
static void cy_stop(struct tty_struct *tty)
L
Linus Torvalds 已提交
2924
{
2925
	struct cyclades_card *cinfo;
2926
	struct cyclades_port *info = tty->driver_data;
2927
	int channel;
2928
	unsigned long flags;
L
Linus Torvalds 已提交
2929 2930

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

2934 2935
	if (serial_paranoia_check(info, tty->name, "cy_stop"))
		return;
L
Linus Torvalds 已提交
2936

2937
	cinfo = info->card;
2938
	channel = info->line - cinfo->first_line;
2939
	if (!cy_is_Z(cinfo)) {
2940
		spin_lock_irqsave(&cinfo->card_lock, flags);
2941 2942
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
2943
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2944 2945
	}
}				/* cy_stop */
L
Linus Torvalds 已提交
2946

2947
static void cy_start(struct tty_struct *tty)
L
Linus Torvalds 已提交
2948
{
2949
	struct cyclades_card *cinfo;
2950
	struct cyclades_port *info = tty->driver_data;
2951
	int channel;
2952
	unsigned long flags;
L
Linus Torvalds 已提交
2953 2954

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

2958 2959
	if (serial_paranoia_check(info, tty->name, "cy_start"))
		return;
L
Linus Torvalds 已提交
2960

2961
	cinfo = info->card;
2962
	channel = info->line - cinfo->first_line;
2963
	if (!cy_is_Z(cinfo)) {
2964
		spin_lock_irqsave(&cinfo->card_lock, flags);
2965 2966
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
2967
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2968 2969
	}
}				/* cy_start */
L
Linus Torvalds 已提交
2970 2971 2972 2973

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

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

2982 2983
	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
		return;
L
Linus Torvalds 已提交
2984

2985
	cy_flush_buffer(tty);
J
Jiri Slaby 已提交
2986
	cy_shutdown(info, tty);
J
Jiri Slaby 已提交
2987
	tty_port_hangup(&info->port);
2988
}				/* cy_hangup */
L
Linus Torvalds 已提交
2989

J
Jiri Slaby 已提交
2990 2991 2992 2993 2994 2995 2996 2997 2998 2999
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);
3000 3001
	cyy_writeb(info, CyCAR, channel & 0x03);
	cd = cyy_readb(info, CyMSVR1) & CyDCD;
J
Jiri Slaby 已提交
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014
	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 已提交
3015 3016
	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
J
Jiri Slaby 已提交
3017 3018 3019 3020 3021 3022 3023 3024
	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);

3025
	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
J
Jiri Slaby 已提交
3026 3027 3028 3029 3030 3031 3032
}

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

3037
	rs = readl(&ch_ctrl->rs_control);
J
Jiri Slaby 已提交
3038 3039 3040 3041
	if (raise)
		rs |= C_RS_RTS | C_RS_DTR;
	else
		rs &= ~(C_RS_RTS | C_RS_DTR);
3042
	cy_writel(&ch_ctrl->rs_control, rs);
J
Jiri Slaby 已提交
3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054
	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,
3055
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3056 3057 3058 3059 3060
};

static const struct tty_port_operations cyz_port_ops = {
	.carrier_raised = cyz_carrier_raised,
	.dtr_rts = cyz_dtr_rts,
3061
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3062 3063
};

L
Linus Torvalds 已提交
3064 3065 3066 3067 3068 3069 3070 3071
/*
 * ---------------------------------------------------------------------
 * cy_init() and friends
 *
 * cy_init() is called at boot-time to initialize the serial driver.
 * ---------------------------------------------------------------------
 */

B
Bill Pemberton 已提交
3072
static int cy_init_card(struct cyclades_card *cinfo)
3073 3074
{
	struct cyclades_port *info;
3075
	unsigned int channel, port;
3076

3077
	spin_lock_init(&cinfo->card_lock);
J
Jiri Slaby 已提交
3078
	cinfo->intr_enabled = 0;
3079

J
Jiri Slaby 已提交
3080 3081
	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
			GFP_KERNEL);
J
Jiri Slaby 已提交
3082 3083 3084 3085 3086
	if (cinfo->ports == NULL) {
		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
		return -ENOMEM;
	}

3087 3088 3089
	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
			channel++, port++) {
		info = &cinfo->ports[channel];
A
Alan Cox 已提交
3090
		tty_port_init(&info->port);
3091
		info->magic = CYCLADES_MAGIC;
3092
		info->card = cinfo;
3093 3094
		info->line = port;

A
Alan Cox 已提交
3095 3096
		info->port.closing_wait = CLOSING_WAIT_DELAY;
		info->port.close_delay = 5 * HZ / 10;
A
Alan Cox 已提交
3097
		info->port.flags = STD_COM_FLAGS;
J
Jiri Slaby 已提交
3098
		init_completion(&info->shutdown_wait);
3099

3100
		if (cy_is_Z(cinfo)) {
3101 3102 3103
			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
			struct ZFW_CTRL *zfw_ctrl;

J
Jiri Slaby 已提交
3104
			info->port.ops = &cyz_port_ops;
3105
			info->type = PORT_STARTECH;
3106 3107 3108 3109 3110 3111

			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 已提交
3112
			if (cinfo->hw_ver == ZO_V1)
3113 3114
				info->xmit_fifo_size = CYZ_FIFO_SIZE;
			else
3115
				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
3116
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3117 3118
			setup_timer(&cyz_rx_full_timer[port],
				cyz_rx_restart, (unsigned long)info);
3119
#endif
3120
		} else {
3121
			unsigned short chip_number;
J
Jiri Slaby 已提交
3122
			int index = cinfo->bus_index;
3123

J
Jiri Slaby 已提交
3124
			info->port.ops = &cyy_port_ops;
3125 3126
			info->type = PORT_CIRRUS;
			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
3127
			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
3128 3129
			info->cor2 = CyETC;
			info->cor3 = 0x08;	/* _very_ small rcv threshold */
3130

3131
			chip_number = channel / CyPORTS_PER_CHIP;
3132 3133 3134
			info->u.cyy.base_addr = cinfo->base_addr +
				(cy_chip_offset[chip_number] << index);
			info->chip_rev = cyy_readb(info, CyGFRCR);
A
Alan Cox 已提交
3135 3136

			if (info->chip_rev >= CD1400_REV_J) {
3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149
				/* 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;
			}
3150 3151
			info->read_status_mask = CyTIMEOUT | CySPECHAR |
				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3152
		}
3153

3154
	}
3155 3156

#ifndef CONFIG_CYZ_INTR
3157
	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
3158 3159 3160 3161 3162 3163
		mod_timer(&cyz_timerlist, jiffies + 1);
#ifdef CY_PCI_DEBUG
		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
#endif
	}
#endif
J
Jiri Slaby 已提交
3164
	return 0;
3165 3166
}

L
Linus Torvalds 已提交
3167 3168
/* initialize chips on Cyclom-Y card -- return number of valid
   chips (which is number of ports/4) */
B
Bill Pemberton 已提交
3169
static unsigned short cyy_init_card(void __iomem *true_base_addr,
3170
		int index)
L
Linus Torvalds 已提交
3171
{
3172 3173 3174 3175 3176 3177 3178 3179 3180
	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 已提交
3181 3182
	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
							chip_number++) {
3183 3184 3185
		base_addr =
		    true_base_addr + (cy_chip_offset[chip_number] << index);
		mdelay(1);
3186
		if (readb(base_addr + (CyCCR << index)) != 0x00) {
3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
			/*************
			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.
		 */
3203
		if (chip_number == 4 && readb(true_base_addr +
3204 3205 3206 3207 3208 3209 3210 3211
				(cy_chip_offset[0] << index) +
				(CyGFRCR << index)) == 0) {
			return chip_number;
		}

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

3212
		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
3213 3214 3215 3216 3217 3218 3219
			/*
			   printk(" chip #%d at %#6lx is not responding ",
			   chip_number, (unsigned long)base_addr);
			   printk("(GFRCR stayed 0)\n",
			 */
			return chip_number;
		}
3220
		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
3221 3222 3223 3224 3225 3226 3227 3228 3229 3230
				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);
3231
		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
3232 3233 3234 3235 3236 3237 3238 3239
			/* 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 已提交
3240

3241 3242 3243
		/*
		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
		   chip_number, (unsigned long)base_addr,
3244
		   readb(base_addr+(CyGFRCR<<index)));
3245 3246 3247 3248
		 */
	}
	return chip_number;
}				/* cyy_init_card */
L
Linus Torvalds 已提交
3249 3250 3251 3252 3253 3254 3255

/*
 * ---------------------------------------------------------------------
 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
 * sets global variables and return the number of ISA boards found.
 * ---------------------------------------------------------------------
 */
3256
static int __init cy_detect_isa(void)
L
Linus Torvalds 已提交
3257 3258
{
#ifdef CONFIG_ISA
3259
	struct cyclades_card *card;
3260 3261
	unsigned short cy_isa_irq, nboard;
	void __iomem *cy_isa_address;
J
Jiri Slaby 已提交
3262
	unsigned short i, j, k, cy_isa_nchan;
3263
	int isparam = 0;
L
Linus Torvalds 已提交
3264

3265
	nboard = 0;
L
Linus Torvalds 已提交
3266 3267

	/* Check for module parameters */
3268 3269 3270 3271 3272 3273 3274
	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 已提交
3275 3276
	}

3277 3278 3279
	/* 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 已提交
3280
		if (isa_address == 0x0000)
J
Jiri Slaby 已提交
3281
			return nboard;
L
Linus Torvalds 已提交
3282

3283
		/* probe for CD1400... */
3284
		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
J
Jiri Slaby 已提交
3285 3286 3287 3288 3289
		if (cy_isa_address == NULL) {
			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
					"address\n");
			continue;
		}
3290 3291 3292
		cy_isa_nchan = CyPORTS_PER_CHIP *
			cyy_init_card(cy_isa_address, 0);
		if (cy_isa_nchan == 0) {
J
Jiri Slaby 已提交
3293
			iounmap(cy_isa_address);
3294 3295
			continue;
		}
3296

R
Roel Kluin 已提交
3297
		if (isparam && i < NR_CARDS && irq[i])
3298
			cy_isa_irq = irq[i];
L
Linus Torvalds 已提交
3299
		else
3300 3301 3302
			/* 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 已提交
3303 3304
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
				"IRQ could not be detected.\n",
3305
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3306
			iounmap(cy_isa_address);
3307 3308 3309 3310
			continue;
		}

		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
J
Jiri Slaby 已提交
3311 3312 3313
			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",
3314
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3315
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3316
			return nboard;
3317 3318 3319
		}
		/* fill the next cy_card structure available */
		for (j = 0; j < NR_CARDS; j++) {
3320 3321
			card = &cy_card[j];
			if (card->base_addr == NULL)
3322 3323 3324
				break;
		}
		if (j == NR_CARDS) {	/* no more cy_cards available */
J
Jiri Slaby 已提交
3325 3326 3327
			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",
3328
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3329
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3330
			return nboard;
3331 3332 3333 3334
		}

		/* allocate IRQ */
		if (request_irq(cy_isa_irq, cyy_interrupt,
3335
				0, "Cyclom-Y", card)) {
J
Jiri Slaby 已提交
3336 3337 3338
			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 已提交
3339
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3340
			return nboard;
3341 3342 3343
		}

		/* set cy_card */
3344 3345 3346 3347 3348 3349 3350 3351 3352 3353
		card->base_addr = cy_isa_address;
		card->ctl_addr.p9050 = NULL;
		card->irq = (int)cy_isa_irq;
		card->bus_index = 0;
		card->first_line = cy_next_channel;
		card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
		card->nports = cy_isa_nchan;
		if (cy_init_card(card)) {
			card->base_addr = NULL;
			free_irq(cy_isa_irq, card);
J
Jiri Slaby 已提交
3354 3355 3356
			iounmap(cy_isa_address);
			continue;
		}
3357 3358
		nboard++;

J
Jiri Slaby 已提交
3359 3360
		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
			"%d channels starting from port %d\n",
3361 3362
			j + 1, (unsigned long)cy_isa_address,
			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
J
Jiri Slaby 已提交
3363 3364
			cy_isa_irq, cy_isa_nchan, cy_next_channel);

J
Jiri Slaby 已提交
3365 3366 3367 3368
		for (k = 0, j = cy_next_channel;
				j < cy_next_channel + cy_isa_nchan; j++, k++)
			tty_port_register_device(&card->ports[k].port,
					cy_serial_driver, j, NULL);
3369 3370
		cy_next_channel += cy_isa_nchan;
	}
J
Jiri Slaby 已提交
3371
	return nboard;
L
Linus Torvalds 已提交
3372
#else
J
Jiri Slaby 已提交
3373
	return 0;
3374 3375
#endif				/* CONFIG_ISA */
}				/* cy_detect_isa */
L
Linus Torvalds 已提交
3376

J
Jiri Slaby 已提交
3377
#ifdef CONFIG_PCI
B
Bill Pemberton 已提交
3378
static inline int cyc_isfwstr(const char *str, unsigned int size)
3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392
{
	unsigned int a;

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

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

	return 0;
}

B
Bill Pemberton 已提交
3393
static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3394 3395 3396 3397 3398 3399 3400 3401
		unsigned int size)
{
	for (; size > 0; size--) {
		cy_writel(fpga, *data++);
		udelay(10);
	}
}

B
Bill Pemberton 已提交
3402
static void plx_init(struct pci_dev *pdev, int irq,
3403
		struct RUNTIME_9060 __iomem *addr)
L
Linus Torvalds 已提交
3404
{
3405
	/* Reset PLX */
3406
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
3407
	udelay(100L);
3408
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
3409 3410

	/* Reload Config. Registers from EEPROM */
3411
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3412
	udelay(100L);
3413 3414 3415 3416 3417 3418 3419 3420 3421
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);

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

B
Bill Pemberton 已提交
3422
static int __cyz_load_fw(const struct firmware *fw,
3423 3424 3425
		const char *name, const u32 mailbox, void __iomem *base,
		void __iomem *fpga)
{
3426 3427 3428 3429
	const void *ptr = fw->data;
	const struct zfile_header *h = ptr;
	const struct zfile_config *c, *cs;
	const struct zfile_block *b, *bs;
3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498
	unsigned int a, tmp, len = fw->size;
#define BAD_FW KERN_ERR "Bad firmware: "
	if (len < sizeof(*h)) {
		printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
		return -EINVAL;
	}

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

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

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

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

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

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

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

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

B
Bill Pemberton 已提交
3499
static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3500 3501 3502 3503 3504 3505
		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 已提交
3506
	void __iomem *tmp;
J
Jiri Slaby 已提交
3507
	u32 mailbox, status, nchan;
3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518
	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 */
3519
	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537
		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);

3538
	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
		/* 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;
3554
		if (!__cyz_fpga_loaded(ctl_addr)) {
3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567
			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 已提交
3568
	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3569 3570 3571 3572
		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 已提交
3573
		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612
			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");

3613
			if (__cyz_fpga_loaded(ctl_addr))
3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627
				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 已提交
3628
	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3629
	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
J
Jiri Slaby 已提交
3630
		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3631

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

3637
		if (__cyz_fpga_loaded(ctl_addr))
3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657
			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 已提交
3658
	return nchan;
3659 3660 3661 3662
err_rel:
	release_firmware(fw);
err:
	return retval;
L
Linus Torvalds 已提交
3663 3664
}

B
Bill Pemberton 已提交
3665
static int cy_pci_probe(struct pci_dev *pdev,
J
Jiri Slaby 已提交
3666
		const struct pci_device_id *ent)
L
Linus Torvalds 已提交
3667
{
3668
	struct cyclades_card *card;
J
Jiri Slaby 已提交
3669 3670
	void __iomem *addr0 = NULL, *addr2 = NULL;
	char *card_name = NULL;
J
Jiri Slaby 已提交
3671
	u32 uninitialized_var(mailbox);
J
Jiri Slaby 已提交
3672
	unsigned int device_id, nchan = 0, card_no, i, j;
J
Jiri Slaby 已提交
3673 3674
	unsigned char plx_ver;
	int retval, irq;
3675

J
Jiri Slaby 已提交
3676 3677 3678
	retval = pci_enable_device(pdev);
	if (retval) {
		dev_err(&pdev->dev, "cannot enable device\n");
J
Jiri Slaby 已提交
3679
		goto err;
J
Jiri Slaby 已提交
3680
	}
L
Linus Torvalds 已提交
3681

J
Jiri Slaby 已提交
3682
	/* read PCI configuration area */
J
Jiri Slaby 已提交
3683
	irq = pdev->irq;
J
Jiri Slaby 已提交
3684
	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
L
Linus Torvalds 已提交
3685

J
Jiri Slaby 已提交
3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713
#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 已提交
3714 3715
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
J
Jiri Slaby 已提交
3716
		card_name = "Cyclom-Y";
L
Linus Torvalds 已提交
3717

J
Jiri Slaby 已提交
3718 3719
		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Yctl);
J
Jiri Slaby 已提交
3720 3721 3722
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
J
Jiri Slaby 已提交
3723
		}
J
Jiri Slaby 已提交
3724 3725
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				CyPCI_Ywin);
J
Jiri Slaby 已提交
3726 3727 3728
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3729
		}
L
Linus Torvalds 已提交
3730

J
Jiri Slaby 已提交
3731 3732
		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
		if (nchan == 0) {
J
Jiri Slaby 已提交
3733 3734
			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
					"Serial-Modules\n");
3735
			goto err_unmap;
J
Jiri Slaby 已提交
3736 3737
		}
	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
J
Jiri Slaby 已提交
3738
		struct RUNTIME_9060 __iomem *ctl_addr;
J
Jiri Slaby 已提交
3739

J
Jiri Slaby 已提交
3740 3741
		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Zctl);
J
Jiri Slaby 已提交
3742 3743 3744 3745
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
		}
J
Jiri Slaby 已提交
3746 3747

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

3751
		plx_init(pdev, irq, addr0);
3752

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

J
Jiri Slaby 已提交
3755 3756
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
J
Jiri Slaby 已提交
3757 3758 3759
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3760 3761 3762
		}

		if (mailbox == ZE_V1) {
J
Jiri Slaby 已提交
3763
			card_name = "Cyclades-Ze";
J
Jiri Slaby 已提交
3764
		} else {
J
Jiri Slaby 已提交
3765
			card_name = "Cyclades-8Zo";
L
Linus Torvalds 已提交
3766
#ifdef CY_PCI_DEBUG
J
Jiri Slaby 已提交
3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779
			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 已提交
3780
#endif
J
Jiri Slaby 已提交
3781 3782 3783 3784 3785 3786
			/* 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 已提交
3787
		}
3788 3789

		retval = cyz_load_fw(pdev, addr2, addr0, irq);
J
Jiri Slaby 已提交
3790
		if (retval <= 0)
3791
			goto err_unmap;
J
Jiri Slaby 已提交
3792
		nchan = retval;
J
Jiri Slaby 已提交
3793 3794 3795 3796 3797 3798 3799 3800 3801 3802
	}

	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++) {
3803 3804
		card = &cy_card[card_no];
		if (card->base_addr == NULL)
J
Jiri Slaby 已提交
3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817
			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,
3818
				IRQF_SHARED, "Cyclom-Y", card);
J
Jiri Slaby 已提交
3819 3820 3821
		if (retval) {
			dev_err(&pdev->dev, "could not allocate IRQ\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3822
		}
3823
		card->num_chips = nchan / CyPORTS_PER_CHIP;
J
Jiri Slaby 已提交
3824
	} else {
3825 3826 3827 3828 3829
		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
		struct ZFW_CTRL __iomem *zfw_ctrl;

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

3830 3831 3832
		card->hw_ver = mailbox;
		card->num_chips = (unsigned int)-1;
		card->board_ctrl = &zfw_ctrl->board_ctrl;
3833
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3834
		/* allocate IRQ only if board has an IRQ */
J
Jiri Slaby 已提交
3835 3836
		if (irq != 0 && irq != 255) {
			retval = request_irq(irq, cyz_interrupt,
3837
					IRQF_SHARED, "Cyclades-Z", card);
J
Jiri Slaby 已提交
3838
			if (retval) {
J
Jiri Slaby 已提交
3839
				dev_err(&pdev->dev, "could not allocate IRQ\n");
J
Jiri Slaby 已提交
3840
				goto err_unmap;
3841
			}
J
Jiri Slaby 已提交
3842
		}
3843
#endif				/* CONFIG_CYZ_INTR */
J
Jiri Slaby 已提交
3844
	}
3845

J
Jiri Slaby 已提交
3846
	/* set cy_card */
3847 3848 3849 3850 3851 3852 3853
	card->base_addr = addr2;
	card->ctl_addr.p9050 = addr0;
	card->irq = irq;
	card->bus_index = 1;
	card->first_line = cy_next_channel;
	card->nports = nchan;
	retval = cy_init_card(card);
J
Jiri Slaby 已提交
3854 3855
	if (retval)
		goto err_null;
J
Jiri Slaby 已提交
3856

3857
	pci_set_drvdata(pdev, card);
J
Jiri Slaby 已提交
3858

J
Jiri Slaby 已提交
3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870
	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 */
3871 3872 3873 3874 3875
		{
			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 已提交
3876 3877
			break;
		}
3878
		}
J
Jiri Slaby 已提交
3879 3880
	}

J
Jiri Slaby 已提交
3881 3882
	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
J
Jiri Slaby 已提交
3883 3884 3885
	for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
		tty_port_register_device(&card->ports[j].port,
				cy_serial_driver, i, &pdev->dev);
J
Jiri Slaby 已提交
3886 3887
	cy_next_channel += nchan;

J
Jiri Slaby 已提交
3888
	return 0;
J
Jiri Slaby 已提交
3889
err_null:
3890 3891
	card->base_addr = NULL;
	free_irq(irq, card);
J
Jiri Slaby 已提交
3892
err_unmap:
J
Jiri Slaby 已提交
3893
	iounmap(addr0);
J
Jiri Slaby 已提交
3894
	if (addr2)
J
Jiri Slaby 已提交
3895
		iounmap(addr2);
J
Jiri Slaby 已提交
3896 3897 3898 3899 3900 3901
err_reg:
	pci_release_regions(pdev);
err_dis:
	pci_disable_device(pdev);
err:
	return retval;
J
Jiri Slaby 已提交
3902 3903
}

B
Bill Pemberton 已提交
3904
static void cy_pci_remove(struct pci_dev *pdev)
J
Jiri Slaby 已提交
3905
{
J
Jiri Slaby 已提交
3906
	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3907
	unsigned int i, channel;
J
Jiri Slaby 已提交
3908

3909
	/* non-Z with old PLX */
3910
	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
J
Jiri Slaby 已提交
3911
			PLX_9050)
3912
		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
3913 3914
	else
#ifndef CONFIG_CYZ_INTR
3915
		if (!cy_is_Z(cinfo))
3916
#endif
3917 3918 3919
		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
			~0x0900);
3920

J
Jiri Slaby 已提交
3921
	iounmap(cinfo->base_addr);
3922 3923
	if (cinfo->ctl_addr.p9050)
		iounmap(cinfo->ctl_addr.p9050);
J
Jiri Slaby 已提交
3924 3925
	if (cinfo->irq
#ifndef CONFIG_CYZ_INTR
3926
		&& !cy_is_Z(cinfo)
J
Jiri Slaby 已提交
3927 3928 3929 3930 3931 3932
#endif /* CONFIG_CYZ_INTR */
		)
		free_irq(cinfo->irq, cinfo);
	pci_release_regions(pdev);

	cinfo->base_addr = NULL;
3933 3934
	for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
			cinfo->nports; i++, channel++) {
3935
		tty_unregister_device(cy_serial_driver, i);
3936 3937
		tty_port_destroy(&cinfo->ports[channel].port);
	}
J
Jiri Slaby 已提交
3938 3939
	cinfo->nports = 0;
	kfree(cinfo->ports);
J
Jiri Slaby 已提交
3940 3941
}

3942 3943 3944 3945
static struct pci_driver cy_pci_driver = {
	.name = "cyclades",
	.id_table = cy_pci_dev_id,
	.probe = cy_pci_probe,
B
Bill Pemberton 已提交
3946
	.remove = cy_pci_remove
3947 3948 3949
};
#endif

3950
static int cyclades_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
3951
{
3952
	struct cyclades_port *info;
J
Jiri Slaby 已提交
3953
	unsigned int i, j;
3954 3955
	__u32 cur_jifs = jiffies;

3956
	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
3957 3958 3959
			"IdleIn  Overruns  Ldisc\n");

	/* Output one line for each known port */
J
Jiri Slaby 已提交
3960 3961 3962 3963
	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 已提交
3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977
			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);
				}
3978
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
3979
					"%10lu %8lu %9lu %6d\n", info->line,
J
Jiri Slaby 已提交
3980 3981 3982 3983 3984 3985
					(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 已提交
3986 3987
					num);
			} else
3988
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
3989 3990
					"%10lu %8lu %9lu %6ld\n",
					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
3991
		}
3992 3993 3994 3995 3996 3997
	return 0;
}

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

4000 4001 4002 4003 4004 4005 4006 4007
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 已提交
4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025
/* 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 已提交
4026
static const struct tty_operations cy_ops = {
4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045
	.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,
4046
	.get_icount = cy_get_icount,
4047
	.proc_fops = &cyclades_proc_fops,
L
Linus Torvalds 已提交
4048 4049
};

4050
static int __init cy_init(void)
L
Linus Torvalds 已提交
4051
{
J
Jiri Slaby 已提交
4052
	unsigned int nboards;
4053
	int retval = -ENOMEM;
4054 4055 4056

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

M
Michal Marek 已提交
4059
	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071

	/* Initialize the tty_driver structure */

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

4075 4076 4077 4078 4079
	retval = tty_register_driver(cy_serial_driver);
	if (retval) {
		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
		goto err_frtty;
	}
4080 4081 4082 4083 4084 4085 4086 4087 4088

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

4091
#ifdef CONFIG_PCI
4092
	/* look for pci boards */
4093
	retval = pci_register_driver(&cy_pci_driver);
4094 4095 4096 4097
	if (retval && !nboards) {
		tty_unregister_driver(cy_serial_driver);
		goto err_frtty;
	}
4098
#endif
4099 4100 4101 4102 4103 4104

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

4107
static void __exit cy_cleanup_module(void)
L
Linus Torvalds 已提交
4108
{
J
Jiri Slaby 已提交
4109
	struct cyclades_card *card;
J
Jiri Slaby 已提交
4110
	unsigned int i, e1;
L
Linus Torvalds 已提交
4111 4112

#ifndef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
4113
	del_timer_sync(&cyz_timerlist);
L
Linus Torvalds 已提交
4114 4115
#endif /* CONFIG_CYZ_INTR */

A
Alan Cox 已提交
4116 4117
	e1 = tty_unregister_driver(cy_serial_driver);
	if (e1)
J
Jiri Slaby 已提交
4118 4119
		printk(KERN_ERR "failed to unregister Cyclades serial "
				"driver(%d)\n", e1);
L
Linus Torvalds 已提交
4120

4121 4122 4123 4124
#ifdef CONFIG_PCI
	pci_unregister_driver(&cy_pci_driver);
#endif

4125
	for (i = 0; i < NR_CARDS; i++) {
J
Jiri Slaby 已提交
4126 4127
		card = &cy_card[i];
		if (card->base_addr) {
4128
			/* clear interrupt */
J
Jiri Slaby 已提交
4129 4130
			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
			iounmap(card->base_addr);
4131 4132
			if (card->ctl_addr.p9050)
				iounmap(card->ctl_addr.p9050);
J
Jiri Slaby 已提交
4133
			if (card->irq
L
Linus Torvalds 已提交
4134
#ifndef CONFIG_CYZ_INTR
4135
				&& !cy_is_Z(card)
L
Linus Torvalds 已提交
4136
#endif /* CONFIG_CYZ_INTR */
4137
				)
J
Jiri Slaby 已提交
4138
				free_irq(card->irq, card);
J
Jiri Slaby 已提交
4139
			for (e1 = card->first_line; e1 < card->first_line +
J
Jiri Slaby 已提交
4140
					card->nports; e1++)
4141
				tty_unregister_device(cy_serial_driver, e1);
J
Jiri Slaby 已提交
4142
			kfree(card->ports);
4143 4144
		}
	}
4145 4146

	put_tty_driver(cy_serial_driver);
L
Linus Torvalds 已提交
4147 4148 4149 4150 4151 4152
} /* cy_cleanup_module */

module_init(cy_init);
module_exit(cy_cleanup_module);

MODULE_LICENSE("GPL");
4153
MODULE_VERSION(CY_VERSION);
4154
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4155
MODULE_FIRMWARE("cyzfirm.bin");