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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#define STD_COM_FLAGS (0)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* PCI related definitions */

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

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

#ifndef CONFIG_CYZ_INTR
static void cyz_poll(unsigned long);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

440 441
static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
		void __iomem *base_addr)
442 443
{
	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);
1127 1128 1129 1130 1131 1132 1133 1134
				else {
					struct tty_struct *tty;
					tty = tty_port_tty_get(&info->port);
					if (tty) {
						tty_hangup(tty);
						tty_kref_put(tty);
					}
				}
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
			}
			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 已提交
1149
#ifdef Z_WAKE
1150
		case C_CM_IOCTLW:
1151
			complete(&info->shutdown_wait);
1152
			break;
L
Linus Torvalds 已提交
1153 1154
#endif
#ifdef CONFIG_CYZ_INTR
1155 1156 1157 1158
		case C_CM_RXHIWM:
		case C_CM_RXNNDT:
		case C_CM_INTBACK2:
			/* Reception Interrupt */
L
Linus Torvalds 已提交
1159
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1160 1161
			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
					"port %ld\n", info->card, channel);
L
Linus Torvalds 已提交
1162
#endif
1163
			cyz_handle_rx(info);
1164 1165 1166 1167 1168
			break;
		case C_CM_TXBEMPTY:
		case C_CM_TXLOWWM:
		case C_CM_INTBACK:
			/* Transmission Interrupt */
L
Linus Torvalds 已提交
1169
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1170 1171
			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
					"port %ld\n", info->card, channel);
L
Linus Torvalds 已提交
1172
#endif
1173
			cyz_handle_tx(info);
1174 1175 1176 1177 1178 1179 1180 1181 1182
			break;
#endif				/* CONFIG_CYZ_INTR */
		case C_CM_FATAL:
			/* should do something with this !!! */
			break;
		default:
			break;
		}
		if (delta_count)
1183
			wake_up_interruptible(&info->port.delta_msr_wait);
1184
		if (special_count)
J
Jiri Slaby 已提交
1185
			tty_schedule_flip(&info->port);
L
Linus Torvalds 已提交
1186 1187 1188 1189
	}
}

#ifdef CONFIG_CYZ_INTR
1190
static irqreturn_t cyz_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
1191
{
J
Jiri Slaby 已提交
1192
	struct cyclades_card *cinfo = dev_id;
L
Linus Torvalds 已提交
1193

1194
	if (unlikely(!cyz_is_loaded(cinfo))) {
L
Linus Torvalds 已提交
1195
#ifdef CY_DEBUG_INTERRUPTS
J
Jiri Slaby 已提交
1196 1197
		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
				"(IRQ%d).\n", irq);
L
Linus Torvalds 已提交
1198
#endif
1199 1200
		return IRQ_NONE;
	}
L
Linus Torvalds 已提交
1201

1202 1203
	/* Handle the interrupts */
	cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1204

1205 1206
	return IRQ_HANDLED;
}				/* cyz_interrupt */
L
Linus Torvalds 已提交
1207

1208
static void cyz_rx_restart(unsigned long arg)
L
Linus Torvalds 已提交
1209
{
1210
	struct cyclades_port *info = (struct cyclades_port *)arg;
1211
	struct cyclades_card *card = info->card;
1212
	int retval;
1213
	__u32 channel = info->line - card->first_line;
1214 1215
	unsigned long flags;

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

1225
#else				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1226

1227
static void cyz_poll(unsigned long arg)
L
Linus Torvalds 已提交
1228
{
1229 1230
	struct cyclades_card *cinfo;
	struct cyclades_port *info;
J
Jiri Slaby 已提交
1231
	unsigned long expires = jiffies + HZ;
J
Jiri Slaby 已提交
1232
	unsigned int port, card;
L
Linus Torvalds 已提交
1233

1234 1235 1236
	for (card = 0; card < NR_CARDS; card++) {
		cinfo = &cy_card[card];

1237
		if (!cy_is_Z(cinfo))
1238
			continue;
1239
		if (!cyz_is_loaded(cinfo))
1240 1241
			continue;

L
Linus Torvalds 已提交
1242
	/* Skip first polling cycle to avoid racing conditions with the FW */
1243 1244 1245 1246
		if (!cinfo->intr_enabled) {
			cinfo->intr_enabled = 1;
			continue;
		}
L
Linus Torvalds 已提交
1247

1248
		cyz_handle_cmd(cinfo);
L
Linus Torvalds 已提交
1249

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

1253
			if (!info->throttle)
1254 1255
				cyz_handle_rx(info);
			cyz_handle_tx(info);
1256 1257
		}
		/* poll every 'cyz_polling_cycle' period */
J
Jiri Slaby 已提交
1258
		expires = jiffies + cyz_polling_cycle;
L
Linus Torvalds 已提交
1259
	}
J
Jiri Slaby 已提交
1260
	mod_timer(&cyz_timerlist, expires);
1261
}				/* cyz_poll */
L
Linus Torvalds 已提交
1262

1263
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1264 1265 1266 1267 1268 1269 1270

/********** 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 已提交
1271
static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1272
{
1273
	struct cyclades_card *card;
1274 1275
	unsigned long flags;
	int retval = 0;
J
Jiri Slaby 已提交
1276
	int channel;
1277
	unsigned long page;
L
Linus Torvalds 已提交
1278

1279
	card = info->card;
1280
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1281

1282 1283 1284
	page = get_zeroed_page(GFP_KERNEL);
	if (!page)
		return -ENOMEM;
L
Linus Torvalds 已提交
1285

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

J
Jiri Slaby 已提交
1288
	if (info->port.flags & ASYNC_INITIALIZED)
1289
		goto errout;
L
Linus Torvalds 已提交
1290

1291
	if (!info->type) {
J
Jiri Slaby 已提交
1292
		set_bit(TTY_IO_ERROR, &tty->flags);
1293 1294
		goto errout;
	}
L
Linus Torvalds 已提交
1295

A
Alan Cox 已提交
1296
	if (info->port.xmit_buf)
1297 1298
		free_page(page);
	else
A
Alan Cox 已提交
1299
		info->port.xmit_buf = (unsigned char *)page;
L
Linus Torvalds 已提交
1300

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

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

1305
	if (!cy_is_Z(card)) {
1306
		channel &= 0x03;
L
Linus Torvalds 已提交
1307

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

1310
		cyy_writeb(info, CyCAR, channel);
L
Linus Torvalds 已提交
1311

1312
		cyy_writeb(info, CyRTPR,
1313 1314
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */
L
Linus Torvalds 已提交
1315

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

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

1320
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
1321
	} else {
1322
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
L
Linus Torvalds 已提交
1323

1324
		if (!cyz_is_loaded(card))
1325
			return -ENODEV;
L
Linus Torvalds 已提交
1326 1327

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1328
		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1329
			"base_addr %p\n", card, channel, card->base_addr);
L
Linus Torvalds 已提交
1330
#endif
1331
		spin_lock_irqsave(&card->card_lock, flags);
L
Linus Torvalds 已提交
1332

1333
		cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
L
Linus Torvalds 已提交
1334 1335
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
1336
		cy_writel(&ch_ctrl->intr_enable,
1337 1338
			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
L
Linus Torvalds 已提交
1339
#else
1340
		cy_writel(&ch_ctrl->intr_enable,
1341 1342
			  C_IN_IOCTLW | C_IN_MDCD);
#endif				/* CONFIG_CYZ_INTR */
L
Linus Torvalds 已提交
1343 1344
#else
#ifdef CONFIG_CYZ_INTR
1345
		cy_writel(&ch_ctrl->intr_enable,
1346 1347
			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
			  C_IN_RXNNDT | C_IN_MDCD);
L
Linus Torvalds 已提交
1348
#else
1349
		cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
1350 1351 1352
#endif				/* CONFIG_CYZ_INTR */
#endif				/* Z_WAKE */

1353
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
1354
		if (retval != 0) {
J
Jiri Slaby 已提交
1355 1356
			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
				"%x\n", info->line, retval);
1357
		}
L
Linus Torvalds 已提交
1358

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

1366 1367
		/* set timeout !!! */
		/* set RTS and DTR !!! */
J
Jiri Slaby 已提交
1368
		tty_port_raise_dtr_rts(&info->port);
L
Linus Torvalds 已提交
1369

1370
		/* enable send, recv, modem !!! */
J
Jiri Slaby 已提交
1371
	}
1372

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

J
Jiri Slaby 已提交
1375 1376 1377 1378 1379 1380 1381 1382 1383
	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 已提交
1384 1385

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1386
	printk(KERN_DEBUG "cyc startup done\n");
L
Linus Torvalds 已提交
1387 1388 1389 1390
#endif
	return 0;

errout:
1391
	spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1392
	free_page(page);
L
Linus Torvalds 已提交
1393
	return retval;
1394
}				/* startup */
L
Linus Torvalds 已提交
1395

