blob: 1ec3d5cd748f5e602fbf7813ca7a23266102daeb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/char/serial167.c
3 *
4 * Driver for MVME166/7 board serial ports, which are via a CD2401.
5 * Based very much on cyclades.c.
6 *
7 * MVME166/7 work by Richard Hirst [richard@sleepie.demon.co.uk]
8 *
9 * ==============================================================
10 *
11 * static char rcsid[] =
12 * "$Revision: 1.36.1.4 $$Date: 1995/03/29 06:14:14 $";
13 *
14 * linux/kernel/cyclades.c
15 *
16 * Maintained by Marcio Saito (cyclades@netcom.com) and
17 * Randolph Bentson (bentson@grieg.seaslug.org)
18 *
19 * Much of the design and some of the code came from serial.c
20 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
21 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
22 * and then fixed as suggested by Michael K. Johnson 12/12/92.
23 *
24 * This version does not support shared irq's.
25 *
26 * $Log: cyclades.c,v $
27 * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
28 * disambiguate between Cyclom-16Y and Cyclom-32Ye;
29 *
30 * Changes:
31 *
32 * 200 lines of changes record removed - RGH 11-10-95, starting work on
33 * converting this to drive serial ports on mvme166 (cd2401).
34 *
35 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/08/25
36 * - get rid of verify_area
37 * - use get_user to access memory from userspace in set_threshold,
38 * set_default_threshold and set_timeout
39 * - don't use the panic function in serial167_init
40 * - do resource release on failure on serial167_init
41 * - include missing restore_flags in mvme167_serial_console_setup
42 *
43 * Kars de Jong <jongk@linux-m68k.org> - 2004/09/06
44 * - replace bottom half handler with task queue handler
45 */
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/errno.h>
48#include <linux/signal.h>
49#include <linux/sched.h>
50#include <linux/timer.h>
51#include <linux/tty.h>
52#include <linux/interrupt.h>
53#include <linux/serial.h>
54#include <linux/serialP.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040055#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/string.h>
57#include <linux/fcntl.h>
58#include <linux/ptrace.h>
59#include <linux/serial167.h>
60#include <linux/delay.h>
61#include <linux/major.h>
62#include <linux/mm.h>
63#include <linux/console.h>
64#include <linux/module.h>
65#include <linux/bitops.h>
Geert Uytterhoeven81e859a2006-10-09 22:27:42 +020066#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68#include <asm/system.h>
69#include <asm/io.h>
70#include <asm/mvme16xhw.h>
71#include <asm/bootinfo.h>
72#include <asm/setup.h>
73
74#include <linux/types.h>
75#include <linux/kernel.h>
76
77#include <asm/uaccess.h>
78#include <linux/init.h>
79
80#define SERIAL_PARANOIA_CHECK
81#undef SERIAL_DEBUG_OPEN
82#undef SERIAL_DEBUG_THROTTLE
83#undef SERIAL_DEBUG_OTHER
84#undef SERIAL_DEBUG_IO
85#undef SERIAL_DEBUG_COUNT
86#undef SERIAL_DEBUG_DTR
87#undef CYCLOM_16Y_HACK
88#define CYCLOM_ENABLE_MONITORING
89
90#define WAKEUP_CHARS 256
91
92#define STD_COM_FLAGS (0)
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static struct tty_driver *cy_serial_driver;
95extern int serial_console;
96static struct cyclades_port *serial_console_info = NULL;
97static unsigned int serial_console_cflag = 0;
98u_char initial_console_speed;
99
100/* Base address of cd2401 chip on mvme166/7 */
101
102#define BASE_ADDR (0xfff45000)
103#define pcc2chip ((volatile u_char *)0xfff42000)
104#define PccSCCMICR 0x1d
105#define PccSCCTICR 0x1e
106#define PccSCCRICR 0x1f
107#define PccTPIACKR 0x25
108#define PccRPIACKR 0x27
109#define PccIMLR 0x3f
110
111/* This is the per-port data structure */
112struct cyclades_port cy_port[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800113 /* CARD# */
114 {-1}, /* ttyS0 */
115 {-1}, /* ttyS1 */
116 {-1}, /* ttyS2 */
117 {-1}, /* ttyS3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800119
Tobias Klauserfe971072006-01-09 20:54:02 -0800120#define NR_PORTS ARRAY_SIZE(cy_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 * This is used to look up the divisor speeds and the timeouts
124 * We're normally limited to 15 distinct baud rates. The extra
125 * are accessed via settings in info->flags.
126 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
127 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
128 * HI VHI
129 */
130static int baud_table[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800131 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
132 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
133 0
134};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800137static char baud_co[] = { /* 25 MHz clock option table */
138 /* value => 00 01 02 03 04 */
139 /* divide by 8 32 128 512 2048 */
140 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
141 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
142};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800144static char baud_bpr[] = { /* 25 MHz baud rate period table */
145 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
146 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
147};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148#endif
149
150/* I think 166 brd clocks 2401 at 20MHz.... */
151
152/* These values are written directly to tcor, and >> 5 for writing to rcor */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800153static u_char baud_co[] = { /* 20 MHz clock option table */
154 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40,
155 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
156};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158/* These values written directly to tbpr/rbpr */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800159static u_char baud_bpr[] = { /* 20 MHz baud rate period table */
160 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81,
161 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10
162};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800164static u_char baud_cor4[] = { /* receive threshold */
165 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
166 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07
167};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169static void shutdown(struct cyclades_port *);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800170static int startup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void cy_throttle(struct tty_struct *);
172static void cy_unthrottle(struct tty_struct *);
173static void config_setup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#ifdef CYCLOM_SHOW_STATUS
175static void show_status(int);
176#endif
177
178#ifdef CONFIG_REMOTE_DEBUG
179static void debug_setup(void);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800180void queueDebugChar(int c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181int getDebugChar(void);
182
183#define DEBUG_PORT 1
184#define DEBUG_LEN 256
185
186typedef struct {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800187 int in;
188 int out;
189 unsigned char buf[DEBUG_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190} debugq;
191
192debugq debugiq;
193#endif
194
195/*
196 * I have my own version of udelay(), as it is needed when initialising
197 * the chip, before the delay loop has been calibrated. Should probably
198 * reference one of the vmechip2 or pccchip2 counter for an accurate
199 * delay, but this wild guess will do for now.
200 */
201
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800202void my_udelay(long us)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203{
204 u_char x;
205 volatile u_char *p = &x;
206 int i;
207
208 while (us--)
209 for (i = 100; i; i--)
210 x |= *p;
211}
212
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800213static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
214 const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800217 if (!info) {
218 printk("Warning: null cyclades_port for (%s) in %s\n", name,
219 routine);
220 return 1;
221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Roel Kluinf23fc152009-10-01 15:44:25 -0700223 if (info < &cy_port[0] || info >= &cy_port[NR_PORTS]) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800224 printk("Warning: cyclades_port out of range for (%s) in %s\n",
225 name, routine);
226 return 1;
227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800229 if (info->magic != CYCLADES_MAGIC) {
230 printk("Warning: bad magic number for serial struct (%s) in "
231 "%s\n", name, routine);
232 return 1;
233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234#endif
235 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800236} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238#if 0
239/* The following diagnostic routines allow the driver to spew
240 information on the screen, even (especially!) during interrupts.
241 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800242void SP(char *data)
243{
244 unsigned long flags;
245 local_irq_save(flags);
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700246 printk(KERN_EMERG "%s", data);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800247 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800250char scrn[2];
251void CP(char data)
252{
253 unsigned long flags;
254 local_irq_save(flags);
255 scrn[0] = data;
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700256 printk(KERN_EMERG "%c", scrn);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800257 local_irq_restore(flags);
258} /* CP */
259
260void CP1(int data)
261{
262 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
263} /* CP1 */
264void CP2(int data)
265{
266 CP1((data >> 4) & 0x0f);
267 CP1(data & 0x0f);
268} /* CP2 */
269void CP4(int data)
270{
271 CP2((data >> 8) & 0xff);
272 CP2(data & 0xff);
273} /* CP4 */
274void CP8(long data)
275{
276 CP4((data >> 16) & 0xffff);
277 CP4(data & 0xffff);
278} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#endif
280
281/* This routine waits up to 1000 micro-seconds for the previous
282 command to the Cirrus chip to complete and then issues the
283 new command. An error is returned if the previous command
284 didn't finish within the time limit.
285 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800286u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800288 unsigned long flags;
289 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800291 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800293 for (i = 0; i < 100; i++) {
294 if (base_addr[CyCCR] == 0) {
295 break;
296 }
297 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
299 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800300 didn't finish within the "reasonable time" */
301 if (i == 10) {
302 local_irq_restore(flags);
303 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
305
306 /* Issue the new command */
307 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800308 local_irq_restore(flags);
309 return (0);
310} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312/* cy_start and cy_stop provide software output flow control as a
313 function of XON/XOFF, software CTS, and other such stuff. */
314
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800315static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
Alan Coxc9f19e92009-01-02 13:47:26 +0000317 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800318 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
319 int channel;
320 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800323 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324#endif
325
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800326 if (serial_paranoia_check(info, tty->name, "cy_stop"))
327 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800329 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800331 local_irq_save(flags);
332 base_addr[CyCAR] = (u_char) (channel); /* index channel */
333 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
334 local_irq_restore(flags);
335} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800337static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
Alan Coxc9f19e92009-01-02 13:47:26 +0000339 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800340 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
341 int channel;
342 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800345 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346#endif
347
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800348 if (serial_paranoia_check(info, tty->name, "cy_start"))
349 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800351 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800353 local_irq_save(flags);
354 base_addr[CyCAR] = (u_char) (channel);
355 base_addr[CyIER] |= CyTxMpty;
356 local_irq_restore(flags);
357} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359/* The real interrupt service routines are called
360 whenever the card wants its hand held--chars
361 received, out buffer empty, modem change, etc.
362 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800363static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800365 struct tty_struct *tty;
366 struct cyclades_port *info;
367 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
368 unsigned char err, rfoc;
369 int channel;
370 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800372 /* determine the channel and change to that context */
373 channel = (u_short) (base_addr[CyLICR] >> 2);
374 info = &cy_port[channel];
375 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800377 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
378 /* This is a receive timeout interrupt, ignore it */
379 base_addr[CyREOIR] = CyNOTRANS;
380 return IRQ_HANDLED;
381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800383 /* Read a byte of data if there is any - assume the error
384 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800386 if ((rfoc = base_addr[CyRFOC]) != 0)
387 data = base_addr[CyRDR];
388 else
389 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800391 /* if there is nowhere to put the data, discard it */
392 if (info->tty == 0) {
393 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
394 return IRQ_HANDLED;
395 } else { /* there is an open port for this data */
396 tty = info->tty;
397 if (err & info->ignore_status_mask) {
398 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
399 return IRQ_HANDLED;
400 }
401 if (tty_buffer_request_room(tty, 1) != 0) {
402 if (err & info->read_status_mask) {
403 if (err & CyBREAK) {
404 tty_insert_flip_char(tty, data,
405 TTY_BREAK);
406 if (info->flags & ASYNC_SAK) {
407 do_SAK(tty);
408 }
409 } else if (err & CyFRAME) {
410 tty_insert_flip_char(tty, data,
411 TTY_FRAME);
412 } else if (err & CyPARITY) {
413 tty_insert_flip_char(tty, data,
414 TTY_PARITY);
415 } else if (err & CyOVERRUN) {
416 tty_insert_flip_char(tty, 0,
417 TTY_OVERRUN);
418 /*
419 If the flip buffer itself is
Nick Andrewc4f01242008-12-05 16:34:46 +0000420 overflowing, we still lose
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800421 the next incoming character.
422 */
423 if (tty_buffer_request_room(tty, 1) !=
424 0) {
425 tty_insert_flip_char(tty, data,
426 TTY_FRAME);
427 }
428 /* These two conditions may imply */
429 /* a normal read should be done. */
430 /* else if(data & CyTIMEOUT) */
431 /* else if(data & CySPECHAR) */
432 } else {
433 tty_insert_flip_char(tty, 0,
434 TTY_NORMAL);
435 }
436 } else {
437 tty_insert_flip_char(tty, data, TTY_NORMAL);
438 }
439 } else {
440 /* there was a software buffer overrun
441 and nothing could be done about it!!! */
442 }
443 }
444 tty_schedule_flip(tty);
445 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
447 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800448} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800450static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800452 struct cyclades_port *info;
453 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
454 int channel;
455 int mdm_change;
456 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800458 /* determine the channel and change to that context */
459 channel = (u_short) (base_addr[CyLICR] >> 2);
460 info = &cy_port[channel];
461 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800463 mdm_change = base_addr[CyMISR];
464 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800466 if (info->tty == 0) { /* nowhere to put the data, ignore it */
467 ;
468 } else {
469 if ((mdm_change & CyDCD)
470 && (info->flags & ASYNC_CHECK_CD)) {
471 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472/* CP('!'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800473 wake_up_interruptible(&info->open_wait);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800474 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475/* CP('@'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800476 tty_hangup(info->tty);
477 wake_up_interruptible(&info->open_wait);
478 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800481 if ((mdm_change & CyCTS)
482 && (info->flags & ASYNC_CTS_FLOW)) {
483 if (info->tty->stopped) {
484 if (mdm_status & CyCTS) {
485 /* !!! cy_start isn't used because... */
486 info->tty->stopped = 0;
487 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800488 tty_wakeup(info->tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800489 }
490 } else {
491 if (!(mdm_status & CyCTS)) {
492 /* !!! cy_stop isn't used because... */
493 info->tty->stopped = 1;
494 base_addr[CyIER] &=
495 ~(CyTxMpty | CyTxRdy);
496 }
497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800499 if (mdm_status & CyDSR) {
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800502 base_addr[CyMEOIR] = 0;
503 return IRQ_HANDLED;
504} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800506static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800508 struct cyclades_port *info;
509 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
510 int channel;
511 int char_count, saved_cnt;
512 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800514 /* determine the channel and change to that context */
515 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800518 if (channel == DEBUG_PORT) {
519 panic("TxInt on debug port!!!");
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800522 /* validate the port number (as configured and open) */
523 if ((channel < 0) || (NR_PORTS <= channel)) {
524 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
525 base_addr[CyTEOIR] = CyNOTRANS;
526 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 }
Roel Kluinf23fc152009-10-01 15:44:25 -0700528 info = &cy_port[channel];
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800529 info->last_active = jiffies;
530 if (info->tty == 0) {
531 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800532 base_addr[CyTEOIR] = CyNOTRANS;
533 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800535
536 /* load the on-chip space available for outbound data */
537 saved_cnt = char_count = base_addr[CyTFTC];
538
539 if (info->x_char) { /* send special char */
540 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800543 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800546 if (info->x_break) {
547 /* The Cirrus chip requires the "Embedded Transmit
548 Commands" of start break, delay, and end break
549 sequences to be sent. The duration of the
550 break is given in TICs, which runs at HZ
551 (typically 100) and the PPR runs at 200 Hz,
552 so the delay is duration * 200/HZ, and thus a
553 break can run from 1/100 sec to about 5/4 sec.
554 Need to check these values - RGH 141095.
555 */
556 base_addr[CyTDR] = 0; /* start break */
557 base_addr[CyTDR] = 0x81;
558 base_addr[CyTDR] = 0; /* delay a bit */
559 base_addr[CyTDR] = 0x82;
560 base_addr[CyTDR] = info->x_break * 200 / HZ;
561 base_addr[CyTDR] = 0; /* terminate break */
562 base_addr[CyTDR] = 0x83;
563 char_count -= 7;
564 info->x_break = 0;
565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800567 while (char_count > 0) {
568 if (!info->xmit_cnt) {
569 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
570 break;
571 }
572 if (info->xmit_buf == 0) {
573 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
574 break;
575 }
576 if (info->tty->stopped || info->tty->hw_stopped) {
577 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
578 break;
579 }
580 /* Because the Embedded Transmit Commands have been
581 enabled, we must check to see if the escape
582 character, NULL, is being sent. If it is, we
583 must ensure that there is room for it to be
584 doubled in the output stream. Therefore we
585 no longer advance the pointer when the character
586 is fetched, but rather wait until after the check
587 for a NULL output character. (This is necessary
588 because there may not be room for the two chars
589 needed to send a NULL.
590 */
591 outch = info->xmit_buf[info->xmit_tail];
592 if (outch) {
593 info->xmit_cnt--;
594 info->xmit_tail = (info->xmit_tail + 1)
595 & (PAGE_SIZE - 1);
596 base_addr[CyTDR] = outch;
597 char_count--;
598 } else {
599 if (char_count > 1) {
600 info->xmit_cnt--;
601 info->xmit_tail = (info->xmit_tail + 1)
602 & (PAGE_SIZE - 1);
603 base_addr[CyTDR] = outch;
604 base_addr[CyTDR] = 0;
605 char_count--;
606 char_count--;
607 } else {
608 break;
609 }
610 }
611 }
612
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800613 if (info->xmit_cnt < WAKEUP_CHARS)
614 tty_wakeup(info->tty);
615
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800616 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
617 return IRQ_HANDLED;
618} /* cy_tx_interrupt */
619
620static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800622 struct tty_struct *tty;
623 struct cyclades_port *info;
624 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
625 int channel;
626 char data;
627 int char_count;
628 int save_cnt;
629 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800631 /* determine the channel and change to that context */
632 channel = (u_short) (base_addr[CyLICR] >> 2);
633 info = &cy_port[channel];
634 info->last_active = jiffies;
635 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800638 if (channel == DEBUG_PORT) {
639 while (char_count--) {
640 data = base_addr[CyRDR];
641 queueDebugChar(data);
642 }
643 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800645 /* if there is nowhere to put the data, discard it */
646 if (info->tty == 0) {
647 while (char_count--) {
648 data = base_addr[CyRDR];
649 }
650 } else { /* there is an open port for this data */
651 tty = info->tty;
652 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800655 ++info->mon.int_count;
656 info->mon.char_count += char_count;
657 if (char_count > info->mon.char_max)
658 info->mon.char_max = char_count;
659 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660#endif
Alan Cox4165fe42010-02-17 13:07:13 +0000661 while (char_count--) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800662 data = base_addr[CyRDR];
663 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800665 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800667 }
668 tty_schedule_flip(tty);
669 }
670 /* end of service */
671 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
672 return IRQ_HANDLED;
673} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675/* This is called whenever a port becomes active;
676 interrupts are enabled and DTR & RTS are turned on.
677 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800678static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800680 unsigned long flags;
681 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
682 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800684 if (info->flags & ASYNC_INITIALIZED) {
685 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800687
688 if (!info->type) {
689 if (info->tty) {
690 set_bit(TTY_IO_ERROR, &info->tty->flags);
691 }
692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800694 if (!info->xmit_buf) {
695 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
696 if (!info->xmit_buf) {
697 return -ENOMEM;
698 }
699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800701 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800703 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800706 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707#endif
708
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800709 local_irq_save(flags);
710 base_addr[CyCAR] = (u_char) channel;
711 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800713 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 base_addr[CyMSVR1] = CyRTS;
715/* CP('S');CP('1'); */
716 base_addr[CyMSVR2] = CyDTR;
717
718#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800719 printk("cyc: %d: raising DTR\n", __LINE__);
720 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
721 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722#endif
723
724 base_addr[CyIER] |= CyRxData;
725 info->flags |= ASYNC_INITIALIZED;
726
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800727 if (info->tty) {
728 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
731
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800732 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800735 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800737 return 0;
738} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800740void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800742 unsigned long flags;
743 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
744 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800746 channel = info->line;
747 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 base_addr[CyCAR] = channel;
749 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800750 local_irq_restore(flags);
751} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753/*
754 * This routine shuts down a serial port; interrupts are disabled,
755 * and DTR is dropped if the hangup on close termio flag is on.
756 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800757static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800759 unsigned long flags;
760 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
761 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800763 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800765 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800768 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800770#ifdef SERIAL_DEBUG_OPEN
771 printk("shutdown channel %d\n", channel);
772#endif
773
774 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
775 SENT BEFORE DROPPING THE LINE !!! (Perhaps
776 set some flag that is read when XMTY happens.)
777 Other choices are to delay some fixed interval
778 or schedule some later processing.
779 */
780 local_irq_save(flags);
781 if (info->xmit_buf) {
782 free_page((unsigned long)info->xmit_buf);
783 info->xmit_buf = NULL;
784 }
785
786 base_addr[CyCAR] = (u_char) channel;
787 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
788 base_addr[CyMSVR1] = 0;
789/* CP('C');CP('1'); */
790 base_addr[CyMSVR2] = 0;
791#ifdef SERIAL_DEBUG_DTR
792 printk("cyc: %d: dropping DTR\n", __LINE__);
793 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
794 base_addr[CyMSVR2]);
795#endif
796 }
797 write_cy_cmd(base_addr, CyDIS_RCVR);
798 /* it may be appropriate to clear _XMIT at
799 some later date (after testing)!!! */
800
801 if (info->tty) {
802 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800805 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800808 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800810} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812/*
813 * This routine finds or computes the various line characteristics.
814 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800815static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800817 unsigned long flags;
818 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
819 int channel;
820 unsigned cflag;
821 int i;
822 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800824 if (!info->tty || !info->tty->termios) {
825 return;
826 }
827 if (info->line == -1) {
828 return;
829 }
830 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800832 /* baud rate */
833 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834#ifdef CBAUDEX
835/* Starting with kernel 1.1.65, there is direct support for
836 higher baud rates. The following code supports those
837 changes. The conditional aspect allows this driver to be
838 used for earlier as well as later kernel versions. (The
839 mapping is slightly different from serial.c because there
840 is still the possibility of supporting 75 kbit/sec with
841 the Cyclades board.)
842 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800843 if (i & CBAUDEX) {
844 if (i == B57600)
845 i = 16;
846 else if (i == B115200)
847 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800849 else if (i == B78600)
850 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800852 else
853 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800856 if (i == 15) {
857 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
858 i += 1;
859 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
860 i += 3;
861 }
862 /* Don't ever change the speed of the console port. It will
863 * run at the speed specified in bootinfo, or at 19.2K */
864 /* Actually, it should run at whatever speed 166Bug was using */
865 /* Note info->timeout isn't used at present */
866 if (info != serial_console_info) {
867 info->tbpr = baud_bpr[i]; /* Tx BPR */
868 info->tco = baud_co[i]; /* Tx CO */
869 info->rbpr = baud_bpr[i]; /* Rx BPR */
870 info->rco = baud_co[i] >> 5; /* Rx CO */
871 if (baud_table[i] == 134) {
872 info->timeout =
873 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
874 /* get it right for 134.5 baud */
875 } else if (baud_table[i]) {
876 info->timeout =
877 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
878 2;
879 /* this needs to be propagated into the card info */
880 } else {
881 info->timeout = 0;
882 }
883 }
884 /* By tradition (is it a standard?) a baud rate of zero
885 implies the line should be/has been closed. A bit
886 later in this routine such a test is performed. */
887
888 /* byte size and parity */
889 info->cor7 = 0;
890 info->cor6 = 0;
891 info->cor5 = 0;
892 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
893 /* Following two lines added 101295, RGH. */
894 /* It is obviously wrong to access CyCORx, and not info->corx here,
895 * try and remember to fix it later! */
896 channel = info->line;
897 base_addr[CyCAR] = (u_char) channel;
898 if (C_CLOCAL(info->tty)) {
899 if (base_addr[CyIER] & CyMdmCh)
900 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
901 /* ignore 1->0 modem transitions */
902 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
903 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
904 /* ignore 0->1 modem transitions */
905 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
906 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
907 } else {
908 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
909 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
910 /* act on 1->0 modem transitions */
911 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
912 (CyDSR | CyCTS | CyDCD))
913 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
914 /* act on 0->1 modem transitions */
915 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
916 (CyDSR | CyCTS | CyDCD))
917 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
918 }
919 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
920 info->cor2 = CyETC;
921 switch (cflag & CSIZE) {
922 case CS5:
923 info->cor1 = Cy_5_BITS;
924 break;
925 case CS6:
926 info->cor1 = Cy_6_BITS;
927 break;
928 case CS7:
929 info->cor1 = Cy_7_BITS;
930 break;
931 case CS8:
932 info->cor1 = Cy_8_BITS;
933 break;
934 }
935 if (cflag & PARENB) {
936 if (cflag & PARODD) {
937 info->cor1 |= CyPARITY_O;
938 } else {
939 info->cor1 |= CyPARITY_E;
940 }
941 } else {
942 info->cor1 |= CyPARITY_NONE;
943 }
944
945 /* CTS flow control flag */
946#if 0
947 /* Don't complcate matters for now! RGH 141095 */
948 if (cflag & CRTSCTS) {
949 info->flags |= ASYNC_CTS_FLOW;
950 info->cor2 |= CyCtsAE;
951 } else {
952 info->flags &= ~ASYNC_CTS_FLOW;
953 info->cor2 &= ~CyCtsAE;
954 }
955#endif
956 if (cflag & CLOCAL)
957 info->flags &= ~ASYNC_CHECK_CD;
958 else
959 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 /***********************************************
962 The hardware option, CyRtsAO, presents RTS when
963 the chip has characters to send. Since most modems
964 use RTS as reverse (inbound) flow control, this
965 option is not used. If inbound flow control is
966 necessary, DTR can be programmed to provide the
967 appropriate signals for use with a non-standard
968 cable. Contact Marcio Saito for details.
969 ***********************************************/
970
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800971 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800973 local_irq_save(flags);
974 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 /* CyCMR set once only in mvme167_init_serial() */
977 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800978 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800980 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800982 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
984 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800985 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800987 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800989 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800991 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800993 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 /* set line characteristics according configuration */
996
997 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800998 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001000 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001002 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001004 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001006 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001008 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001010 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001012 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001014 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001016 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001018 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001021 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001023 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 /* 2ms default rx timeout */
1026 ti = info->default_timeout ? info->default_timeout : 0x02;
1027 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001028 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001030 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001033 if (i == 0) { /* baud rate is zero, turn off line */
1034 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1035 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001037 printk("cyc: %d: dropping DTR\n", __LINE__);
1038 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1039 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001041 } else {
1042 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1043 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001045 printk("cyc: %d: raising DTR\n", __LINE__);
1046 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1047 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048#endif
1049 }
1050
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001051 if (info->tty) {
1052 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001055 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001057} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Alan Coxa5b08c62008-04-30 00:54:05 -07001059static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060{
Alan Coxc9f19e92009-01-02 13:47:26 +00001061 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001062 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001065 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066#endif
1067
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001068 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001069 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001071 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001072 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001074 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001076 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 }
1079
1080 info->xmit_buf[info->xmit_head++] = ch;
1081 info->xmit_head &= PAGE_SIZE - 1;
1082 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001083 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001084 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001085} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001087static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
Alan Coxc9f19e92009-01-02 13:47:26 +00001089 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001090 unsigned long flags;
1091 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1092 int channel;
1093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001095 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096#endif
1097
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001098 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1099 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001101 if (info->xmit_cnt <= 0 || tty->stopped
1102 || tty->hw_stopped || !info->xmit_buf)
1103 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001105 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001107 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 base_addr[CyCAR] = channel;
1109 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001110 local_irq_restore(flags);
1111} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113/* This routine gets called when tty_write has put something into
1114 the write_queue. If the port is not already transmitting stuff,
1115 start it off by enabling interrupts. The interrupt service
1116 routine will then ensure that the characters are sent. If the
1117 port is already active, there is no need to kick it.
1118 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001119static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
Alan Coxc9f19e92009-01-02 13:47:26 +00001121 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001122 unsigned long flags;
1123 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001126 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127#endif
1128
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001129 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1130 return 0;
1131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001133 if (!info->xmit_buf) {
1134 return 0;
1135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001137 while (1) {
1138 local_irq_save(flags);
1139 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1140 SERIAL_XMIT_SIZE - info->xmit_head));
1141 if (c <= 0) {
1142 local_irq_restore(flags);
1143 break;
1144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001146 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1147 info->xmit_head =
1148 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1149 info->xmit_cnt += c;
1150 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001152 buf += c;
1153 count -= c;
1154 total += c;
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001157 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1158 start_xmit(info);
1159 }
1160 return total;
1161} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001163static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
Alan Coxc9f19e92009-01-02 13:47:26 +00001165 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001166 int ret;
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001169 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170#endif
1171
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001172 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1173 return 0;
1174 ret = PAGE_SIZE - info->xmit_cnt - 1;
1175 if (ret < 0)
1176 ret = 0;
1177 return ret;
1178} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001180static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
Alan Coxc9f19e92009-01-02 13:47:26 +00001182 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001185 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186#endif
1187
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001188 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1189 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001191 return info->xmit_cnt;
1192} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001194static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Alan Coxc9f19e92009-01-02 13:47:26 +00001196 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001197 unsigned long flags;
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001200 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201#endif
1202
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001203 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1204 return;
1205 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001207 local_irq_restore(flags);
1208 tty_wakeup(tty);
1209} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211/* This routine is called by the upper-layer tty layer to signal
1212 that incoming characters should be throttled or that the
1213 throttle should be released.
1214 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001215static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
Alan Coxc9f19e92009-01-02 13:47:26 +00001217 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001218 unsigned long flags;
1219 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1220 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001223 char buf[64];
1224
1225 printk("throttle %s: %d....\n", tty_name(tty, buf),
1226 tty->ldisc.chars_in_buffer(tty));
1227 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228#endif
1229
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001230 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1231 return;
1232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001234 if (I_IXOFF(tty)) {
1235 info->x_char = STOP_CHAR(tty);
1236 /* Should use the "Send Special Character" feature!!! */
1237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001239 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001241 local_irq_save(flags);
1242 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001244 local_irq_restore(flags);
1245} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001247static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248{
Alan Coxc9f19e92009-01-02 13:47:26 +00001249 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001250 unsigned long flags;
1251 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1252 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001255 char buf[64];
1256
1257 printk("throttle %s: %d....\n", tty_name(tty, buf),
1258 tty->ldisc.chars_in_buffer(tty));
1259 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260#endif
1261
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001262 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1263 return;
1264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001266 if (I_IXOFF(tty)) {
1267 info->x_char = START_CHAR(tty);
1268 /* Should use the "Send Special Character" feature!!! */
1269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001271 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001273 local_irq_save(flags);
1274 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001276 local_irq_restore(flags);
1277} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001280get_serial_info(struct cyclades_port *info,
1281 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001283 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001286 if (!retinfo)
1287 return -EFAULT;
1288 memset(&tmp, 0, sizeof(tmp));
1289 tmp.type = info->type;
1290 tmp.line = info->line;
1291 tmp.port = info->line;
1292 tmp.irq = 0;
1293 tmp.flags = info->flags;
1294 tmp.baud_base = 0; /*!!! */
1295 tmp.close_delay = info->close_delay;
1296 tmp.custom_divisor = 0; /*!!! */
1297 tmp.hub6 = 0; /*!!! */
1298 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1299} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001302set_serial_info(struct cyclades_port *info,
1303 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001305 struct serial_struct new_serial;
1306 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
1308/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001309 if (!new_info)
1310 return -EFAULT;
1311 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1312 return -EFAULT;
1313 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001315 if (!capable(CAP_SYS_ADMIN)) {
1316 if ((new_serial.close_delay != info->close_delay) ||
1317 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1318 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1319 return -EPERM;
1320 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1321 (new_serial.flags & ASYNC_USR_MASK));
1322 goto check_and_exit;
1323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001325 /*
1326 * OK, past this point, all the error checking has been done.
1327 * At this point, we start making changes.....
1328 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001330 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1331 (new_serial.flags & ASYNC_FLAGS));
1332 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001335 if (info->flags & ASYNC_INITIALIZED) {
1336 config_setup(info);
1337 return 0;
1338 }
1339 return startup(info);
1340} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001342static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
Alan Coxc9f19e92009-01-02 13:47:26 +00001344 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001345 int channel;
1346 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1347 unsigned long flags;
1348 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001350 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001352 local_irq_save(flags);
1353 base_addr[CyCAR] = (u_char) channel;
1354 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1355 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001357 return ((status & CyRTS) ? TIOCM_RTS : 0)
1358 | ((status & CyDTR) ? TIOCM_DTR : 0)
1359 | ((status & CyDCD) ? TIOCM_CAR : 0)
1360 | ((status & CyDSR) ? TIOCM_DSR : 0)
1361 | ((status & CyCTS) ? TIOCM_CTS : 0);
1362} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
1364static int
1365cy_tiocmset(struct tty_struct *tty, struct file *file,
1366 unsigned int set, unsigned int clear)
1367{
Alan Coxc9f19e92009-01-02 13:47:26 +00001368 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001369 int channel;
1370 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1371 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001373 channel = info->line;
1374
1375 if (set & TIOCM_RTS) {
1376 local_irq_save(flags);
1377 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001379 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001381 if (set & TIOCM_DTR) {
1382 local_irq_save(flags);
1383 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001385 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001387 printk("cyc: %d: raising DTR\n", __LINE__);
1388 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1389 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001391 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
1393
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001394 if (clear & TIOCM_RTS) {
1395 local_irq_save(flags);
1396 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001398 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001400 if (clear & TIOCM_DTR) {
1401 local_irq_save(flags);
1402 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001404 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001406 printk("cyc: %d: dropping DTR\n", __LINE__);
1407 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1408 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001410 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 }
1412
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001413 return 0;
1414} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001416static void send_break(struct cyclades_port *info, int duration)
1417{ /* Let the transmit ISR take care of this (since it
1418 requires stuffing characters into the output stream).
1419 */
1420 info->x_break = duration;
1421 if (!info->xmit_cnt) {
1422 start_xmit(info);
1423 }
1424} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001427get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428{
1429
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001430 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1431 return -EFAULT;
1432 info->mon.int_count = 0;
1433 info->mon.char_count = 0;
1434 info->mon.char_max = 0;
1435 info->mon.char_last = 0;
1436 return 0;
1437}
1438
1439static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1440{
1441 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1442 unsigned long value;
1443 int channel;
1444
1445 if (get_user(value, arg))
1446 return -EFAULT;
1447
1448 channel = info->line;
1449 info->cor4 &= ~CyREC_FIFO;
1450 info->cor4 |= value & CyREC_FIFO;
1451 base_addr[CyCOR4] = info->cor4;
1452 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453}
1454
1455static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001456get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001458 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1459 int channel;
1460 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001462 channel = info->line;
1463
1464 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1465 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466}
1467
1468static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001469set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001471 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001473 if (get_user(value, arg))
1474 return -EFAULT;
1475
1476 info->default_threshold = value & 0x0f;
1477 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478}
1479
1480static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001481get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001483 return put_user(info->default_threshold, value);
1484}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001486static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1487{
1488 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1489 int channel;
1490 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001492 if (get_user(value, arg))
1493 return -EFAULT;
1494
1495 channel = info->line;
1496
1497 base_addr[CyRTPRL] = value & 0xff;
1498 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1499 return 0;
1500}
1501
1502static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1503{
1504 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1505 int channel;
1506 unsigned long tmp;
1507
1508 channel = info->line;
1509
1510 tmp = base_addr[CyRTPRL];
1511 return put_user(tmp, value);
1512}
1513
1514static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1515{
1516 info->default_timeout = value & 0xff;
1517 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518}
1519
1520static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001521get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001523 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524}
1525
1526static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001527cy_ioctl(struct tty_struct *tty, struct file *file,
1528 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001530 unsigned long val;
Alan Coxc9f19e92009-01-02 13:47:26 +00001531 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001532 int ret_val = 0;
1533 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001536 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537#endif
1538
Alan Cox638157b2008-04-30 00:53:22 -07001539 lock_kernel();
1540
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001541 switch (cmd) {
1542 case CYGETMON:
1543 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001545 case CYGETTHRESH:
1546 ret_val = get_threshold(info, argp);
1547 break;
1548 case CYSETTHRESH:
1549 ret_val = set_threshold(info, argp);
1550 break;
1551 case CYGETDEFTHRESH:
1552 ret_val = get_default_threshold(info, argp);
1553 break;
1554 case CYSETDEFTHRESH:
1555 ret_val = set_default_threshold(info, argp);
1556 break;
1557 case CYGETTIMEOUT:
1558 ret_val = get_timeout(info, argp);
1559 break;
1560 case CYSETTIMEOUT:
1561 ret_val = set_timeout(info, argp);
1562 break;
1563 case CYGETDEFTIMEOUT:
1564 ret_val = get_default_timeout(info, argp);
1565 break;
1566 case CYSETDEFTIMEOUT:
1567 ret_val = set_default_timeout(info, (unsigned long)arg);
1568 break;
1569 case TCSBRK: /* SVID version: non-zero arg --> no break */
1570 ret_val = tty_check_change(tty);
1571 if (ret_val)
1572 break;
1573 tty_wait_until_sent(tty, 0);
1574 if (!arg)
1575 send_break(info, HZ / 4); /* 1/4 second */
1576 break;
1577 case TCSBRKP: /* support for POSIX tcsendbreak() */
1578 ret_val = tty_check_change(tty);
1579 if (ret_val)
1580 break;
1581 tty_wait_until_sent(tty, 0);
1582 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1583 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001586 case TIOCGSERIAL:
1587 ret_val = get_serial_info(info, argp);
1588 break;
1589 case TIOCSSERIAL:
1590 ret_val = set_serial_info(info, argp);
1591 break;
1592 default:
1593 ret_val = -ENOIOCTLCMD;
1594 }
Alan Cox638157b2008-04-30 00:53:22 -07001595 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001598 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599#endif
1600
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001601 return ret_val;
1602} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001604static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605{
Alan Coxc9f19e92009-01-02 13:47:26 +00001606 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001609 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610#endif
1611
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001612 if (tty->termios->c_cflag == old_termios->c_cflag)
1613 return;
1614 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001616 if ((old_termios->c_cflag & CRTSCTS) &&
1617 !(tty->termios->c_cflag & CRTSCTS)) {
1618 tty->stopped = 0;
1619 cy_start(tty);
1620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001622 if (!(old_termios->c_cflag & CLOCAL) &&
1623 (tty->termios->c_cflag & CLOCAL))
1624 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001626} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001628static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
Alan Coxc9f19e92009-01-02 13:47:26 +00001630 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632/* CP('C'); */
1633#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001634 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635#endif
1636
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001637 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1638 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001640#ifdef SERIAL_DEBUG_OPEN
1641 printk("cy_close %s, count = %d\n", tty->name, info->count);
1642#endif
1643
1644 if ((tty->count == 1) && (info->count != 1)) {
1645 /*
1646 * Uh, oh. tty->count is 1, which means that the tty
1647 * structure will be freed. Info->count should always
1648 * be one in these conditions. If it's greater than
1649 * one, we've got real problems, since it means the
1650 * serial port won't be shutdown.
1651 */
1652 printk("cy_close: bad serial port count; tty->count is 1, "
1653 "info->count is %d\n", info->count);
1654 info->count = 1;
1655 }
1656#ifdef SERIAL_DEBUG_COUNT
1657 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1658 info->count - 1);
1659#endif
1660 if (--info->count < 0) {
1661 printk("cy_close: bad serial port count for ttys%d: %d\n",
1662 info->line, info->count);
1663#ifdef SERIAL_DEBUG_COUNT
1664 printk("cyc: %d: setting count to 0\n", __LINE__);
1665#endif
1666 info->count = 0;
1667 }
1668 if (info->count)
1669 return;
1670 info->flags |= ASYNC_CLOSING;
1671 if (info->flags & ASYNC_INITIALIZED)
1672 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1673 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001674 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001675 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001676 info->tty = NULL;
1677 if (info->blocked_open) {
1678 if (info->close_delay) {
1679 msleep_interruptible(jiffies_to_msecs
1680 (info->close_delay));
1681 }
1682 wake_up_interruptible(&info->open_wait);
1683 }
1684 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1685 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001688 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001690} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692/*
1693 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1694 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001695void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696{
Alan Coxc9f19e92009-01-02 13:47:26 +00001697 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001700 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701#endif
1702
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001703 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1704 return;
1705
1706 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001708 info->event = 0;
1709 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001711 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001713 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001715 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1716 wake_up_interruptible(&info->open_wait);
1717} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719/*
1720 * ------------------------------------------------------------
1721 * cy_open() and friends
1722 * ------------------------------------------------------------
1723 */
1724
1725static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001726block_til_ready(struct tty_struct *tty, struct file *filp,
1727 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001729 DECLARE_WAITQUEUE(wait, current);
1730 unsigned long flags;
1731 int channel;
1732 int retval;
1733 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001735 /*
1736 * If the device is in the middle of being closed, then block
1737 * until it's done, and then try again.
1738 */
1739 if (info->flags & ASYNC_CLOSING) {
1740 interruptible_sleep_on(&info->close_wait);
1741 if (info->flags & ASYNC_HUP_NOTIFY) {
1742 return -EAGAIN;
1743 } else {
1744 return -ERESTARTSYS;
1745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001748 /*
1749 * If non-blocking mode is set, then make the check up front
1750 * and then exit.
1751 */
1752 if (filp->f_flags & O_NONBLOCK) {
1753 info->flags |= ASYNC_NORMAL_ACTIVE;
1754 return 0;
1755 }
1756
1757 /*
1758 * Block waiting for the carrier detect and the line to become
1759 * free (i.e., not in use by the callout). While we are in
1760 * this loop, info->count is dropped by one, so that
1761 * cy_close() knows when to free things. We restore it upon
1762 * exit, either normal or abnormal.
1763 */
1764 retval = 0;
1765 add_wait_queue(&info->open_wait, &wait);
1766#ifdef SERIAL_DEBUG_OPEN
1767 printk("block_til_ready before block: %s, count = %d\n",
1768 tty->name, info->count);
1769 /**/
1770#endif
1771 info->count--;
1772#ifdef SERIAL_DEBUG_COUNT
1773 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1774#endif
1775 info->blocked_open++;
1776
1777 channel = info->line;
1778
1779 while (1) {
1780 local_irq_save(flags);
1781 base_addr[CyCAR] = (u_char) channel;
1782 base_addr[CyMSVR1] = CyRTS;
1783/* CP('S');CP('4'); */
1784 base_addr[CyMSVR2] = CyDTR;
1785#ifdef SERIAL_DEBUG_DTR
1786 printk("cyc: %d: raising DTR\n", __LINE__);
1787 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1788 base_addr[CyMSVR2]);
1789#endif
1790 local_irq_restore(flags);
1791 set_current_state(TASK_INTERRUPTIBLE);
1792 if (tty_hung_up_p(filp)
1793 || !(info->flags & ASYNC_INITIALIZED)) {
1794 if (info->flags & ASYNC_HUP_NOTIFY) {
1795 retval = -EAGAIN;
1796 } else {
1797 retval = -ERESTARTSYS;
1798 }
1799 break;
1800 }
1801 local_irq_save(flags);
1802 base_addr[CyCAR] = (u_char) channel;
1803/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1804 if (!(info->flags & ASYNC_CLOSING)
1805 && (C_CLOCAL(tty)
1806 || (base_addr[CyMSVR1] & CyDCD))) {
1807 local_irq_restore(flags);
1808 break;
1809 }
1810 local_irq_restore(flags);
1811 if (signal_pending(current)) {
1812 retval = -ERESTARTSYS;
1813 break;
1814 }
1815#ifdef SERIAL_DEBUG_OPEN
1816 printk("block_til_ready blocking: %s, count = %d\n",
1817 tty->name, info->count);
1818 /**/
1819#endif
1820 schedule();
1821 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001822 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001823 remove_wait_queue(&info->open_wait, &wait);
1824 if (!tty_hung_up_p(filp)) {
1825 info->count++;
1826#ifdef SERIAL_DEBUG_COUNT
1827 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1828 info->count);
1829#endif
1830 }
1831 info->blocked_open--;
1832#ifdef SERIAL_DEBUG_OPEN
1833 printk("block_til_ready after blocking: %s, count = %d\n",
1834 tty->name, info->count);
1835 /**/
1836#endif
1837 if (retval)
1838 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 info->flags |= ASYNC_NORMAL_ACTIVE;
1840 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001841} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843/*
1844 * This routine is called whenever a serial port is opened. It
1845 * performs the serial-specific initialization for the tty structure.
1846 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001847int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001849 struct cyclades_port *info;
1850 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001853 line = tty->index;
1854 if ((line < 0) || (NR_PORTS <= line)) {
1855 return -ENODEV;
1856 }
1857 info = &cy_port[line];
1858 if (info->line < 0) {
1859 return -ENODEV;
1860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001862 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001864 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1865 return -ENODEV;
1866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001868 printk("cy_open %s, count = %d\n", tty->name, info->count);
1869 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001871 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001873 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001875 tty->driver_data = info;
1876 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001878 /*
1879 * Start up serial port
1880 */
1881 retval = startup(info);
1882 if (retval) {
1883 return retval;
1884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001886 retval = block_til_ready(tty, filp, info);
1887 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001889 printk("cy_open returning after block_til_ready with %d\n",
1890 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001892 return retval;
1893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001895 printk("cy_open done\n");
1896 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001898 return 0;
1899} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901/*
1902 * ---------------------------------------------------------------------
1903 * serial167_init() and friends
1904 *
1905 * serial167_init() is called at boot-time to initialize the serial driver.
1906 * ---------------------------------------------------------------------
1907 */
1908
1909/*
1910 * This routine prints out the appropriate serial driver version
1911 * number, and identifies which options were configured into this
1912 * driver.
1913 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001914static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001916 printk("MVME166/167 cd2401 driver\n");
1917} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919/* initialize chips on card -- return number of valid
1920 chips (which is number of ports/4) */
1921
1922/*
1923 * This initialises the hardware to a reasonable state. It should
1924 * probe the chip first so as to copy 166-Bug setup as a default for
1925 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1926 * as to limit the number of CyINIT_CHAN commands in normal running.
1927 *
1928 * ... I wonder what I should do if this fails ...
1929 */
1930
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001931void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001933 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 int ch;
1935 u_char spd;
1936 u_char rcor, rbpr, badspeed = 0;
1937 unsigned long flags;
1938
1939 local_irq_save(flags);
1940
1941 /*
1942 * First probe channel zero of the chip, to see what speed has
1943 * been selected.
1944 */
1945
1946 base_addr[CyCAR] = 0;
1947
1948 rcor = base_addr[CyRCOR] << 5;
1949 rbpr = base_addr[CyRBPR];
1950
1951 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1952 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1953 break;
1954 if (spd >= sizeof(baud_bpr)) {
1955 spd = 14; /* 19200 */
1956 badspeed = 1; /* Failed to identify speed */
1957 }
1958 initial_console_speed = spd;
1959
1960 /* OK, we have chosen a speed, now reset and reinitialise */
1961
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001962 my_udelay(20000L); /* Allow time for any active o/p to complete */
1963 if (base_addr[CyCCR] != 0x00) {
1964 local_irq_restore(flags);
1965 /* printk(" chip is never idle (CCR != 0)\n"); */
1966 return;
1967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001969 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1970 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001972 if (base_addr[CyGFRCR] == 0x00) {
1973 local_irq_restore(flags);
1974 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1975 return;
1976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
1978 /*
1979 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1980 * tick
1981 */
1982
1983 base_addr[CyTPR] = 10;
1984
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001985 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1986 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1987 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989 /*
1990 * Attempt to set up all channels to something reasonable, and
1991 * bang out a INIT_CHAN command. We should then be able to limit
Uwe Kleine-König9ddc5b62010-01-20 17:02:24 +01001992 * the amount of fiddling we have to do in normal running.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 */
1994
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001995 for (ch = 3; ch >= 0; ch--) {
1996 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 base_addr[CyIER] = 0;
1998 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001999 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 base_addr[CyLIVR] = 0x5c;
2001 base_addr[CyTCOR] = baud_co[spd];
2002 base_addr[CyTBPR] = baud_bpr[spd];
2003 base_addr[CyRCOR] = baud_co[spd] >> 5;
2004 base_addr[CyRBPR] = baud_bpr[spd];
2005 base_addr[CySCHR1] = 'Q' & 0x1f;
2006 base_addr[CySCHR2] = 'X' & 0x1f;
2007 base_addr[CySCRL] = 0;
2008 base_addr[CySCRH] = 0;
2009 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2010 base_addr[CyCOR2] = 0;
2011 base_addr[CyCOR3] = Cy_1_STOP;
2012 base_addr[CyCOR4] = baud_cor4[spd];
2013 base_addr[CyCOR5] = 0;
2014 base_addr[CyCOR6] = 0;
2015 base_addr[CyCOR7] = 0;
2016 base_addr[CyRTPRL] = 2;
2017 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002018 base_addr[CyMSVR1] = 0;
2019 base_addr[CyMSVR2] = 0;
2020 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022
2023 /*
2024 * Now do specials for channel zero....
2025 */
2026
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002027 base_addr[CyMSVR1] = CyRTS;
2028 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002030 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031
2032 local_irq_restore(flags);
2033
2034 my_udelay(20000L); /* Let it all settle down */
2035
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002036 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002038 printk
2039 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2040 rcor >> 5, rbpr);
2041} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002043static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 .open = cy_open,
2045 .close = cy_close,
2046 .write = cy_write,
2047 .put_char = cy_put_char,
2048 .flush_chars = cy_flush_chars,
2049 .write_room = cy_write_room,
2050 .chars_in_buffer = cy_chars_in_buffer,
2051 .flush_buffer = cy_flush_buffer,
2052 .ioctl = cy_ioctl,
2053 .throttle = cy_throttle,
2054 .unthrottle = cy_unthrottle,
2055 .set_termios = cy_set_termios,
2056 .stop = cy_stop,
2057 .start = cy_start,
2058 .hangup = cy_hangup,
2059 .tiocmget = cy_tiocmget,
2060 .tiocmset = cy_tiocmset,
2061};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002062
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063/* The serial driver boot-time initialization code!
2064 Hardware I/O ports are mapped to character special devices on a
2065 first found, first allocated manner. That is, this code searches
2066 for Cyclom cards in the system. As each is found, it is probed
2067 to discover how many chips (and thus how many ports) are present.
2068 These ports are mapped to the tty ports 64 and upward in monotonic
2069 fashion. If an 8-port card is replaced with a 16-port card, the
2070 port mapping on a following card will shift.
2071
2072 This approach is different from what is used in the other serial
2073 device driver because the Cyclom is more properly a multiplexer,
2074 not just an aggregation of serial ports on one card.
2075
2076 If there are more cards with more ports than have been statically
2077 allocated above, a warning is printed and the extra ports are ignored.
2078 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002079static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002081 struct cyclades_port *info;
2082 int ret = 0;
2083 int good_ports = 0;
2084 int port_num = 0;
2085 int index;
2086 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002088 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089#endif
2090
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002091 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2092 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002094 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2095 if (!cy_serial_driver)
2096 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
2098#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002099 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100#endif
2101
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002102 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002104 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2105 if (serial_console_cflag)
2106 DefSpeed = serial_console_cflag & 0017;
2107 else {
2108 DefSpeed = initial_console_speed;
2109 serial_console_info = &cy_port[0];
2110 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002112 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002115
2116 /* Initialize the tty_driver structure */
2117
2118 cy_serial_driver->owner = THIS_MODULE;
2119 cy_serial_driver->name = "ttyS";
2120 cy_serial_driver->major = TTY_MAJOR;
2121 cy_serial_driver->minor_start = 64;
2122 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2123 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2124 cy_serial_driver->init_termios = tty_std_termios;
2125 cy_serial_driver->init_termios.c_cflag =
2126 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2127 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2128 tty_set_operations(cy_serial_driver, &cy_ops);
2129
2130 ret = tty_register_driver(cy_serial_driver);
2131 if (ret) {
2132 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2133 put_tty_driver(cy_serial_driver);
2134 return ret;
2135 }
2136
2137 port_num = 0;
2138 info = cy_port;
2139 for (index = 0; index < 1; index++) {
2140
2141 good_ports = 4;
2142
2143 if (port_num < NR_PORTS) {
2144 while (good_ports-- && port_num < NR_PORTS) {
2145 /*** initialize port ***/
2146 info->magic = CYCLADES_MAGIC;
2147 info->type = PORT_CIRRUS;
2148 info->card = index;
2149 info->line = port_num;
2150 info->flags = STD_COM_FLAGS;
2151 info->tty = NULL;
2152 info->xmit_fifo_size = 12;
2153 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2154 info->cor2 = CyETC;
2155 info->cor3 = Cy_1_STOP;
2156 info->cor4 = 0x08; /* _very_ small receive threshold */
2157 info->cor5 = 0;
2158 info->cor6 = 0;
2159 info->cor7 = 0;
2160 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2161 info->tco = baud_co[DefSpeed]; /* Tx CO */
2162 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2163 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2164 info->close_delay = 0;
2165 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002166 info->count = 0;
2167#ifdef SERIAL_DEBUG_COUNT
2168 printk("cyc: %d: setting count to 0\n",
2169 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002171 info->blocked_open = 0;
2172 info->default_threshold = 0;
2173 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002174 init_waitqueue_head(&info->open_wait);
2175 init_waitqueue_head(&info->close_wait);
2176 /* info->session */
2177 /* info->pgrp */
2178/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2179 info->read_status_mask =
2180 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2181 CyFRAME | CyOVERRUN;
2182 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002184 printk("ttyS%d ", info->line);
2185 port_num++;
2186 info++;
2187 if (!(port_num & 7)) {
2188 printk("\n ");
2189 }
2190 }
2191 }
2192 printk("\n");
2193 }
2194 while (port_num < NR_PORTS) {
2195 info->line = -1;
2196 port_num++;
2197 info++;
2198 }
2199#ifdef CONFIG_REMOTE_DEBUG
2200 debug_setup();
2201#endif
2202 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2203 "cd2401_errors", cd2401_rxerr_interrupt);
2204 if (ret) {
2205 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2206 goto cleanup_serial_driver;
2207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002209 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2210 "cd2401_modem", cd2401_modem_interrupt);
2211 if (ret) {
2212 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2213 goto cleanup_irq_cd2401_errors;
2214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002216 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2217 "cd2401_txints", cd2401_tx_interrupt);
2218 if (ret) {
2219 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2220 goto cleanup_irq_cd2401_modem;
2221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002223 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2224 "cd2401_rxints", cd2401_rx_interrupt);
2225 if (ret) {
2226 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2227 goto cleanup_irq_cd2401_txints;
2228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002230 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002232 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2233 pcc2chip[PccSCCTICR] = 0x15;
2234 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002236 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2237
2238 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002240 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002242 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002244 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002246 if (tty_unregister_driver(cy_serial_driver))
2247 printk(KERN_ERR
2248 "Couldn't unregister MVME166/7 serial driver\n");
2249 put_tty_driver(cy_serial_driver);
2250 return ret;
2251} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
2253module_init(serial167_init);
2254
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002256static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002258 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2259 int channel;
2260 struct cyclades_port *info;
2261 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002263 info = &cy_port[line_num];
2264 channel = info->line;
2265 printk(" channel %d\n", channel);
2266 /**/ printk(" cy_port\n");
2267 printk(" card line flags = %d %d %x\n",
2268 info->card, info->line, info->flags);
2269 printk
2270 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2271 (long)info->tty, info->read_status_mask, info->timeout,
2272 info->xmit_fifo_size);
2273 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2274 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2275 info->cor6, info->cor7);
2276 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2277 info->rbpr, info->rco);
2278 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2279 info->event, info->count);
2280 printk(" x_char blocked_open = %x %x\n", info->x_char,
2281 info->blocked_open);
2282 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002284 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
2286/* Global Registers */
2287
2288 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2289 printk(" CyCAR %x\n", base_addr[CyCAR]);
2290 printk(" CyRISR %x\n", base_addr[CyRISR]);
2291 printk(" CyTISR %x\n", base_addr[CyTISR]);
2292 printk(" CyMISR %x\n", base_addr[CyMISR]);
2293 printk(" CyRIR %x\n", base_addr[CyRIR]);
2294 printk(" CyTIR %x\n", base_addr[CyTIR]);
2295 printk(" CyMIR %x\n", base_addr[CyMIR]);
2296 printk(" CyTPR %x\n", base_addr[CyTPR]);
2297
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002298 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
2300/* Virtual Registers */
2301
2302#if 0
2303 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2304 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2305 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2306 printk(" CyMISR %x\n", base_addr[CyMISR]);
2307#endif
2308
2309/* Channel Registers */
2310
2311 printk(" CyCCR %x\n", base_addr[CyCCR]);
2312 printk(" CyIER %x\n", base_addr[CyIER]);
2313 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2314 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2315 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2316 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2317 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2318#if 0
2319 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2320 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2321#endif
2322 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2323 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2324#if 0
2325 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2326 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2327 printk(" CySCRL %x\n", base_addr[CySCRL]);
2328 printk(" CySCRH %x\n", base_addr[CySCRH]);
2329 printk(" CyLNC %x\n", base_addr[CyLNC]);
2330 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2331 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2332#endif
2333 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2334 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2335 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2336 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2337 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2338 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2339 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2340 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2341
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002342 local_irq_restore(flags);
2343} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344#endif
2345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346#if 0
2347/* Dummy routine in mvme16x/config.c for now */
2348
2349/* Serial console setup. Called from linux/init/main.c */
2350
2351void console_setup(char *str, int *ints)
2352{
2353 char *s;
2354 int baud, bits, parity;
2355 int cflag = 0;
2356
2357 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002358 if (ints[0] > 3 || ints[1] > 3)
2359 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361 /* Get baud, bits and parity */
2362 baud = 2400;
2363 bits = 8;
2364 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002365 if (ints[2])
2366 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 if ((s = strchr(str, ','))) {
2368 do {
2369 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002370 } while (*s >= '0' && *s <= '9');
2371 if (*s)
2372 parity = *s++;
2373 if (*s)
2374 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 }
2376
2377 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002378 switch (baud) {
2379 case 1200:
2380 cflag |= B1200;
2381 break;
2382 case 9600:
2383 cflag |= B9600;
2384 break;
2385 case 19200:
2386 cflag |= B19200;
2387 break;
2388 case 38400:
2389 cflag |= B38400;
2390 break;
2391 case 2400:
2392 default:
2393 cflag |= B2400;
2394 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002396 switch (bits) {
2397 case 7:
2398 cflag |= CS7;
2399 break;
2400 default:
2401 case 8:
2402 cflag |= CS8;
2403 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002405 switch (parity) {
2406 case 'o':
2407 case 'O':
2408 cflag |= PARODD;
2409 break;
2410 case 'e':
2411 case 'E':
2412 cflag |= PARENB;
2413 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 }
2415
2416 serial_console_info = &cy_port[ints[1]];
2417 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002418 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419}
2420#endif
2421
2422/*
2423 * The following is probably out of date for 2.1.x serial console stuff.
2424 *
2425 * The console is registered early on from arch/m68k/kernel/setup.c, and
2426 * it therefore relies on the chip being setup correctly by 166-Bug. This
2427 * seems reasonable, as the serial port has been used to invoke the system
2428 * boot. It also means that this function must not rely on any data
2429 * initialisation performed by serial167_init() etc.
2430 *
2431 * Of course, once the console has been registered, we had better ensure
2432 * that serial167_init() doesn't leave the chip non-functional.
2433 *
2434 * The console must be locked when we get here.
2435 */
2436
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002437void serial167_console_write(struct console *co, const char *str,
2438 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002440 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 unsigned long flags;
2442 volatile u_char sink;
2443 u_char ier;
2444 int port;
2445 u_char do_lf = 0;
2446 int i = 0;
2447
2448 local_irq_save(flags);
2449
2450 /* Ensure transmitter is enabled! */
2451
2452 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002453 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 while (base_addr[CyCCR])
2455 ;
2456 base_addr[CyCCR] = CyENB_XMTR;
2457
2458 ier = base_addr[CyIER];
2459 base_addr[CyIER] = CyTxMpty;
2460
2461 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002462 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 /* We have a Tx int. Acknowledge it */
2464 sink = pcc2chip[PccTPIACKR];
2465 if ((base_addr[CyLICR] >> 2) == port) {
2466 if (i == count) {
2467 /* Last char of string is now output */
2468 base_addr[CyTEOIR] = CyNOTRANS;
2469 break;
2470 }
2471 if (do_lf) {
2472 base_addr[CyTDR] = '\n';
2473 str++;
2474 i++;
2475 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002476 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 base_addr[CyTDR] = '\r';
2478 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002479 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 base_addr[CyTDR] = *str++;
2481 i++;
2482 }
2483 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002484 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 base_addr[CyTEOIR] = CyNOTRANS;
2486 }
2487 }
2488
2489 base_addr[CyIER] = ier;
2490
2491 local_irq_restore(flags);
2492}
2493
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002494static struct tty_driver *serial167_console_device(struct console *c,
2495 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496{
2497 *index = c->index;
2498 return cy_serial_driver;
2499}
2500
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002502 .name = "ttyS",
2503 .write = serial167_console_write,
2504 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002505 .flags = CON_PRINTBUFFER,
2506 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507};
2508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509static int __init serial167_console_init(void)
2510{
2511 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002512 vme_brdtype == VME_TYPE_MVME167 ||
2513 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 mvme167_serial_console_setup(0);
2515 register_console(&sercons);
2516 }
2517 return 0;
2518}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002519
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520console_initcall(serial167_console_init);
2521
2522#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002523void putDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002525 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 unsigned long flags;
2527 volatile u_char sink;
2528 u_char ier;
2529 int port;
2530
2531 local_irq_save(flags);
2532
2533 /* Ensure transmitter is enabled! */
2534
2535 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002536 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 while (base_addr[CyCCR])
2538 ;
2539 base_addr[CyCCR] = CyENB_XMTR;
2540
2541 ier = base_addr[CyIER];
2542 base_addr[CyIER] = CyTxMpty;
2543
2544 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002545 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 /* We have a Tx int. Acknowledge it */
2547 sink = pcc2chip[PccTPIACKR];
2548 if ((base_addr[CyLICR] >> 2) == port) {
2549 base_addr[CyTDR] = c;
2550 base_addr[CyTEOIR] = 0;
2551 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002552 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 base_addr[CyTEOIR] = CyNOTRANS;
2554 }
2555 }
2556
2557 base_addr[CyIER] = ier;
2558
2559 local_irq_restore(flags);
2560}
2561
2562int getDebugChar()
2563{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002564 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 unsigned long flags;
2566 volatile u_char sink;
2567 u_char ier;
2568 int port;
2569 int i, c;
2570
2571 i = debugiq.out;
2572 if (i != debugiq.in) {
2573 c = debugiq.buf[i];
2574 if (++i == DEBUG_LEN)
2575 i = 0;
2576 debugiq.out = i;
2577 return c;
2578 }
2579 /* OK, nothing in queue, wait in poll loop */
2580
2581 local_irq_save(flags);
2582
2583 /* Ensure receiver is enabled! */
2584
2585 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002586 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587#if 0
2588 while (base_addr[CyCCR])
2589 ;
2590 base_addr[CyCCR] = CyENB_RCVR;
2591#endif
2592 ier = base_addr[CyIER];
2593 base_addr[CyIER] = CyRxData;
2594
2595 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002596 if (pcc2chip[PccSCCRICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 /* We have a Rx int. Acknowledge it */
2598 sink = pcc2chip[PccRPIACKR];
2599 if ((base_addr[CyLICR] >> 2) == port) {
2600 int cnt = base_addr[CyRFOC];
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002601 while (cnt-- > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 c = base_addr[CyRDR];
2603 if (c == 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002604 printk
2605 ("!! debug char is null (cnt=%d) !!",
2606 cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 else
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002608 queueDebugChar(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 }
2610 base_addr[CyREOIR] = 0;
2611 i = debugiq.out;
2612 if (i == debugiq.in)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002613 panic("Debug input queue empty!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 c = debugiq.buf[i];
2615 if (++i == DEBUG_LEN)
2616 i = 0;
2617 debugiq.out = i;
2618 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002619 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 base_addr[CyREOIR] = CyNOTRANS;
2621 }
2622 }
2623
2624 base_addr[CyIER] = ier;
2625
2626 local_irq_restore(flags);
2627
2628 return (c);
2629}
2630
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002631void queueDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632{
2633 int i;
2634
2635 i = debugiq.in;
2636 debugiq.buf[i] = c;
2637 if (++i == DEBUG_LEN)
2638 i = 0;
2639 if (i != debugiq.out)
2640 debugiq.in = i;
2641}
2642
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002643static void debug_setup()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002645 unsigned long flags;
2646 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2647 int i, cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002649 cflag = B19200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002651 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002653 for (i = 0; i < 4; i++) {
2654 base_addr[CyCAR] = i;
2655 base_addr[CyLICR] = i << 2;
2656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002658 debugiq.in = debugiq.out = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002660 base_addr[CyCAR] = DEBUG_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002662 /* baud rate */
2663 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002665 base_addr[CyIER] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002667 base_addr[CyCMR] = CyASYNC;
2668 base_addr[CyLICR] = DEBUG_PORT << 2;
2669 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002671 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002673 base_addr[CyTCOR] = baud_co[i];
2674 base_addr[CyTBPR] = baud_bpr[i];
2675 base_addr[CyRCOR] = baud_co[i] >> 5;
2676 base_addr[CyRBPR] = baud_bpr[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002678 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002680 base_addr[CySCHR1] = 0;
2681 base_addr[CySCHR2] = 0;
2682 base_addr[CySCRL] = 0;
2683 base_addr[CySCRH] = 0;
2684 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2685 base_addr[CyCOR2] = 0;
2686 base_addr[CyCOR3] = Cy_1_STOP;
2687 base_addr[CyCOR4] = baud_cor4[i];
2688 base_addr[CyCOR5] = 0;
2689 base_addr[CyCOR6] = 0;
2690 base_addr[CyCOR7] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002692 write_cy_cmd(base_addr, CyINIT_CHAN);
2693 write_cy_cmd(base_addr, CyENB_RCVR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002695 base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002697 base_addr[CyRTPRL] = 2;
2698 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002700 base_addr[CyMSVR1] = CyRTS;
2701 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002703 base_addr[CyIER] = CyRxData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002705 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002707} /* debug_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709#endif
2710
2711MODULE_LICENSE("GPL");