1396
static void start_xmit(struct cyclades_port *info)
L
Linus Torvalds 已提交
1397
{
1398
	struct cyclades_card *card = info->card;
1399
	unsigned long flags;
1400
	int channel = info->line - card->first_line;
L
Linus Torvalds 已提交
1401

1402
	if (!cy_is_Z(card)) {
1403
		spin_lock_irqsave(&card->card_lock, flags);
1404 1405
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
1406
		spin_unlock_irqrestore(&card->card_lock, flags);
1407
	} else {
L
Linus Torvalds 已提交
1408
#ifdef CONFIG_CYZ_INTR
1409
		int retval;
L
Linus Torvalds 已提交
1410

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

/*
 * 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 已提交
1428
static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1429
{
1430
	struct cyclades_card *card;
1431 1432
	unsigned long flags;

A
Alan Cox 已提交
1433
	if (!(info->port.flags & ASYNC_INITIALIZED))
1434 1435 1436
		return;

	card = info->card;
1437
	if (!cy_is_Z(card)) {
1438
		spin_lock_irqsave(&card->card_lock, flags);
1439 1440

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

A
Alan Cox 已提交
1443
		if (info->port.xmit_buf) {
1444
			unsigned char *temp;
A
Alan Cox 已提交
1445 1446
			temp = info->port.xmit_buf;
			info->port.xmit_buf = NULL;
1447 1448
			free_page((unsigned long)temp);
		}
1449
		if (tty->termios.c_cflag & HUPCL)
J
Jiri Slaby 已提交
1450 1451
			cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);

1452
		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
1453 1454 1455
		/* it may be appropriate to clear _XMIT at
		   some later date (after testing)!!! */

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

1466
		if (!cyz_is_loaded(card))
1467
			return;
L
Linus Torvalds 已提交
1468

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

A
Alan Cox 已提交
1471
		if (info->port.xmit_buf) {
1472
			unsigned char *temp;
A
Alan Cox 已提交
1473 1474
			temp = info->port.xmit_buf;
			info->port.xmit_buf = NULL;
1475
			free_page((unsigned long)temp);
L
Linus Torvalds 已提交
1476
		}
1477

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

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

1484
		spin_unlock_irqrestore(&card->card_lock, flags);
1485
	}
L
Linus Torvalds 已提交
1486 1487

#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1488
	printk(KERN_DEBUG "cyc shutdown done\n");
L
Linus Torvalds 已提交
1489
#endif
1490
}				/* shutdown */
L
Linus Torvalds 已提交
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501

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

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

J
Jiri Slaby 已提交
1508 1509 1510 1511 1512 1513 1514
	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 已提交
1515
	if (info->line < 0)
1516
		return -ENODEV;
L
Linus Torvalds 已提交
1517

1518 1519 1520 1521
	/* If the card's firmware hasn't been loaded,
	   treat it as absent from the system.  This
	   will make the user pay attention.
	 */
1522
	if (cy_is_Z(info->card)) {
1523
		struct cyclades_card *cinfo = info->card;
1524 1525
		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;

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

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

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

1585 1586 1587
	/*
	 * If the port is the middle of closing, bail out now
	 */
A
Alan Cox 已提交
1588
	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
A
Alan Cox 已提交
1589
		wait_event_interruptible_tty(tty, info->port.close_wait,
A
Alan Cox 已提交
1590 1591
				!(info->port.flags & ASYNC_CLOSING));
		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
1592
	}
L
Linus Torvalds 已提交
1593

1594 1595 1596
	/*
	 * Start up serial port
	 */
J
Jiri Slaby 已提交
1597
	retval = cy_startup(info, tty);
A
Alan Cox 已提交
1598
	if (retval)
1599
		return retval;
L
Linus Torvalds 已提交
1600

J
Jiri Slaby 已提交
1601
	retval = tty_port_block_til_ready(&info->port, tty, filp);
1602
	if (retval) {
L
Linus Torvalds 已提交
1603
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1604 1605
		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
			"with %d\n", retval);
L
Linus Torvalds 已提交
1606
#endif
1607 1608
		return retval;
	}
L
Linus Torvalds 已提交
1609

1610
	info->throttle = 0;
J
Jiri Slaby 已提交
1611
	tty_port_tty_set(&info->port, tty);
L
Linus Torvalds 已提交
1612

1613
#ifdef CY_DEBUG_OPEN
J
Jiri Slaby 已提交
1614
	printk(KERN_DEBUG "cyc:cy_open done\n");
1615 1616 1617
#endif
	return 0;
}				/* cy_open */
L
Linus Torvalds 已提交
1618 1619 1620 1621

/*
 * cy_wait_until_sent() --- wait until the transmitter is empty
 */
1622
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
L
Linus Torvalds 已提交
1623
{
1624
	struct cyclades_card *card;
1625
	struct cyclades_port *info = tty->driver_data;
1626 1627 1628 1629 1630 1631 1632 1633
	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 已提交
1634

1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
	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;
1663

1664
	card = info->card;
1665
	if (!cy_is_Z(card)) {
1666
		while (cyy_readb(info, CySRER) & CyTxRdy) {
1667 1668 1669 1670 1671 1672
			if (msleep_interruptible(jiffies_to_msecs(char_time)))
				break;
			if (timeout && time_after(jiffies, orig_jiffies +
					timeout))
				break;
		}
L
Linus Torvalds 已提交
1673
	}
1674 1675
	/* Run one more char cycle */
	msleep_interruptible(jiffies_to_msecs(char_time * 5));
L
Linus Torvalds 已提交
1676 1677
}

1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698
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);

1699
	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712
					   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 */


1713
static void cy_do_close(struct tty_port *port)
L
Linus Torvalds 已提交
1714
{
1715 1716
	struct cyclades_port *info = container_of(port, struct cyclades_port,
								port);
1717
	struct cyclades_card *card;
1718
	unsigned long flags;
1719
	int channel;
L
Linus Torvalds 已提交
1720

1721
	card = info->card;
1722
	channel = info->line - card->first_line;
1723
	spin_lock_irqsave(&card->card_lock, flags);
1724

1725
	if (!cy_is_Z(card)) {
1726
		/* Stop accepting input */
1727 1728
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
A
Alan Cox 已提交
1729
		if (info->port.flags & ASYNC_INITIALIZED) {
A
Alan Cox 已提交
1730 1731
			/* Waiting for on-board buffers to be empty before
			   closing the port */
1732
			spin_unlock_irqrestore(&card->card_lock, flags);
1733
			cy_wait_until_sent(port->tty, info->timeout);
1734
			spin_lock_irqsave(&card->card_lock, flags);
1735 1736 1737
		}
	} else {
#ifdef Z_WAKE
A
Alan Cox 已提交
1738 1739
		/* Waiting for on-board buffers to be empty before closing
		   the port */
1740
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
1741 1742
		int retval;

1743
		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
1744
			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
1745
			if (retval != 0) {
J
Jiri Slaby 已提交
1746 1747
				printk(KERN_DEBUG "cyc:cy_close retval on "
					"ttyC%d was %x\n", info->line, retval);
1748
			}
1749
			spin_unlock_irqrestore(&card->card_lock, flags);
J
Jiri Slaby 已提交
1750
			wait_for_completion_interruptible(&info->shutdown_wait);
1751
			spin_lock_irqsave(&card->card_lock, flags);
1752
		}
L
Linus Torvalds 已提交
1753
#endif
1754
	}
1755
	spin_unlock_irqrestore(&card->card_lock, flags);
1756 1757
	cy_shutdown(info, port->tty);
}
L
Linus Torvalds 已提交
1758

1759 1760 1761 1762 1763 1764 1765 1766 1767
/*
 * 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);
1768
}				/* cy_close */
L
Linus Torvalds 已提交
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782

/* 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.
 *
 */
1783
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
L
Linus Torvalds 已提交
1784
{
1785
	struct cyclades_port *info = tty->driver_data;
1786 1787
	unsigned long flags;
	int c, ret = 0;
L
Linus Torvalds 已提交
1788 1789

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

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

A
Alan Cox 已提交
1796
	if (!info->port.xmit_buf)
1797
		return 0;
L
Linus Torvalds 已提交
1798

1799
	spin_lock_irqsave(&info->card->card_lock, flags);
1800
	while (1) {
1801 1802
		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
1803 1804 1805 1806

		if (c <= 0)
			break;

A
Alan Cox 已提交
1807
		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
1808 1809 1810 1811 1812 1813 1814
		info->xmit_head = (info->xmit_head + c) &
			(SERIAL_XMIT_SIZE - 1);
		info->xmit_cnt += c;
		buf += c;
		count -= c;
		ret += c;
	}
1815
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1816 1817 1818 1819

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

A
Alan Cox 已提交
1820
	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1821
		start_xmit(info);
A
Alan Cox 已提交
1822

1823 1824
	return ret;
}				/* cy_write */
L
Linus Torvalds 已提交
1825 1826 1827 1828 1829 1830 1831 1832

/*
 * 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.
 */
1833
static int cy_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
1834
{
1835
	struct cyclades_port *info = tty->driver_data;
1836
	unsigned long flags;
L
Linus Torvalds 已提交
1837 1838

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

1842
	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1843
		return 0;
L
Linus Torvalds 已提交
1844

A
Alan Cox 已提交
1845
	if (!info->port.xmit_buf)
1846
		return 0;
L
Linus Torvalds 已提交
1847

1848
	spin_lock_irqsave(&info->card->card_lock, flags);
J
Jiri Slaby 已提交
1849
	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
1850
		spin_unlock_irqrestore(&info->card->card_lock, flags);
1851
		return 0;
1852
	}
L
Linus Torvalds 已提交
1853

A
Alan Cox 已提交
1854
	info->port.xmit_buf[info->xmit_head++] = ch;
1855 1856
	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
	info->xmit_cnt++;
L
Linus Torvalds 已提交
1857 1858
	info->idle_stats.xmit_bytes++;
	info->idle_stats.xmit_idle = jiffies;
1859
	spin_unlock_irqrestore(&info->card->card_lock, flags);
1860
	return 1;
1861
}				/* cy_put_char */
L
Linus Torvalds 已提交
1862 1863 1864

/*
 * This routine is called by the kernel after it has written a
A
Alan Cox 已提交
1865
 * series of characters to the tty device using put_char().
L
Linus Torvalds 已提交
1866
 */
1867
static void cy_flush_chars(struct tty_struct *tty)
L
Linus Torvalds 已提交
1868
{
1869
	struct cyclades_port *info = tty->driver_data;
1870

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

1875 1876
	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
		return;
L
Linus Torvalds 已提交
1877

1878
	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
A
Alan Cox 已提交
1879
			!info->port.xmit_buf)
1880
		return;
L
Linus Torvalds 已提交
1881

1882 1883
	start_xmit(info);
}				/* cy_flush_chars */
L
Linus Torvalds 已提交
1884 1885 1886 1887 1888 1889 1890

/*
 * 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.
 */
1891
static int cy_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
1892
{
1893
	struct cyclades_port *info = tty->driver_data;
1894 1895
	int ret;

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

1900 1901 1902 1903 1904 1905 1906
	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 已提交
1907

1908
static int cy_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1909
{
1910
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
1911

1912 1913 1914
	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
		return 0;

L
Linus Torvalds 已提交
1915
#ifdef Z_EXT_CHARS_IN_BUFFER
1916
	if (!cy_is_Z(info->card)) {
1917
#endif				/* Z_EXT_CHARS_IN_BUFFER */
L
Linus Torvalds 已提交
1918
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1919 1920
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt);
L
Linus Torvalds 已提交
1921
#endif
1922
		return info->xmit_cnt;
L
Linus Torvalds 已提交
1923
#ifdef Z_EXT_CHARS_IN_BUFFER
1924
	} else {
1925
		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1926
		int char_count;
J
Jiri Slaby 已提交
1927
		__u32 tx_put, tx_get, tx_bufsize;
1928

1929 1930 1931
		tx_get = readl(&buf_ctrl->tx_get);
		tx_put = readl(&buf_ctrl->tx_put);
		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1932 1933 1934 1935
		if (tx_put >= tx_get)
			char_count = tx_put - tx_get;
		else
			char_count = tx_put - tx_get + tx_bufsize;
L
Linus Torvalds 已提交
1936
#ifdef CY_DEBUG_IO
J
Jiri Slaby 已提交
1937 1938
		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
			info->line, info->xmit_cnt + char_count);
L
Linus Torvalds 已提交
1939
#endif
J
Jiri Slaby 已提交
1940
		return info->xmit_cnt + char_count;
1941 1942 1943
	}
#endif				/* Z_EXT_CHARS_IN_BUFFER */
}				/* cy_chars_in_buffer */
L
Linus Torvalds 已提交
1944 1945 1946 1947 1948 1949 1950

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

K
Klaus Kudielka 已提交
1951
static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
L
Linus Torvalds 已提交
1952
{
1953
	int co, co_val, bpr;
K
Klaus Kudielka 已提交
1954
	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
1955
			25000000);
L
Linus Torvalds 已提交
1956

1957 1958 1959 1960
	if (baud == 0) {
		info->tbpr = info->tco = info->rbpr = info->rco = 0;
		return;
	}
L
Linus Torvalds 已提交
1961

1962 1963 1964 1965 1966
	/* 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 已提交
1967

1968 1969 1970
	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
	if (bpr > 255)
		bpr = 255;
L
Linus Torvalds 已提交
1971

1972 1973
	info->tbpr = info->rbpr = bpr;
	info->tco = info->rco = co;
L
Linus Torvalds 已提交
1974 1975 1976 1977 1978 1979
}

/*
 * This routine finds or computes the various line characteristics.
 * It used to be called config_setup
 */
J
Jiri Slaby 已提交
1980
static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
L
Linus Torvalds 已提交
1981
{
1982
	struct cyclades_card *card;
1983
	unsigned long flags;
1984
	int channel;
1985 1986 1987 1988
	unsigned cflag, iflag;
	int baud, baud_rate = 0;
	int i;

A
Alan Cox 已提交
1989
	if (info->line == -1)
1990
		return;
A
Alan Cox 已提交
1991

1992 1993
	cflag = tty->termios.c_cflag;
	iflag = tty->termios.c_iflag;
L
Linus Torvalds 已提交
1994

1995 1996 1997
	/*
	 * Set up the tty->alt_speed kludge
	 */
J
Jiri Slaby 已提交
1998 1999 2000 2001 2002 2003 2004 2005
	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;
2006 2007

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

2010
	if (!cy_is_Z(card)) {
2011 2012
		u32 cflags;

2013
		/* baud rate */
J
Jiri Slaby 已提交
2014
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2015
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025
				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 已提交
2026
			if (baud == baud_table[i])
2027 2028
				break;
		}
A
Alan Cox 已提交
2029
		if (i == 20)
2030 2031
			i = 19;	/* CD1400_MAX_SPEED */

A
Alan Cox 已提交
2032
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
				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 已提交
2053
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088
				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 已提交
2089
		if (cflag & CSTOPB)
2090
			info->cor1 |= Cy_2_STOP;
A
Alan Cox 已提交
2091

2092
		if (cflag & PARENB) {
A
Alan Cox 已提交
2093
			if (cflag & PARODD)
2094
				info->cor1 |= CyPARITY_O;
A
Alan Cox 已提交
2095
			else
2096
				info->cor1 |= CyPARITY_E;
A
Alan Cox 已提交
2097
		} else
2098 2099 2100 2101
			info->cor1 |= CyPARITY_NONE;

		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
A
Alan Cox 已提交
2102
			info->port.flags |= ASYNC_CTS_FLOW;
2103 2104
			info->cor2 |= CyCtsAE;
		} else {
A
Alan Cox 已提交
2105
			info->port.flags &= ~ASYNC_CTS_FLOW;
2106 2107 2108
			info->cor2 &= ~CyCtsAE;
		}
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2109
			info->port.flags &= ~ASYNC_CHECK_CD;
2110
		else
A
Alan Cox 已提交
2111
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122

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

2123
		channel &= 0x03;
L
Linus Torvalds 已提交
2124

2125
		spin_lock_irqsave(&card->card_lock, flags);
2126
		cyy_writeb(info, CyCAR, channel);
2127 2128 2129

		/* tx and rx baud rate */

2130 2131 2132 2133
		cyy_writeb(info, CyTCOR, info->tco);
		cyy_writeb(info, CyTBPR, info->tbpr);
		cyy_writeb(info, CyRCOR, info->rco);
		cyy_writeb(info, CyRBPR, info->rbpr);
2134 2135 2136

		/* set line characteristics  according configuration */

2137 2138 2139 2140 2141 2142 2143
		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);
2144

2145 2146
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
				CyCOR3ch);
2147

A
Alan Cox 已提交
2148
		/* !!! Is this needed? */
2149 2150
		cyy_writeb(info, CyCAR, channel);
		cyy_writeb(info, CyRTPR,
2151 2152 2153
			(info->default_timeout ? info->default_timeout : 0x02));
		/* 10ms rx timeout */

2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
		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);
2166

J
Jiri Slaby 已提交
2167 2168 2169 2170
		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 已提交
2171

J
Jiri Slaby 已提交
2172
		clear_bit(TTY_IO_ERROR, &tty->flags);
2173
		spin_unlock_irqrestore(&card->card_lock, flags);
L
Linus Torvalds 已提交
2174 2175

	} else {
2176
		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
K
Klaus Kudielka 已提交
2177
		__u32 sw_flow;
2178
		int retval;
L
Linus Torvalds 已提交
2179

2180
		if (!cyz_is_loaded(card))
2181
			return;
L
Linus Torvalds 已提交
2182

2183
		/* baud rate */
J
Jiri Slaby 已提交
2184
		baud = tty_get_baud_rate(tty);
A
Alan Cox 已提交
2185
		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199
				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 已提交
2200
		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2201 2202 2203 2204 2205 2206 2207 2208 2209 2210
				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 已提交
2211

2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228
		/* 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,
2229
				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
2230 2231
		} else {
			cy_writel(&ch_ctrl->comm_data_l,
2232
				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
2233 2234
		}
		if (cflag & PARENB) {
A
Alan Cox 已提交
2235
			if (cflag & PARODD)
2236
				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
A
Alan Cox 已提交
2237
			else
2238
				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
A
Alan Cox 已提交
2239
		} else
2240
			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
L
Linus Torvalds 已提交
2241

2242 2243 2244
		/* CTS flow control flag */
		if (cflag & CRTSCTS) {
			cy_writel(&ch_ctrl->hw_flow,
2245
				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
2246
		} else {
2247 2248
			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
					~(C_RS_CTS | C_RS_RTS));
2249 2250 2251
		}
		/* As the HW flow control is done in firmware, the driver
		   doesn't need to care about it */
A
Alan Cox 已提交
2252
		info->port.flags &= ~ASYNC_CTS_FLOW;
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262

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

2263
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
2264
		if (retval != 0) {
J
Jiri Slaby 已提交
2265 2266
			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
				"was %x\n", info->line, retval);
2267 2268 2269
		}

		/* CD sensitivity */
A
Alan Cox 已提交
2270
		if (cflag & CLOCAL)
A
Alan Cox 已提交
2271
			info->port.flags &= ~ASYNC_CHECK_CD;
A
Alan Cox 已提交
2272
		else
A
Alan Cox 已提交
2273
			info->port.flags |= ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
2274

2275 2276
		if (baud == 0) {	/* baud rate is zero, turn off line */
			cy_writel(&ch_ctrl->rs_control,
2277
				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
L
Linus Torvalds 已提交
2278
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2279
			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
L
Linus Torvalds 已提交
2280
#endif
2281 2282
		} else {
			cy_writel(&ch_ctrl->rs_control,
2283
				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
L
Linus Torvalds 已提交
2284
#ifdef CY_DEBUG_DTR
J
Jiri Slaby 已提交
2285
			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
L
Linus Torvalds 已提交
2286
#endif
2287
		}
L
Linus Torvalds 已提交
2288

A
Alan Cox 已提交
2289
		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
2290
		if (retval != 0) {
J
Jiri Slaby 已提交
2291 2292
			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
				"was %x\n", info->line, retval);
2293
		}
L
Linus Torvalds 已提交
2294

J
Jiri Slaby 已提交
2295
		clear_bit(TTY_IO_ERROR, &tty->flags);
L
Linus Torvalds 已提交
2296
	}
2297
}				/* set_line_char */
L
Linus Torvalds 已提交
2298

J
Jiri Slaby 已提交
2299
static int cy_get_serial_info(struct cyclades_port *info,
A
Alan Cox 已提交
2300
		struct serial_struct __user *retinfo)
L
Linus Torvalds 已提交
2301
{
2302
	struct cyclades_card *cinfo = info->card;
J
Jiri Slaby 已提交
2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315
	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,		/*!!! */
	};
2316
	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
J
Jiri Slaby 已提交
2317
}
L
Linus Torvalds 已提交
2318 2319

static int
J
Jiri Slaby 已提交
2320
cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
A
Alan Cox 已提交
2321
		struct serial_struct __user *new_info)
L
Linus Torvalds 已提交
2322
{
2323
	struct serial_struct new_serial;
A
Alan Cox 已提交
2324
	int ret;
2325 2326 2327 2328

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

A
Alan Cox 已提交
2329
	mutex_lock(&info->port.mutex);
2330
	if (!capable(CAP_SYS_ADMIN)) {
A
Alan Cox 已提交
2331
		if (new_serial.close_delay != info->port.close_delay ||
2332 2333 2334
				new_serial.baud_base != info->baud ||
				(new_serial.flags & ASYNC_FLAGS &
					~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
2335
				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
A
Alan Cox 已提交
2336 2337
		{
			mutex_unlock(&info->port.mutex);
2338
			return -EPERM;
A
Alan Cox 已提交
2339
		}
A
Alan Cox 已提交
2340
		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353
				(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 已提交
2354
	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
2355
			(new_serial.flags & ASYNC_FLAGS);
A
Alan Cox 已提交
2356 2357
	info->port.close_delay = new_serial.close_delay * HZ / 100;
	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
L
Linus Torvalds 已提交
2358 2359

check_and_exit:
A
Alan Cox 已提交
2360
	if (info->port.flags & ASYNC_INITIALIZED) {
J
Jiri Slaby 已提交
2361
		cy_set_line_char(info, tty);
A
Alan Cox 已提交
2362
		ret = 0;
2363
	} else {
A
Alan Cox 已提交
2364
		ret = cy_startup(info, tty);
2365
	}
A
Alan Cox 已提交
2366 2367
	mutex_unlock(&info->port.mutex);
	return ret;
2368
}				/* set_serial_info */
L
Linus Torvalds 已提交
2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379

/*
 * 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 已提交
2380
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
L
Linus Torvalds 已提交
2381
{
2382
	struct cyclades_card *card = info->card;
2383 2384
	unsigned int result;
	unsigned long flags;
2385
	u8 status;
L
Linus Torvalds 已提交
2386

2387
	if (!cy_is_Z(card)) {
2388
		spin_lock_irqsave(&card->card_lock, flags);
2389
		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
2390
		spin_unlock_irqrestore(&card->card_lock, flags);
2391 2392 2393 2394 2395
		result = (status ? 0 : TIOCSER_TEMT);
	} else {
		/* Not supported yet */
		return -EINVAL;
	}
2396
	return put_user(result, value);
L
Linus Torvalds 已提交
2397 2398
}

2399
static int cy_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
2400
{
2401
	struct cyclades_port *info = tty->driver_data;
2402
	struct cyclades_card *card;
2403
	int result;
2404

2405
	if (serial_paranoia_check(info, tty->name, __func__))
2406
		return -ENODEV;
L
Linus Torvalds 已提交
2407

2408
	card = info->card;
J
Jiri Slaby 已提交
2409

2410
	if (!cy_is_Z(card)) {
J
Jiri Slaby 已提交
2411
		unsigned long flags;
2412 2413
		int channel = info->line - card->first_line;
		u8 status;
L
Linus Torvalds 已提交
2414

2415
		spin_lock_irqsave(&card->card_lock, flags);
2416 2417 2418
		cyy_writeb(info, CyCAR, channel & 0x03);
		status = cyy_readb(info, CyMSVR1);
		status |= cyy_readb(info, CyMSVR2);
2419
		spin_unlock_irqrestore(&card->card_lock, flags);
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431

		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 已提交
2432
	} else {
J
Jiri Slaby 已提交
2433 2434 2435 2436 2437
		u32 lstatus;

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

J
Jiri Slaby 已提交
2440 2441 2442 2443 2444 2445 2446
		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);
2447
	}
J
Jiri Slaby 已提交
2448
end:
2449 2450
	return result;
}				/* cy_tiomget */
L
Linus Torvalds 已提交
2451 2452

static int
2453
cy_tiocmset(struct tty_struct *tty,
2454
		unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
2455
{
2456
	struct cyclades_port *info = tty->driver_data;
2457
	struct cyclades_card *card;
2458 2459
	unsigned long flags;

2460
	if (serial_paranoia_check(info, tty->name, __func__))
2461 2462 2463
		return -ENODEV;

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

/*
 * cy_break() --- routine which turns the break handling on or off
 */
A
Alan Cox 已提交
2509
static int cy_break(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
2510
{
2511
	struct cyclades_port *info = tty->driver_data;
2512
	struct cyclades_card *card;
2513
	unsigned long flags;
A
Alan Cox 已提交
2514
	int retval = 0;
L
Linus Torvalds 已提交
2515

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

2519 2520 2521
	card = info->card;

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

2569
static int set_threshold(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2570
{
2571
	struct cyclades_card *card = info->card;
2572
	unsigned long flags;
L
Linus Torvalds 已提交
2573

2574
	if (!cy_is_Z(card)) {
2575 2576
		info->cor3 &= ~CyREC_FIFO;
		info->cor3 |= value & CyREC_FIFO;
L
Linus Torvalds 已提交
2577

2578
		spin_lock_irqsave(&card->card_lock, flags);
2579 2580
		cyy_writeb(info, CyCOR3, info->cor3);
		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
2581
		spin_unlock_irqrestore(&card->card_lock, flags);
2582 2583 2584
	}
	return 0;
}				/* set_threshold */
L
Linus Torvalds 已提交
2585

A
Alan Cox 已提交
2586 2587
static int get_threshold(struct cyclades_port *info,
						unsigned long __user *value)
L
Linus Torvalds 已提交
2588
{
2589
	struct cyclades_card *card = info->card;
L
Linus Torvalds 已提交
2590

2591
	if (!cy_is_Z(card)) {
2592
		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
2593 2594
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2595
	return 0;
2596
}				/* get_threshold */
L
Linus Torvalds 已提交
2597

2598
static int set_timeout(struct cyclades_port *info, unsigned long value)
L
Linus Torvalds 已提交
2599
{
2600
	struct cyclades_card *card = info->card;
2601
	unsigned long flags;
L
Linus Torvalds 已提交
2602

2603
	if (!cy_is_Z(card)) {
2604
		spin_lock_irqsave(&card->card_lock, flags);
2605
		cyy_writeb(info, CyRTPR, value & 0xff);
2606
		spin_unlock_irqrestore(&card->card_lock, flags);
2607 2608 2609
	}
	return 0;
}				/* set_timeout */
L
Linus Torvalds 已提交
2610

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

2616
	if (!cy_is_Z(card)) {
2617
		u8 tmp = cyy_readb(info, CyRTPR);
2618 2619
		return put_user(tmp, value);
	}
J
Jiri Slaby 已提交
2620
	return 0;
2621
}				/* get_timeout */
L
Linus Torvalds 已提交
2622

J
Jiri Slaby 已提交
2623 2624
static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
		struct cyclades_icount *cprev)
L
Linus Torvalds 已提交
2625
{
J
Jiri Slaby 已提交
2626 2627 2628
	struct cyclades_icount cnow;
	unsigned long flags;
	int ret;
L
Linus Torvalds 已提交
2629

J
Jiri Slaby 已提交
2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
	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 已提交
2643 2644 2645 2646 2647 2648 2649

/*
 * 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
2650
cy_ioctl(struct tty_struct *tty,
2651
	 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2652
{
2653
	struct cyclades_port *info = tty->driver_data;
J
Jiri Slaby 已提交
2654
	struct cyclades_icount cnow;	/* kernel counter temps */
2655 2656 2657 2658 2659 2660
	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 已提交
2661 2662

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

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

2754 2755 2756 2757 2758 2759 2760 2761 2762
		/*
		 * 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 已提交
2763 2764

#ifdef CY_DEBUG_OTHER
J
Jiri Slaby 已提交
2765
	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
L
Linus Torvalds 已提交
2766
#endif
2767 2768
	return ret_val;
}				/* cy_ioctl */
L
Linus Torvalds 已提交
2769

2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794
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 已提交
2795 2796 2797 2798 2799 2800
/*
 * 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.
 */
2801
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
L
Linus Torvalds 已提交
2802
{
2803
	struct cyclades_port *info = tty->driver_data;
L
Linus Torvalds 已提交
2804 2805

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

J
Jiri Slaby 已提交
2809
	cy_set_line_char(info, tty);
2810 2811

	if ((old_termios->c_cflag & CRTSCTS) &&
2812
			!(tty->termios.c_cflag & CRTSCTS)) {
2813 2814 2815
		tty->hw_stopped = 0;
		cy_start(tty);
	}
L
Linus Torvalds 已提交
2816
#if 0
2817 2818 2819 2820 2821 2822 2823
	/*
	 * 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) &&
2824
	    (tty->termios.c_cflag & CLOCAL))
A
Alan Cox 已提交
2825
		wake_up_interruptible(&info->port.open_wait);
L
Linus Torvalds 已提交
2826
#endif
2827
}				/* cy_set_termios */
L
Linus Torvalds 已提交
2828 2829 2830 2831

/* This function is used to send a high-priority XON/XOFF character to
   the device.
*/
2832
static void cy_send_xchar(struct tty_struct *tty, char ch)
L
Linus Torvalds 已提交
2833
{
2834
	struct cyclades_port *info = tty->driver_data;
2835 2836
	struct cyclades_card *card;
	int channel;
L
Linus Torvalds 已提交
2837

2838
	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
L
Linus Torvalds 已提交
2839 2840
		return;

2841
	info->x_char = ch;
L
Linus Torvalds 已提交
2842 2843

	if (ch)
2844
		cy_start(tty);
L
Linus Torvalds 已提交
2845 2846

	card = info->card;
2847
	channel = info->line - card->first_line;
L
Linus Torvalds 已提交
2848

2849
	if (cy_is_Z(card)) {
2850
		if (ch == STOP_CHAR(tty))
2851
			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
2852
		else if (ch == START_CHAR(tty))
2853
			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
L
Linus Torvalds 已提交
2854 2855 2856 2857 2858 2859 2860
	}
}

/* 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.
 */
2861
static void cy_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2862
{
2863
	struct cyclades_port *info = tty->driver_data;
2864
	struct cyclades_card *card;
2865
	unsigned long flags;
L
Linus Torvalds 已提交
2866 2867

#ifdef CY_DEBUG_THROTTLE
2868
	char buf[64];
L
Linus Torvalds 已提交
2869

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

A
Alan Cox 已提交
2874
	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2875 2876 2877 2878 2879
		return;

	card = info->card;

	if (I_IXOFF(tty)) {
2880
		if (!cy_is_Z(card))
2881 2882 2883 2884
			cy_send_xchar(tty, STOP_CHAR(tty));
		else
			info->throttle = 1;
	}
L
Linus Torvalds 已提交
2885

2886
	if (tty->termios.c_cflag & CRTSCTS) {
2887
		if (!cy_is_Z(card)) {
2888
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2889
			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
2890
			spin_unlock_irqrestore(&card->card_lock, flags);
2891 2892 2893 2894 2895
		} else {
			info->throttle = 1;
		}
	}
}				/* cy_throttle */
L
Linus Torvalds 已提交
2896 2897 2898 2899 2900 2901

/*
 * 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.
 */
2902
static void cy_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
2903
{
2904
	struct cyclades_port *info = tty->driver_data;
2905
	struct cyclades_card *card;
2906
	unsigned long flags;
L
Linus Torvalds 已提交
2907 2908

#ifdef CY_DEBUG_THROTTLE
2909 2910
	char buf[64];

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

A
Alan Cox 已提交
2915
	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2916
		return;
L
Linus Torvalds 已提交
2917

2918 2919 2920 2921 2922
	if (I_IXOFF(tty)) {
		if (info->x_char)
			info->x_char = 0;
		else
			cy_send_xchar(tty, START_CHAR(tty));
L
Linus Torvalds 已提交
2923 2924
	}

2925
	if (tty->termios.c_cflag & CRTSCTS) {
2926
		card = info->card;
2927
		if (!cy_is_Z(card)) {
2928
			spin_lock_irqsave(&card->card_lock, flags);
J
Jiri Slaby 已提交
2929
			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
2930
			spin_unlock_irqrestore(&card->card_lock, flags);
2931 2932 2933 2934 2935
		} else {
			info->throttle = 0;
		}
	}
}				/* cy_unthrottle */
L
Linus Torvalds 已提交
2936 2937 2938 2939

/* cy_start and cy_stop provide software output flow control as a
   function of XON/XOFF, software CTS, and other such stuff.
*/
2940
static void cy_stop(struct tty_struct *tty)
L
Linus Torvalds 已提交
2941
{
2942
	struct cyclades_card *cinfo;
2943
	struct cyclades_port *info = tty->driver_data;
2944
	int channel;
2945
	unsigned long flags;
L
Linus Torvalds 已提交
2946 2947

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

2951 2952
	if (serial_paranoia_check(info, tty->name, "cy_stop"))
		return;
L
Linus Torvalds 已提交
2953

2954
	cinfo = info->card;
2955
	channel = info->line - cinfo->first_line;
2956
	if (!cy_is_Z(cinfo)) {
2957
		spin_lock_irqsave(&cinfo->card_lock, flags);
2958 2959
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
2960
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2961 2962
	}
}				/* cy_stop */
L
Linus Torvalds 已提交
2963

2964
static void cy_start(struct tty_struct *tty)
L
Linus Torvalds 已提交
2965
{
2966
	struct cyclades_card *cinfo;
2967
	struct cyclades_port *info = tty->driver_data;
2968
	int channel;
2969
	unsigned long flags;
L
Linus Torvalds 已提交
2970 2971

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

2975 2976
	if (serial_paranoia_check(info, tty->name, "cy_start"))
		return;
L
Linus Torvalds 已提交
2977

2978
	cinfo = info->card;
2979
	channel = info->line - cinfo->first_line;
2980
	if (!cy_is_Z(cinfo)) {
2981
		spin_lock_irqsave(&cinfo->card_lock, flags);
2982 2983
		cyy_writeb(info, CyCAR, channel & 0x03);
		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
2984
		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2985 2986
	}
}				/* cy_start */
L
Linus Torvalds 已提交
2987 2988 2989 2990

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

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

2999 3000
	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
		return;
L
Linus Torvalds 已提交
3001

3002
	cy_flush_buffer(tty);
J
Jiri Slaby 已提交
3003
	cy_shutdown(info, tty);
J
Jiri Slaby 已提交
3004
	tty_port_hangup(&info->port);
3005
}				/* cy_hangup */
L
Linus Torvalds 已提交
3006

J
Jiri Slaby 已提交
3007 3008 3009 3010 3011 3012 3013 3014 3015 3016
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);
3017 3018
	cyy_writeb(info, CyCAR, channel & 0x03);
	cd = cyy_readb(info, CyMSVR1) & CyDCD;
J
Jiri Slaby 已提交
3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031
	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 已提交
3032 3033
	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
J
Jiri Slaby 已提交
3034 3035 3036 3037 3038 3039 3040 3041
	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);

3042
	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
J
Jiri Slaby 已提交
3043 3044 3045 3046 3047 3048 3049
}

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

3054
	rs = readl(&ch_ctrl->rs_control);
J
Jiri Slaby 已提交
3055 3056 3057 3058
	if (raise)
		rs |= C_RS_RTS | C_RS_DTR;
	else
		rs &= ~(C_RS_RTS | C_RS_DTR);
3059
	cy_writel(&ch_ctrl->rs_control, rs);
J
Jiri Slaby 已提交
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071
	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,
3072
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3073 3074 3075 3076 3077
};

static const struct tty_port_operations cyz_port_ops = {
	.carrier_raised = cyz_carrier_raised,
	.dtr_rts = cyz_dtr_rts,
3078
	.shutdown = cy_do_close,
J
Jiri Slaby 已提交
3079 3080
};

L
Linus Torvalds 已提交
3081 3082 3083 3084 3085 3086 3087 3088
/*
 * ---------------------------------------------------------------------
 * cy_init() and friends
 *
 * cy_init() is called at boot-time to initialize the serial driver.
 * ---------------------------------------------------------------------
 */

B
Bill Pemberton 已提交
3089
static int cy_init_card(struct cyclades_card *cinfo)
3090 3091
{
	struct cyclades_port *info;
3092
	unsigned int channel, port;
3093

3094
	spin_lock_init(&cinfo->card_lock);
J
Jiri Slaby 已提交
3095
	cinfo->intr_enabled = 0;
3096

J
Jiri Slaby 已提交
3097 3098
	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
			GFP_KERNEL);
J
Jiri Slaby 已提交
3099 3100 3101 3102 3103
	if (cinfo->ports == NULL) {
		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
		return -ENOMEM;
	}

3104 3105 3106
	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
			channel++, port++) {
		info = &cinfo->ports[channel];
A
Alan Cox 已提交
3107
		tty_port_init(&info->port);
3108
		info->magic = CYCLADES_MAGIC;
3109
		info->card = cinfo;
3110 3111
		info->line = port;

A
Alan Cox 已提交
3112 3113
		info->port.closing_wait = CLOSING_WAIT_DELAY;
		info->port.close_delay = 5 * HZ / 10;
A
Alan Cox 已提交
3114
		info->port.flags = STD_COM_FLAGS;
J
Jiri Slaby 已提交
3115
		init_completion(&info->shutdown_wait);
3116

3117
		if (cy_is_Z(cinfo)) {
3118 3119 3120
			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
			struct ZFW_CTRL *zfw_ctrl;

J
Jiri Slaby 已提交
3121
			info->port.ops = &cyz_port_ops;
3122
			info->type = PORT_STARTECH;
3123 3124 3125 3126 3127 3128

			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 已提交
3129
			if (cinfo->hw_ver == ZO_V1)
3130 3131
				info->xmit_fifo_size = CYZ_FIFO_SIZE;
			else
3132
				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
3133
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3134 3135
			setup_timer(&cyz_rx_full_timer[port],
				cyz_rx_restart, (unsigned long)info);
3136
#endif
3137
		} else {
3138
			unsigned short chip_number;
J
Jiri Slaby 已提交
3139
			int index = cinfo->bus_index;
3140

J
Jiri Slaby 已提交
3141
			info->port.ops = &cyy_port_ops;
3142 3143
			info->type = PORT_CIRRUS;
			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
3144
			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
3145 3146
			info->cor2 = CyETC;
			info->cor3 = 0x08;	/* _very_ small rcv threshold */
3147

3148
			chip_number = channel / CyPORTS_PER_CHIP;
3149 3150 3151
			info->u.cyy.base_addr = cinfo->base_addr +
				(cy_chip_offset[chip_number] << index);
			info->chip_rev = cyy_readb(info, CyGFRCR);
A
Alan Cox 已提交
3152 3153

			if (info->chip_rev >= CD1400_REV_J) {
3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166
				/* 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;
			}
3167 3168
			info->read_status_mask = CyTIMEOUT | CySPECHAR |
				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3169
		}
3170

3171
	}
3172 3173

#ifndef CONFIG_CYZ_INTR
3174
	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
3175 3176 3177 3178 3179 3180
		mod_timer(&cyz_timerlist, jiffies + 1);
#ifdef CY_PCI_DEBUG
		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
#endif
	}
#endif
J
Jiri Slaby 已提交
3181
	return 0;
3182 3183
}

L
Linus Torvalds 已提交
3184 3185
/* initialize chips on Cyclom-Y card -- return number of valid
   chips (which is number of ports/4) */
B
Bill Pemberton 已提交
3186
static unsigned short cyy_init_card(void __iomem *true_base_addr,
3187
		int index)
L
Linus Torvalds 已提交
3188
{
3189 3190 3191 3192 3193 3194 3195 3196 3197
	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 已提交
3198 3199
	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
							chip_number++) {
3200 3201 3202
		base_addr =
		    true_base_addr + (cy_chip_offset[chip_number] << index);
		mdelay(1);
3203
		if (readb(base_addr + (CyCCR << index)) != 0x00) {
3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219
			/*************
			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.
		 */
3220
		if (chip_number == 4 && readb(true_base_addr +
3221 3222 3223 3224 3225 3226 3227 3228
				(cy_chip_offset[0] << index) +
				(CyGFRCR << index)) == 0) {
			return chip_number;
		}

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

3229
		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
3230 3231 3232 3233 3234 3235 3236
			/*
			   printk(" chip #%d at %#6lx is not responding ",
			   chip_number, (unsigned long)base_addr);
			   printk("(GFRCR stayed 0)\n",
			 */
			return chip_number;
		}
3237
		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247
				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);
3248
		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
3249 3250 3251 3252 3253 3254 3255 3256
			/* 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 已提交
3257

3258 3259 3260
		/*
		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
		   chip_number, (unsigned long)base_addr,
3261
		   readb(base_addr+(CyGFRCR<<index)));
3262 3263 3264 3265
		 */
	}
	return chip_number;
}				/* cyy_init_card */
L
Linus Torvalds 已提交
3266 3267 3268 3269 3270 3271 3272

/*
 * ---------------------------------------------------------------------
 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
 * sets global variables and return the number of ISA boards found.
 * ---------------------------------------------------------------------
 */
3273
static int __init cy_detect_isa(void)
L
Linus Torvalds 已提交
3274 3275
{
#ifdef CONFIG_ISA
3276
	struct cyclades_card *card;
3277 3278
	unsigned short cy_isa_irq, nboard;
	void __iomem *cy_isa_address;
J
Jiri Slaby 已提交
3279
	unsigned short i, j, k, cy_isa_nchan;
3280
	int isparam = 0;
L
Linus Torvalds 已提交
3281

3282
	nboard = 0;
L
Linus Torvalds 已提交
3283 3284

	/* Check for module parameters */
3285 3286 3287 3288 3289 3290 3291
	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 已提交
3292 3293
	}

3294 3295 3296
	/* 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 已提交
3297
		if (isa_address == 0x0000)
J
Jiri Slaby 已提交
3298
			return nboard;
L
Linus Torvalds 已提交
3299

3300
		/* probe for CD1400... */
3301
		cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
J
Jiri Slaby 已提交
3302 3303 3304 3305 3306
		if (cy_isa_address == NULL) {
			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
					"address\n");
			continue;
		}
3307 3308 3309
		cy_isa_nchan = CyPORTS_PER_CHIP *
			cyy_init_card(cy_isa_address, 0);
		if (cy_isa_nchan == 0) {
J
Jiri Slaby 已提交
3310
			iounmap(cy_isa_address);
3311 3312
			continue;
		}
3313

R
Roel Kluin 已提交
3314
		if (isparam && i < NR_CARDS && irq[i])
3315
			cy_isa_irq = irq[i];
L
Linus Torvalds 已提交
3316
		else
3317 3318 3319
			/* 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 已提交
3320 3321
			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
				"IRQ could not be detected.\n",
3322
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3323
			iounmap(cy_isa_address);
3324 3325 3326 3327
			continue;
		}

		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
J
Jiri Slaby 已提交
3328 3329 3330
			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",
3331
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3332
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3333
			return nboard;
3334 3335 3336
		}
		/* fill the next cy_card structure available */
		for (j = 0; j < NR_CARDS; j++) {
3337 3338
			card = &cy_card[j];
			if (card->base_addr == NULL)
3339 3340 3341
				break;
		}
		if (j == NR_CARDS) {	/* no more cy_cards available */
J
Jiri Slaby 已提交
3342 3343 3344
			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",
3345
				(unsigned long)cy_isa_address);
J
Jiri Slaby 已提交
3346
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3347
			return nboard;
3348 3349 3350 3351
		}

		/* allocate IRQ */
		if (request_irq(cy_isa_irq, cyy_interrupt,
3352
				0, "Cyclom-Y", card)) {
J
Jiri Slaby 已提交
3353 3354 3355
			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 已提交
3356
			iounmap(cy_isa_address);
J
Jiri Slaby 已提交
3357
			return nboard;
3358 3359 3360
		}

		/* set cy_card */
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
		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 已提交
3371 3372 3373
			iounmap(cy_isa_address);
			continue;
		}
3374 3375
		nboard++;

J
Jiri Slaby 已提交
3376 3377
		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
			"%d channels starting from port %d\n",
3378 3379
			j + 1, (unsigned long)cy_isa_address,
			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
J
Jiri Slaby 已提交
3380 3381
			cy_isa_irq, cy_isa_nchan, cy_next_channel);

J
Jiri Slaby 已提交
3382 3383 3384 3385
		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);
3386 3387
		cy_next_channel += cy_isa_nchan;
	}
J
Jiri Slaby 已提交
3388
	return nboard;
L
Linus Torvalds 已提交
3389
#else
J
Jiri Slaby 已提交
3390
	return 0;
3391 3392
#endif				/* CONFIG_ISA */
}				/* cy_detect_isa */
L
Linus Torvalds 已提交
3393

J
Jiri Slaby 已提交
3394
#ifdef CONFIG_PCI
B
Bill Pemberton 已提交
3395
static inline int cyc_isfwstr(const char *str, unsigned int size)
3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
{
	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 已提交
3410
static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3411 3412 3413 3414 3415 3416 3417 3418
		unsigned int size)
{
	for (; size > 0; size--) {
		cy_writel(fpga, *data++);
		udelay(10);
	}
}

B
Bill Pemberton 已提交
3419
static void plx_init(struct pci_dev *pdev, int irq,
3420
		struct RUNTIME_9060 __iomem *addr)
L
Linus Torvalds 已提交
3421
{
3422
	/* Reset PLX */
3423
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
3424
	udelay(100L);
3425
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
3426 3427

	/* Reload Config. Registers from EEPROM */
3428
	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3429
	udelay(100L);
3430 3431 3432 3433 3434 3435 3436 3437 3438
	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 已提交
3439
static int __cyz_load_fw(const struct firmware *fw,
3440 3441 3442
		const char *name, const u32 mailbox, void __iomem *base,
		void __iomem *fpga)
{
3443 3444 3445 3446
	const void *ptr = fw->data;
	const struct zfile_header *h = ptr;
	const struct zfile_config *c, *cs;
	const struct zfile_block *b, *bs;
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 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515
	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 已提交
3516
static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3517 3518 3519 3520 3521 3522
		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 已提交
3523
	void __iomem *tmp;
J
Jiri Slaby 已提交
3524
	u32 mailbox, status, nchan;
3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535
	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 */
3536
	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554
		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);

3555
	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570
		/* 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;
3571
		if (!__cyz_fpga_loaded(ctl_addr)) {
3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584
			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 已提交
3585
	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3586 3587 3588 3589
		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 已提交
3590
		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629
			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");

3630
			if (__cyz_fpga_loaded(ctl_addr))
3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644
				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 已提交
3645
	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3646
	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
J
Jiri Slaby 已提交
3647
		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3648

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

3654
		if (__cyz_fpga_loaded(ctl_addr))
3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674
			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 已提交
3675
	return nchan;
3676 3677 3678 3679
err_rel:
	release_firmware(fw);
err:
	return retval;
L
Linus Torvalds 已提交
3680 3681
}

B
Bill Pemberton 已提交
3682
static int cy_pci_probe(struct pci_dev *pdev,
J
Jiri Slaby 已提交
3683
		const struct pci_device_id *ent)
L
Linus Torvalds 已提交
3684
{
3685
	struct cyclades_card *card;
J
Jiri Slaby 已提交
3686 3687
	void __iomem *addr0 = NULL, *addr2 = NULL;
	char *card_name = NULL;
J
Jiri Slaby 已提交
3688
	u32 uninitialized_var(mailbox);
J
Jiri Slaby 已提交
3689
	unsigned int device_id, nchan = 0, card_no, i, j;
J
Jiri Slaby 已提交
3690 3691
	unsigned char plx_ver;
	int retval, irq;
3692

J
Jiri Slaby 已提交
3693 3694 3695
	retval = pci_enable_device(pdev);
	if (retval) {
		dev_err(&pdev->dev, "cannot enable device\n");
J
Jiri Slaby 已提交
3696
		goto err;
J
Jiri Slaby 已提交
3697
	}
L
Linus Torvalds 已提交
3698

J
Jiri Slaby 已提交
3699
	/* read PCI configuration area */
J
Jiri Slaby 已提交
3700
	irq = pdev->irq;
J
Jiri Slaby 已提交
3701
	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
L
Linus Torvalds 已提交
3702

J
Jiri Slaby 已提交
3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730
#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 已提交
3731 3732
	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
J
Jiri Slaby 已提交
3733
		card_name = "Cyclom-Y";
L
Linus Torvalds 已提交
3734

J
Jiri Slaby 已提交
3735 3736
		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Yctl);
J
Jiri Slaby 已提交
3737 3738 3739
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
J
Jiri Slaby 已提交
3740
		}
J
Jiri Slaby 已提交
3741 3742
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				CyPCI_Ywin);
J
Jiri Slaby 已提交
3743 3744 3745
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3746
		}
L
Linus Torvalds 已提交
3747

J
Jiri Slaby 已提交
3748 3749
		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
		if (nchan == 0) {
J
Jiri Slaby 已提交
3750 3751
			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
					"Serial-Modules\n");
3752
			goto err_unmap;
J
Jiri Slaby 已提交
3753 3754
		}
	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
J
Jiri Slaby 已提交
3755
		struct RUNTIME_9060 __iomem *ctl_addr;
J
Jiri Slaby 已提交
3756

J
Jiri Slaby 已提交
3757 3758
		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
				CyPCI_Zctl);
J
Jiri Slaby 已提交
3759 3760 3761 3762
		if (addr0 == NULL) {
			dev_err(&pdev->dev, "can't remap ctl region\n");
			goto err_reg;
		}
J
Jiri Slaby 已提交
3763 3764

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

3768
		plx_init(pdev, irq, addr0);
3769

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

J
Jiri Slaby 已提交
3772 3773
		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
J
Jiri Slaby 已提交
3774 3775 3776
		if (addr2 == NULL) {
			dev_err(&pdev->dev, "can't remap base region\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3777 3778 3779
		}

		if (mailbox == ZE_V1) {
J
Jiri Slaby 已提交
3780
			card_name = "Cyclades-Ze";
J
Jiri Slaby 已提交
3781
		} else {
J
Jiri Slaby 已提交
3782
			card_name = "Cyclades-8Zo";
L
Linus Torvalds 已提交
3783
#ifdef CY_PCI_DEBUG
J
Jiri Slaby 已提交
3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796
			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 已提交
3797
#endif
J
Jiri Slaby 已提交
3798 3799 3800 3801 3802 3803
			/* 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 已提交
3804
		}
3805 3806

		retval = cyz_load_fw(pdev, addr2, addr0, irq);
J
Jiri Slaby 已提交
3807
		if (retval <= 0)
3808
			goto err_unmap;
J
Jiri Slaby 已提交
3809
		nchan = retval;
J
Jiri Slaby 已提交
3810 3811 3812 3813 3814 3815 3816 3817 3818 3819
	}

	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++) {
3820 3821
		card = &cy_card[card_no];
		if (card->base_addr == NULL)
J
Jiri Slaby 已提交
3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834
			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,
3835
				IRQF_SHARED, "Cyclom-Y", card);
J
Jiri Slaby 已提交
3836 3837 3838
		if (retval) {
			dev_err(&pdev->dev, "could not allocate IRQ\n");
			goto err_unmap;
J
Jiri Slaby 已提交
3839
		}
3840
		card->num_chips = nchan / CyPORTS_PER_CHIP;
J
Jiri Slaby 已提交
3841
	} else {
3842 3843 3844 3845 3846
		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
		struct ZFW_CTRL __iomem *zfw_ctrl;

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

3847 3848 3849
		card->hw_ver = mailbox;
		card->num_chips = (unsigned int)-1;
		card->board_ctrl = &zfw_ctrl->board_ctrl;
3850
#ifdef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
3851
		/* allocate IRQ only if board has an IRQ */
J
Jiri Slaby 已提交
3852 3853
		if (irq != 0 && irq != 255) {
			retval = request_irq(irq, cyz_interrupt,
3854
					IRQF_SHARED, "Cyclades-Z", card);
J
Jiri Slaby 已提交
3855
			if (retval) {
J
Jiri Slaby 已提交
3856
				dev_err(&pdev->dev, "could not allocate IRQ\n");
J
Jiri Slaby 已提交
3857
				goto err_unmap;
3858
			}
J
Jiri Slaby 已提交
3859
		}
3860
#endif				/* CONFIG_CYZ_INTR */
J
Jiri Slaby 已提交
3861
	}
3862

J
Jiri Slaby 已提交
3863
	/* set cy_card */
3864 3865 3866 3867 3868 3869 3870
	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 已提交
3871 3872
	if (retval)
		goto err_null;
J
Jiri Slaby 已提交
3873

3874
	pci_set_drvdata(pdev, card);
J
Jiri Slaby 已提交
3875

J
Jiri Slaby 已提交
3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887
	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 */
3888 3889 3890 3891 3892
		{
			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 已提交
3893 3894
			break;
		}
3895
		}
J
Jiri Slaby 已提交
3896 3897
	}

J
Jiri Slaby 已提交
3898 3899
	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 已提交
3900 3901 3902
	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 已提交
3903 3904
	cy_next_channel += nchan;

J
Jiri Slaby 已提交
3905
	return 0;
J
Jiri Slaby 已提交
3906
err_null:
3907 3908
	card->base_addr = NULL;
	free_irq(irq, card);
J
Jiri Slaby 已提交
3909
err_unmap:
J
Jiri Slaby 已提交
3910
	iounmap(addr0);
J
Jiri Slaby 已提交
3911
	if (addr2)
J
Jiri Slaby 已提交
3912
		iounmap(addr2);
J
Jiri Slaby 已提交
3913 3914 3915 3916 3917 3918
err_reg:
	pci_release_regions(pdev);
err_dis:
	pci_disable_device(pdev);
err:
	return retval;
J
Jiri Slaby 已提交
3919 3920
}

B
Bill Pemberton 已提交
3921
static void cy_pci_remove(struct pci_dev *pdev)
J
Jiri Slaby 已提交
3922
{
J
Jiri Slaby 已提交
3923
	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3924
	unsigned int i, channel;
J
Jiri Slaby 已提交
3925

3926
	/* non-Z with old PLX */
3927
	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
J
Jiri Slaby 已提交
3928
			PLX_9050)
3929
		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
3930 3931
	else
#ifndef CONFIG_CYZ_INTR
3932
		if (!cy_is_Z(cinfo))
3933
#endif
3934 3935 3936
		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
			~0x0900);
3937

J
Jiri Slaby 已提交
3938
	iounmap(cinfo->base_addr);
3939 3940
	if (cinfo->ctl_addr.p9050)
		iounmap(cinfo->ctl_addr.p9050);
J
Jiri Slaby 已提交
3941 3942
	if (cinfo->irq
#ifndef CONFIG_CYZ_INTR
3943
		&& !cy_is_Z(cinfo)
J
Jiri Slaby 已提交
3944 3945 3946 3947 3948 3949
#endif /* CONFIG_CYZ_INTR */
		)
		free_irq(cinfo->irq, cinfo);
	pci_release_regions(pdev);

	cinfo->base_addr = NULL;
3950 3951
	for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
			cinfo->nports; i++, channel++) {
3952
		tty_unregister_device(cy_serial_driver, i);
3953 3954
		tty_port_destroy(&cinfo->ports[channel].port);
	}
J
Jiri Slaby 已提交
3955 3956
	cinfo->nports = 0;
	kfree(cinfo->ports);
J
Jiri Slaby 已提交
3957 3958
}

3959 3960 3961 3962
static struct pci_driver cy_pci_driver = {
	.name = "cyclades",
	.id_table = cy_pci_dev_id,
	.probe = cy_pci_probe,
B
Bill Pemberton 已提交
3963
	.remove = cy_pci_remove
3964 3965 3966
};
#endif

3967
static int cyclades_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
3968
{
3969
	struct cyclades_port *info;
J
Jiri Slaby 已提交
3970
	unsigned int i, j;
3971 3972
	__u32 cur_jifs = jiffies;

3973
	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
3974 3975 3976
			"IdleIn  Overruns  Ldisc\n");

	/* Output one line for each known port */
J
Jiri Slaby 已提交
3977 3978 3979 3980
	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 已提交
3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994
			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);
				}
3995
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
3996
					"%10lu %8lu %9lu %6d\n", info->line,
J
Jiri Slaby 已提交
3997 3998 3999 4000 4001 4002
					(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 已提交
4003 4004
					num);
			} else
4005
				seq_printf(m, "%3d %8lu %10lu %8lu "
J
Jiri Slaby 已提交
4006 4007
					"%10lu %8lu %9lu %6ld\n",
					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
4008
		}
4009 4010 4011 4012 4013 4014
	return 0;
}

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

4017 4018 4019 4020 4021 4022 4023 4024
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 已提交
4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042
/* 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 已提交
4043
static const struct tty_operations cy_ops = {
4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062
	.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,
4063
	.get_icount = cy_get_icount,
4064
	.proc_fops = &cyclades_proc_fops,
L
Linus Torvalds 已提交
4065 4066
};

4067
static int __init cy_init(void)
L
Linus Torvalds 已提交
4068
{
J
Jiri Slaby 已提交
4069
	unsigned int nboards;
4070
	int retval = -ENOMEM;
4071 4072 4073

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

M
Michal Marek 已提交
4076
	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088

	/* 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;
4089
	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
4090 4091
	tty_set_operations(cy_serial_driver, &cy_ops);

4092 4093 4094 4095 4096
	retval = tty_register_driver(cy_serial_driver);
	if (retval) {
		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
		goto err_frtty;
	}
4097 4098 4099 4100 4101 4102 4103 4104 4105

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

4108
#ifdef CONFIG_PCI
4109
	/* look for pci boards */
4110
	retval = pci_register_driver(&cy_pci_driver);
4111 4112 4113 4114
	if (retval && !nboards) {
		tty_unregister_driver(cy_serial_driver);
		goto err_frtty;
	}
4115
#endif
4116 4117 4118 4119 4120 4121

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

4124
static void __exit cy_cleanup_module(void)
L
Linus Torvalds 已提交
4125
{
J
Jiri Slaby 已提交
4126
	struct cyclades_card *card;
J
Jiri Slaby 已提交
4127
	unsigned int i, e1;
L
Linus Torvalds 已提交
4128 4129

#ifndef CONFIG_CYZ_INTR
J
Jiri Slaby 已提交
4130
	del_timer_sync(&cyz_timerlist);
L
Linus Torvalds 已提交
4131 4132
#endif /* CONFIG_CYZ_INTR */

A
Alan Cox 已提交
4133 4134
	e1 = tty_unregister_driver(cy_serial_driver);
	if (e1)
J
Jiri Slaby 已提交
4135 4136
		printk(KERN_ERR "failed to unregister Cyclades serial "
				"driver(%d)\n", e1);
L
Linus Torvalds 已提交
4137

4138 4139 4140 4141
#ifdef CONFIG_PCI
	pci_unregister_driver(&cy_pci_driver);
#endif

4142
	for (i = 0; i < NR_CARDS; i++) {
J
Jiri Slaby 已提交
4143 4144
		card = &cy_card[i];
		if (card->base_addr) {
4145
			/* clear interrupt */
J
Jiri Slaby 已提交
4146 4147
			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
			iounmap(card->base_addr);
4148 4149
			if (card->ctl_addr.p9050)
				iounmap(card->ctl_addr.p9050);
J
Jiri Slaby 已提交
4150
			if (card->irq
L
Linus Torvalds 已提交
4151
#ifndef CONFIG_CYZ_INTR
4152
				&& !cy_is_Z(card)
L
Linus Torvalds 已提交
4153
#endif /* CONFIG_CYZ_INTR */
4154
				)
J
Jiri Slaby 已提交
4155
				free_irq(card->irq, card);
J
Jiri Slaby 已提交
4156
			for (e1 = card->first_line; e1 < card->first_line +
J
Jiri Slaby 已提交
4157
					card->nports; e1++)
4158
				tty_unregister_device(cy_serial_driver, e1);
J
Jiri Slaby 已提交
4159
			kfree(card->ports);
4160 4161
		}
	}
4162 4163

	put_tty_driver(cy_serial_driver);
L
Linus Torvalds 已提交
4164 4165 4166 4167 4168 4169
} /* cy_cleanup_module */

module_init(cy_init);
module_exit(cy_cleanup_module);

MODULE_LICENSE("GPL");
4170
MODULE_VERSION(CY_VERSION);
4171
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4172
MODULE_FIRMWARE("cyzfirm.bin");