blob: 452370af95def5a352dd4753107ce3fd4154fb93 [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
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800661 len = tty_buffer_request_room(tty, char_count);
662 while (len--) {
663 data = base_addr[CyRDR];
664 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800666 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800668 }
669 tty_schedule_flip(tty);
670 }
671 /* end of service */
672 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
673 return IRQ_HANDLED;
674} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676/* This is called whenever a port becomes active;
677 interrupts are enabled and DTR & RTS are turned on.
678 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800679static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800681 unsigned long flags;
682 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
683 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800685 if (info->flags & ASYNC_INITIALIZED) {
686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800688
689 if (!info->type) {
690 if (info->tty) {
691 set_bit(TTY_IO_ERROR, &info->tty->flags);
692 }
693 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800695 if (!info->xmit_buf) {
696 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
697 if (!info->xmit_buf) {
698 return -ENOMEM;
699 }
700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800702 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800704 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800707 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708#endif
709
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800710 local_irq_save(flags);
711 base_addr[CyCAR] = (u_char) channel;
712 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800714 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 base_addr[CyMSVR1] = CyRTS;
716/* CP('S');CP('1'); */
717 base_addr[CyMSVR2] = CyDTR;
718
719#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800720 printk("cyc: %d: raising DTR\n", __LINE__);
721 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
722 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723#endif
724
725 base_addr[CyIER] |= CyRxData;
726 info->flags |= ASYNC_INITIALIZED;
727
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800728 if (info->tty) {
729 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
732
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800733 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800736 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800738 return 0;
739} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800741void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800743 unsigned long flags;
744 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
745 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800747 channel = info->line;
748 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 base_addr[CyCAR] = channel;
750 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800751 local_irq_restore(flags);
752} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754/*
755 * This routine shuts down a serial port; interrupts are disabled,
756 * and DTR is dropped if the hangup on close termio flag is on.
757 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800758static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800760 unsigned long flags;
761 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
762 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800764 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800766 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 }
768
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800769 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800771#ifdef SERIAL_DEBUG_OPEN
772 printk("shutdown channel %d\n", channel);
773#endif
774
775 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
776 SENT BEFORE DROPPING THE LINE !!! (Perhaps
777 set some flag that is read when XMTY happens.)
778 Other choices are to delay some fixed interval
779 or schedule some later processing.
780 */
781 local_irq_save(flags);
782 if (info->xmit_buf) {
783 free_page((unsigned long)info->xmit_buf);
784 info->xmit_buf = NULL;
785 }
786
787 base_addr[CyCAR] = (u_char) channel;
788 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
789 base_addr[CyMSVR1] = 0;
790/* CP('C');CP('1'); */
791 base_addr[CyMSVR2] = 0;
792#ifdef SERIAL_DEBUG_DTR
793 printk("cyc: %d: dropping DTR\n", __LINE__);
794 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
795 base_addr[CyMSVR2]);
796#endif
797 }
798 write_cy_cmd(base_addr, CyDIS_RCVR);
799 /* it may be appropriate to clear _XMIT at
800 some later date (after testing)!!! */
801
802 if (info->tty) {
803 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
805 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800806 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800809 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800811} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813/*
814 * This routine finds or computes the various line characteristics.
815 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800816static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800818 unsigned long flags;
819 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
820 int channel;
821 unsigned cflag;
822 int i;
823 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800825 if (!info->tty || !info->tty->termios) {
826 return;
827 }
828 if (info->line == -1) {
829 return;
830 }
831 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800833 /* baud rate */
834 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835#ifdef CBAUDEX
836/* Starting with kernel 1.1.65, there is direct support for
837 higher baud rates. The following code supports those
838 changes. The conditional aspect allows this driver to be
839 used for earlier as well as later kernel versions. (The
840 mapping is slightly different from serial.c because there
841 is still the possibility of supporting 75 kbit/sec with
842 the Cyclades board.)
843 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800844 if (i & CBAUDEX) {
845 if (i == B57600)
846 i = 16;
847 else if (i == B115200)
848 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800850 else if (i == B78600)
851 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800853 else
854 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800857 if (i == 15) {
858 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
859 i += 1;
860 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
861 i += 3;
862 }
863 /* Don't ever change the speed of the console port. It will
864 * run at the speed specified in bootinfo, or at 19.2K */
865 /* Actually, it should run at whatever speed 166Bug was using */
866 /* Note info->timeout isn't used at present */
867 if (info != serial_console_info) {
868 info->tbpr = baud_bpr[i]; /* Tx BPR */
869 info->tco = baud_co[i]; /* Tx CO */
870 info->rbpr = baud_bpr[i]; /* Rx BPR */
871 info->rco = baud_co[i] >> 5; /* Rx CO */
872 if (baud_table[i] == 134) {
873 info->timeout =
874 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
875 /* get it right for 134.5 baud */
876 } else if (baud_table[i]) {
877 info->timeout =
878 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
879 2;
880 /* this needs to be propagated into the card info */
881 } else {
882 info->timeout = 0;
883 }
884 }
885 /* By tradition (is it a standard?) a baud rate of zero
886 implies the line should be/has been closed. A bit
887 later in this routine such a test is performed. */
888
889 /* byte size and parity */
890 info->cor7 = 0;
891 info->cor6 = 0;
892 info->cor5 = 0;
893 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
894 /* Following two lines added 101295, RGH. */
895 /* It is obviously wrong to access CyCORx, and not info->corx here,
896 * try and remember to fix it later! */
897 channel = info->line;
898 base_addr[CyCAR] = (u_char) channel;
899 if (C_CLOCAL(info->tty)) {
900 if (base_addr[CyIER] & CyMdmCh)
901 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
902 /* ignore 1->0 modem transitions */
903 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
904 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
905 /* ignore 0->1 modem transitions */
906 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
907 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
908 } else {
909 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
910 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
911 /* act on 1->0 modem transitions */
912 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
913 (CyDSR | CyCTS | CyDCD))
914 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
915 /* act on 0->1 modem transitions */
916 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
917 (CyDSR | CyCTS | CyDCD))
918 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
919 }
920 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
921 info->cor2 = CyETC;
922 switch (cflag & CSIZE) {
923 case CS5:
924 info->cor1 = Cy_5_BITS;
925 break;
926 case CS6:
927 info->cor1 = Cy_6_BITS;
928 break;
929 case CS7:
930 info->cor1 = Cy_7_BITS;
931 break;
932 case CS8:
933 info->cor1 = Cy_8_BITS;
934 break;
935 }
936 if (cflag & PARENB) {
937 if (cflag & PARODD) {
938 info->cor1 |= CyPARITY_O;
939 } else {
940 info->cor1 |= CyPARITY_E;
941 }
942 } else {
943 info->cor1 |= CyPARITY_NONE;
944 }
945
946 /* CTS flow control flag */
947#if 0
948 /* Don't complcate matters for now! RGH 141095 */
949 if (cflag & CRTSCTS) {
950 info->flags |= ASYNC_CTS_FLOW;
951 info->cor2 |= CyCtsAE;
952 } else {
953 info->flags &= ~ASYNC_CTS_FLOW;
954 info->cor2 &= ~CyCtsAE;
955 }
956#endif
957 if (cflag & CLOCAL)
958 info->flags &= ~ASYNC_CHECK_CD;
959 else
960 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 /***********************************************
963 The hardware option, CyRtsAO, presents RTS when
964 the chip has characters to send. Since most modems
965 use RTS as reverse (inbound) flow control, this
966 option is not used. If inbound flow control is
967 necessary, DTR can be programmed to provide the
968 appropriate signals for use with a non-standard
969 cable. Contact Marcio Saito for details.
970 ***********************************************/
971
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800972 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800974 local_irq_save(flags);
975 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 /* CyCMR set once only in mvme167_init_serial() */
978 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800979 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800981 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800983 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800986 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800988 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800990 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800992 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800994 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 /* set line characteristics according configuration */
997
998 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800999 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001001 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001003 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001005 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001007 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001009 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001011 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001013 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001015 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001017 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001019 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001022 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001024 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 /* 2ms default rx timeout */
1027 ti = info->default_timeout ? info->default_timeout : 0x02;
1028 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001029 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001031 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001034 if (i == 0) { /* baud rate is zero, turn off line */
1035 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1036 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001038 printk("cyc: %d: dropping DTR\n", __LINE__);
1039 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1040 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001042 } else {
1043 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1044 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001046 printk("cyc: %d: raising DTR\n", __LINE__);
1047 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1048 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049#endif
1050 }
1051
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001052 if (info->tty) {
1053 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001056 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001058} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Alan Coxa5b08c62008-04-30 00:54:05 -07001060static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061{
Alan Coxc9f19e92009-01-02 13:47:26 +00001062 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001063 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001066 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067#endif
1068
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001069 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001070 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001072 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001073 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001075 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001077 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001078 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080
1081 info->xmit_buf[info->xmit_head++] = ch;
1082 info->xmit_head &= PAGE_SIZE - 1;
1083 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001084 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001085 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001086} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001088static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
Alan Coxc9f19e92009-01-02 13:47:26 +00001090 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001091 unsigned long flags;
1092 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1093 int channel;
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001096 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097#endif
1098
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001099 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1100 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001102 if (info->xmit_cnt <= 0 || tty->stopped
1103 || tty->hw_stopped || !info->xmit_buf)
1104 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001106 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001108 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 base_addr[CyCAR] = channel;
1110 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001111 local_irq_restore(flags);
1112} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114/* This routine gets called when tty_write has put something into
1115 the write_queue. If the port is not already transmitting stuff,
1116 start it off by enabling interrupts. The interrupt service
1117 routine will then ensure that the characters are sent. If the
1118 port is already active, there is no need to kick it.
1119 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001120static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
Alan Coxc9f19e92009-01-02 13:47:26 +00001122 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001123 unsigned long flags;
1124 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001127 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128#endif
1129
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001130 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1131 return 0;
1132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001134 if (!info->xmit_buf) {
1135 return 0;
1136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001138 while (1) {
1139 local_irq_save(flags);
1140 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1141 SERIAL_XMIT_SIZE - info->xmit_head));
1142 if (c <= 0) {
1143 local_irq_restore(flags);
1144 break;
1145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001147 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1148 info->xmit_head =
1149 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1150 info->xmit_cnt += c;
1151 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001153 buf += c;
1154 count -= c;
1155 total += c;
1156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001158 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1159 start_xmit(info);
1160 }
1161 return total;
1162} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001164static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
Alan Coxc9f19e92009-01-02 13:47:26 +00001166 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001167 int ret;
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001170 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171#endif
1172
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001173 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1174 return 0;
1175 ret = PAGE_SIZE - info->xmit_cnt - 1;
1176 if (ret < 0)
1177 ret = 0;
1178 return ret;
1179} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001181static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
Alan Coxc9f19e92009-01-02 13:47:26 +00001183 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001186 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187#endif
1188
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001189 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1190 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001192 return info->xmit_cnt;
1193} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001195static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
Alan Coxc9f19e92009-01-02 13:47:26 +00001197 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001198 unsigned long flags;
1199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001201 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202#endif
1203
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001204 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1205 return;
1206 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001208 local_irq_restore(flags);
1209 tty_wakeup(tty);
1210} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
1212/* This routine is called by the upper-layer tty layer to signal
1213 that incoming characters should be throttled or that the
1214 throttle should be released.
1215 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001216static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
Alan Coxc9f19e92009-01-02 13:47:26 +00001218 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001219 unsigned long flags;
1220 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1221 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001224 char buf[64];
1225
1226 printk("throttle %s: %d....\n", tty_name(tty, buf),
1227 tty->ldisc.chars_in_buffer(tty));
1228 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229#endif
1230
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001231 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1232 return;
1233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001235 if (I_IXOFF(tty)) {
1236 info->x_char = STOP_CHAR(tty);
1237 /* Should use the "Send Special Character" feature!!! */
1238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001240 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001242 local_irq_save(flags);
1243 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001245 local_irq_restore(flags);
1246} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001248static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
Alan Coxc9f19e92009-01-02 13:47:26 +00001250 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001251 unsigned long flags;
1252 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1253 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001256 char buf[64];
1257
1258 printk("throttle %s: %d....\n", tty_name(tty, buf),
1259 tty->ldisc.chars_in_buffer(tty));
1260 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261#endif
1262
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001263 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1264 return;
1265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001267 if (I_IXOFF(tty)) {
1268 info->x_char = START_CHAR(tty);
1269 /* Should use the "Send Special Character" feature!!! */
1270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001272 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001274 local_irq_save(flags);
1275 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001277 local_irq_restore(flags);
1278} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001281get_serial_info(struct cyclades_port *info,
1282 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001284 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001287 if (!retinfo)
1288 return -EFAULT;
1289 memset(&tmp, 0, sizeof(tmp));
1290 tmp.type = info->type;
1291 tmp.line = info->line;
1292 tmp.port = info->line;
1293 tmp.irq = 0;
1294 tmp.flags = info->flags;
1295 tmp.baud_base = 0; /*!!! */
1296 tmp.close_delay = info->close_delay;
1297 tmp.custom_divisor = 0; /*!!! */
1298 tmp.hub6 = 0; /*!!! */
1299 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1300} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001303set_serial_info(struct cyclades_port *info,
1304 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001306 struct serial_struct new_serial;
1307 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001310 if (!new_info)
1311 return -EFAULT;
1312 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1313 return -EFAULT;
1314 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001316 if (!capable(CAP_SYS_ADMIN)) {
1317 if ((new_serial.close_delay != info->close_delay) ||
1318 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1319 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1320 return -EPERM;
1321 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1322 (new_serial.flags & ASYNC_USR_MASK));
1323 goto check_and_exit;
1324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001326 /*
1327 * OK, past this point, all the error checking has been done.
1328 * At this point, we start making changes.....
1329 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001331 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1332 (new_serial.flags & ASYNC_FLAGS));
1333 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
1335check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001336 if (info->flags & ASYNC_INITIALIZED) {
1337 config_setup(info);
1338 return 0;
1339 }
1340 return startup(info);
1341} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001343static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
Alan Coxc9f19e92009-01-02 13:47:26 +00001345 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001346 int channel;
1347 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1348 unsigned long flags;
1349 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001351 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001353 local_irq_save(flags);
1354 base_addr[CyCAR] = (u_char) channel;
1355 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1356 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001358 return ((status & CyRTS) ? TIOCM_RTS : 0)
1359 | ((status & CyDTR) ? TIOCM_DTR : 0)
1360 | ((status & CyDCD) ? TIOCM_CAR : 0)
1361 | ((status & CyDSR) ? TIOCM_DSR : 0)
1362 | ((status & CyCTS) ? TIOCM_CTS : 0);
1363} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
1365static int
1366cy_tiocmset(struct tty_struct *tty, struct file *file,
1367 unsigned int set, unsigned int clear)
1368{
Alan Coxc9f19e92009-01-02 13:47:26 +00001369 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001370 int channel;
1371 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1372 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001374 channel = info->line;
1375
1376 if (set & TIOCM_RTS) {
1377 local_irq_save(flags);
1378 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001380 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001382 if (set & TIOCM_DTR) {
1383 local_irq_save(flags);
1384 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001386 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001388 printk("cyc: %d: raising DTR\n", __LINE__);
1389 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1390 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001392 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
1394
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001395 if (clear & TIOCM_RTS) {
1396 local_irq_save(flags);
1397 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001399 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001401 if (clear & TIOCM_DTR) {
1402 local_irq_save(flags);
1403 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001405 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001407 printk("cyc: %d: dropping DTR\n", __LINE__);
1408 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1409 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001411 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001414 return 0;
1415} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001417static void send_break(struct cyclades_port *info, int duration)
1418{ /* Let the transmit ISR take care of this (since it
1419 requires stuffing characters into the output stream).
1420 */
1421 info->x_break = duration;
1422 if (!info->xmit_cnt) {
1423 start_xmit(info);
1424 }
1425} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
1427static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001428get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
1430
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001431 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1432 return -EFAULT;
1433 info->mon.int_count = 0;
1434 info->mon.char_count = 0;
1435 info->mon.char_max = 0;
1436 info->mon.char_last = 0;
1437 return 0;
1438}
1439
1440static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1441{
1442 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1443 unsigned long value;
1444 int channel;
1445
1446 if (get_user(value, arg))
1447 return -EFAULT;
1448
1449 channel = info->line;
1450 info->cor4 &= ~CyREC_FIFO;
1451 info->cor4 |= value & CyREC_FIFO;
1452 base_addr[CyCOR4] = info->cor4;
1453 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454}
1455
1456static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001457get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001459 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1460 int channel;
1461 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001463 channel = info->line;
1464
1465 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1466 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467}
1468
1469static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001470set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001472 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001474 if (get_user(value, arg))
1475 return -EFAULT;
1476
1477 info->default_threshold = value & 0x0f;
1478 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479}
1480
1481static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001482get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001484 return put_user(info->default_threshold, value);
1485}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001487static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1488{
1489 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1490 int channel;
1491 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001493 if (get_user(value, arg))
1494 return -EFAULT;
1495
1496 channel = info->line;
1497
1498 base_addr[CyRTPRL] = value & 0xff;
1499 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1500 return 0;
1501}
1502
1503static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1504{
1505 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1506 int channel;
1507 unsigned long tmp;
1508
1509 channel = info->line;
1510
1511 tmp = base_addr[CyRTPRL];
1512 return put_user(tmp, value);
1513}
1514
1515static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1516{
1517 info->default_timeout = value & 0xff;
1518 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519}
1520
1521static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001522get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001524 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525}
1526
1527static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001528cy_ioctl(struct tty_struct *tty, struct file *file,
1529 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001531 unsigned long val;
Alan Coxc9f19e92009-01-02 13:47:26 +00001532 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001533 int ret_val = 0;
1534 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
1536#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001537 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538#endif
1539
Alan Cox638157b2008-04-30 00:53:22 -07001540 lock_kernel();
1541
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001542 switch (cmd) {
1543 case CYGETMON:
1544 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001546 case CYGETTHRESH:
1547 ret_val = get_threshold(info, argp);
1548 break;
1549 case CYSETTHRESH:
1550 ret_val = set_threshold(info, argp);
1551 break;
1552 case CYGETDEFTHRESH:
1553 ret_val = get_default_threshold(info, argp);
1554 break;
1555 case CYSETDEFTHRESH:
1556 ret_val = set_default_threshold(info, argp);
1557 break;
1558 case CYGETTIMEOUT:
1559 ret_val = get_timeout(info, argp);
1560 break;
1561 case CYSETTIMEOUT:
1562 ret_val = set_timeout(info, argp);
1563 break;
1564 case CYGETDEFTIMEOUT:
1565 ret_val = get_default_timeout(info, argp);
1566 break;
1567 case CYSETDEFTIMEOUT:
1568 ret_val = set_default_timeout(info, (unsigned long)arg);
1569 break;
1570 case TCSBRK: /* SVID version: non-zero arg --> no break */
1571 ret_val = tty_check_change(tty);
1572 if (ret_val)
1573 break;
1574 tty_wait_until_sent(tty, 0);
1575 if (!arg)
1576 send_break(info, HZ / 4); /* 1/4 second */
1577 break;
1578 case TCSBRKP: /* support for POSIX tcsendbreak() */
1579 ret_val = tty_check_change(tty);
1580 if (ret_val)
1581 break;
1582 tty_wait_until_sent(tty, 0);
1583 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1584 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
1586/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001587 case TIOCGSERIAL:
1588 ret_val = get_serial_info(info, argp);
1589 break;
1590 case TIOCSSERIAL:
1591 ret_val = set_serial_info(info, argp);
1592 break;
1593 default:
1594 ret_val = -ENOIOCTLCMD;
1595 }
Alan Cox638157b2008-04-30 00:53:22 -07001596 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001599 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600#endif
1601
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001602 return ret_val;
1603} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001605static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606{
Alan Coxc9f19e92009-01-02 13:47:26 +00001607 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
1609#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001610 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611#endif
1612
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001613 if (tty->termios->c_cflag == old_termios->c_cflag)
1614 return;
1615 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001617 if ((old_termios->c_cflag & CRTSCTS) &&
1618 !(tty->termios->c_cflag & CRTSCTS)) {
1619 tty->stopped = 0;
1620 cy_start(tty);
1621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001623 if (!(old_termios->c_cflag & CLOCAL) &&
1624 (tty->termios->c_cflag & CLOCAL))
1625 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001627} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001629static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630{
Alan Coxc9f19e92009-01-02 13:47:26 +00001631 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633/* CP('C'); */
1634#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001635 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636#endif
1637
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001638 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1639 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001641#ifdef SERIAL_DEBUG_OPEN
1642 printk("cy_close %s, count = %d\n", tty->name, info->count);
1643#endif
1644
1645 if ((tty->count == 1) && (info->count != 1)) {
1646 /*
1647 * Uh, oh. tty->count is 1, which means that the tty
1648 * structure will be freed. Info->count should always
1649 * be one in these conditions. If it's greater than
1650 * one, we've got real problems, since it means the
1651 * serial port won't be shutdown.
1652 */
1653 printk("cy_close: bad serial port count; tty->count is 1, "
1654 "info->count is %d\n", info->count);
1655 info->count = 1;
1656 }
1657#ifdef SERIAL_DEBUG_COUNT
1658 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1659 info->count - 1);
1660#endif
1661 if (--info->count < 0) {
1662 printk("cy_close: bad serial port count for ttys%d: %d\n",
1663 info->line, info->count);
1664#ifdef SERIAL_DEBUG_COUNT
1665 printk("cyc: %d: setting count to 0\n", __LINE__);
1666#endif
1667 info->count = 0;
1668 }
1669 if (info->count)
1670 return;
1671 info->flags |= ASYNC_CLOSING;
1672 if (info->flags & ASYNC_INITIALIZED)
1673 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1674 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001675 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001676 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001677 info->tty = NULL;
1678 if (info->blocked_open) {
1679 if (info->close_delay) {
1680 msleep_interruptible(jiffies_to_msecs
1681 (info->close_delay));
1682 }
1683 wake_up_interruptible(&info->open_wait);
1684 }
1685 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1686 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001689 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001691} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693/*
1694 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1695 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001696void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
Alan Coxc9f19e92009-01-02 13:47:26 +00001698 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001701 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702#endif
1703
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001704 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1705 return;
1706
1707 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001709 info->event = 0;
1710 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001712 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001714 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001716 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1717 wake_up_interruptible(&info->open_wait);
1718} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
1720/*
1721 * ------------------------------------------------------------
1722 * cy_open() and friends
1723 * ------------------------------------------------------------
1724 */
1725
1726static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001727block_til_ready(struct tty_struct *tty, struct file *filp,
1728 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001730 DECLARE_WAITQUEUE(wait, current);
1731 unsigned long flags;
1732 int channel;
1733 int retval;
1734 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001736 /*
1737 * If the device is in the middle of being closed, then block
1738 * until it's done, and then try again.
1739 */
1740 if (info->flags & ASYNC_CLOSING) {
1741 interruptible_sleep_on(&info->close_wait);
1742 if (info->flags & ASYNC_HUP_NOTIFY) {
1743 return -EAGAIN;
1744 } else {
1745 return -ERESTARTSYS;
1746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001749 /*
1750 * If non-blocking mode is set, then make the check up front
1751 * and then exit.
1752 */
1753 if (filp->f_flags & O_NONBLOCK) {
1754 info->flags |= ASYNC_NORMAL_ACTIVE;
1755 return 0;
1756 }
1757
1758 /*
1759 * Block waiting for the carrier detect and the line to become
1760 * free (i.e., not in use by the callout). While we are in
1761 * this loop, info->count is dropped by one, so that
1762 * cy_close() knows when to free things. We restore it upon
1763 * exit, either normal or abnormal.
1764 */
1765 retval = 0;
1766 add_wait_queue(&info->open_wait, &wait);
1767#ifdef SERIAL_DEBUG_OPEN
1768 printk("block_til_ready before block: %s, count = %d\n",
1769 tty->name, info->count);
1770 /**/
1771#endif
1772 info->count--;
1773#ifdef SERIAL_DEBUG_COUNT
1774 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1775#endif
1776 info->blocked_open++;
1777
1778 channel = info->line;
1779
1780 while (1) {
1781 local_irq_save(flags);
1782 base_addr[CyCAR] = (u_char) channel;
1783 base_addr[CyMSVR1] = CyRTS;
1784/* CP('S');CP('4'); */
1785 base_addr[CyMSVR2] = CyDTR;
1786#ifdef SERIAL_DEBUG_DTR
1787 printk("cyc: %d: raising DTR\n", __LINE__);
1788 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1789 base_addr[CyMSVR2]);
1790#endif
1791 local_irq_restore(flags);
1792 set_current_state(TASK_INTERRUPTIBLE);
1793 if (tty_hung_up_p(filp)
1794 || !(info->flags & ASYNC_INITIALIZED)) {
1795 if (info->flags & ASYNC_HUP_NOTIFY) {
1796 retval = -EAGAIN;
1797 } else {
1798 retval = -ERESTARTSYS;
1799 }
1800 break;
1801 }
1802 local_irq_save(flags);
1803 base_addr[CyCAR] = (u_char) channel;
1804/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1805 if (!(info->flags & ASYNC_CLOSING)
1806 && (C_CLOCAL(tty)
1807 || (base_addr[CyMSVR1] & CyDCD))) {
1808 local_irq_restore(flags);
1809 break;
1810 }
1811 local_irq_restore(flags);
1812 if (signal_pending(current)) {
1813 retval = -ERESTARTSYS;
1814 break;
1815 }
1816#ifdef SERIAL_DEBUG_OPEN
1817 printk("block_til_ready blocking: %s, count = %d\n",
1818 tty->name, info->count);
1819 /**/
1820#endif
1821 schedule();
1822 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001823 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001824 remove_wait_queue(&info->open_wait, &wait);
1825 if (!tty_hung_up_p(filp)) {
1826 info->count++;
1827#ifdef SERIAL_DEBUG_COUNT
1828 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1829 info->count);
1830#endif
1831 }
1832 info->blocked_open--;
1833#ifdef SERIAL_DEBUG_OPEN
1834 printk("block_til_ready after blocking: %s, count = %d\n",
1835 tty->name, info->count);
1836 /**/
1837#endif
1838 if (retval)
1839 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 info->flags |= ASYNC_NORMAL_ACTIVE;
1841 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001842} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844/*
1845 * This routine is called whenever a serial port is opened. It
1846 * performs the serial-specific initialization for the tty structure.
1847 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001848int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001850 struct cyclades_port *info;
1851 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001854 line = tty->index;
1855 if ((line < 0) || (NR_PORTS <= line)) {
1856 return -ENODEV;
1857 }
1858 info = &cy_port[line];
1859 if (info->line < 0) {
1860 return -ENODEV;
1861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001863 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001865 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1866 return -ENODEV;
1867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001869 printk("cy_open %s, count = %d\n", tty->name, info->count);
1870 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001872 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001874 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001876 tty->driver_data = info;
1877 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001879 /*
1880 * Start up serial port
1881 */
1882 retval = startup(info);
1883 if (retval) {
1884 return retval;
1885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001887 retval = block_til_ready(tty, filp, info);
1888 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001890 printk("cy_open returning after block_til_ready with %d\n",
1891 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001893 return retval;
1894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001896 printk("cy_open done\n");
1897 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001899 return 0;
1900} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902/*
1903 * ---------------------------------------------------------------------
1904 * serial167_init() and friends
1905 *
1906 * serial167_init() is called at boot-time to initialize the serial driver.
1907 * ---------------------------------------------------------------------
1908 */
1909
1910/*
1911 * This routine prints out the appropriate serial driver version
1912 * number, and identifies which options were configured into this
1913 * driver.
1914 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001915static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001917 printk("MVME166/167 cd2401 driver\n");
1918} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920/* initialize chips on card -- return number of valid
1921 chips (which is number of ports/4) */
1922
1923/*
1924 * This initialises the hardware to a reasonable state. It should
1925 * probe the chip first so as to copy 166-Bug setup as a default for
1926 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1927 * as to limit the number of CyINIT_CHAN commands in normal running.
1928 *
1929 * ... I wonder what I should do if this fails ...
1930 */
1931
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001932void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001934 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 int ch;
1936 u_char spd;
1937 u_char rcor, rbpr, badspeed = 0;
1938 unsigned long flags;
1939
1940 local_irq_save(flags);
1941
1942 /*
1943 * First probe channel zero of the chip, to see what speed has
1944 * been selected.
1945 */
1946
1947 base_addr[CyCAR] = 0;
1948
1949 rcor = base_addr[CyRCOR] << 5;
1950 rbpr = base_addr[CyRBPR];
1951
1952 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1953 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1954 break;
1955 if (spd >= sizeof(baud_bpr)) {
1956 spd = 14; /* 19200 */
1957 badspeed = 1; /* Failed to identify speed */
1958 }
1959 initial_console_speed = spd;
1960
1961 /* OK, we have chosen a speed, now reset and reinitialise */
1962
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001963 my_udelay(20000L); /* Allow time for any active o/p to complete */
1964 if (base_addr[CyCCR] != 0x00) {
1965 local_irq_restore(flags);
1966 /* printk(" chip is never idle (CCR != 0)\n"); */
1967 return;
1968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001970 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1971 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001973 if (base_addr[CyGFRCR] == 0x00) {
1974 local_irq_restore(flags);
1975 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1976 return;
1977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
1979 /*
1980 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1981 * tick
1982 */
1983
1984 base_addr[CyTPR] = 10;
1985
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001986 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1987 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1988 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
1990 /*
1991 * Attempt to set up all channels to something reasonable, and
1992 * bang out a INIT_CHAN command. We should then be able to limit
1993 * the ammount of fiddling we have to do in normal running.
1994 */
1995
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001996 for (ch = 3; ch >= 0; ch--) {
1997 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 base_addr[CyIER] = 0;
1999 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002000 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 base_addr[CyLIVR] = 0x5c;
2002 base_addr[CyTCOR] = baud_co[spd];
2003 base_addr[CyTBPR] = baud_bpr[spd];
2004 base_addr[CyRCOR] = baud_co[spd] >> 5;
2005 base_addr[CyRBPR] = baud_bpr[spd];
2006 base_addr[CySCHR1] = 'Q' & 0x1f;
2007 base_addr[CySCHR2] = 'X' & 0x1f;
2008 base_addr[CySCRL] = 0;
2009 base_addr[CySCRH] = 0;
2010 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2011 base_addr[CyCOR2] = 0;
2012 base_addr[CyCOR3] = Cy_1_STOP;
2013 base_addr[CyCOR4] = baud_cor4[spd];
2014 base_addr[CyCOR5] = 0;
2015 base_addr[CyCOR6] = 0;
2016 base_addr[CyCOR7] = 0;
2017 base_addr[CyRTPRL] = 2;
2018 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002019 base_addr[CyMSVR1] = 0;
2020 base_addr[CyMSVR2] = 0;
2021 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 }
2023
2024 /*
2025 * Now do specials for channel zero....
2026 */
2027
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002028 base_addr[CyMSVR1] = CyRTS;
2029 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002031 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033 local_irq_restore(flags);
2034
2035 my_udelay(20000L); /* Let it all settle down */
2036
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002037 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002039 printk
2040 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2041 rcor >> 5, rbpr);
2042} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002044static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 .open = cy_open,
2046 .close = cy_close,
2047 .write = cy_write,
2048 .put_char = cy_put_char,
2049 .flush_chars = cy_flush_chars,
2050 .write_room = cy_write_room,
2051 .chars_in_buffer = cy_chars_in_buffer,
2052 .flush_buffer = cy_flush_buffer,
2053 .ioctl = cy_ioctl,
2054 .throttle = cy_throttle,
2055 .unthrottle = cy_unthrottle,
2056 .set_termios = cy_set_termios,
2057 .stop = cy_stop,
2058 .start = cy_start,
2059 .hangup = cy_hangup,
2060 .tiocmget = cy_tiocmget,
2061 .tiocmset = cy_tiocmset,
2062};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002063
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064/* The serial driver boot-time initialization code!
2065 Hardware I/O ports are mapped to character special devices on a
2066 first found, first allocated manner. That is, this code searches
2067 for Cyclom cards in the system. As each is found, it is probed
2068 to discover how many chips (and thus how many ports) are present.
2069 These ports are mapped to the tty ports 64 and upward in monotonic
2070 fashion. If an 8-port card is replaced with a 16-port card, the
2071 port mapping on a following card will shift.
2072
2073 This approach is different from what is used in the other serial
2074 device driver because the Cyclom is more properly a multiplexer,
2075 not just an aggregation of serial ports on one card.
2076
2077 If there are more cards with more ports than have been statically
2078 allocated above, a warning is printed and the extra ports are ignored.
2079 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002080static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002082 struct cyclades_port *info;
2083 int ret = 0;
2084 int good_ports = 0;
2085 int port_num = 0;
2086 int index;
2087 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002089 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090#endif
2091
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002092 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2093 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002095 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2096 if (!cy_serial_driver)
2097 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
2099#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002100 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101#endif
2102
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002103 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002105 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2106 if (serial_console_cflag)
2107 DefSpeed = serial_console_cflag & 0017;
2108 else {
2109 DefSpeed = initial_console_speed;
2110 serial_console_info = &cy_port[0];
2111 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002113 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002116
2117 /* Initialize the tty_driver structure */
2118
2119 cy_serial_driver->owner = THIS_MODULE;
2120 cy_serial_driver->name = "ttyS";
2121 cy_serial_driver->major = TTY_MAJOR;
2122 cy_serial_driver->minor_start = 64;
2123 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2124 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2125 cy_serial_driver->init_termios = tty_std_termios;
2126 cy_serial_driver->init_termios.c_cflag =
2127 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2128 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2129 tty_set_operations(cy_serial_driver, &cy_ops);
2130
2131 ret = tty_register_driver(cy_serial_driver);
2132 if (ret) {
2133 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2134 put_tty_driver(cy_serial_driver);
2135 return ret;
2136 }
2137
2138 port_num = 0;
2139 info = cy_port;
2140 for (index = 0; index < 1; index++) {
2141
2142 good_ports = 4;
2143
2144 if (port_num < NR_PORTS) {
2145 while (good_ports-- && port_num < NR_PORTS) {
2146 /*** initialize port ***/
2147 info->magic = CYCLADES_MAGIC;
2148 info->type = PORT_CIRRUS;
2149 info->card = index;
2150 info->line = port_num;
2151 info->flags = STD_COM_FLAGS;
2152 info->tty = NULL;
2153 info->xmit_fifo_size = 12;
2154 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2155 info->cor2 = CyETC;
2156 info->cor3 = Cy_1_STOP;
2157 info->cor4 = 0x08; /* _very_ small receive threshold */
2158 info->cor5 = 0;
2159 info->cor6 = 0;
2160 info->cor7 = 0;
2161 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2162 info->tco = baud_co[DefSpeed]; /* Tx CO */
2163 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2164 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2165 info->close_delay = 0;
2166 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002167 info->count = 0;
2168#ifdef SERIAL_DEBUG_COUNT
2169 printk("cyc: %d: setting count to 0\n",
2170 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002172 info->blocked_open = 0;
2173 info->default_threshold = 0;
2174 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002175 init_waitqueue_head(&info->open_wait);
2176 init_waitqueue_head(&info->close_wait);
2177 /* info->session */
2178 /* info->pgrp */
2179/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2180 info->read_status_mask =
2181 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2182 CyFRAME | CyOVERRUN;
2183 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002185 printk("ttyS%d ", info->line);
2186 port_num++;
2187 info++;
2188 if (!(port_num & 7)) {
2189 printk("\n ");
2190 }
2191 }
2192 }
2193 printk("\n");
2194 }
2195 while (port_num < NR_PORTS) {
2196 info->line = -1;
2197 port_num++;
2198 info++;
2199 }
2200#ifdef CONFIG_REMOTE_DEBUG
2201 debug_setup();
2202#endif
2203 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2204 "cd2401_errors", cd2401_rxerr_interrupt);
2205 if (ret) {
2206 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2207 goto cleanup_serial_driver;
2208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002210 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2211 "cd2401_modem", cd2401_modem_interrupt);
2212 if (ret) {
2213 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2214 goto cleanup_irq_cd2401_errors;
2215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002217 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2218 "cd2401_txints", cd2401_tx_interrupt);
2219 if (ret) {
2220 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2221 goto cleanup_irq_cd2401_modem;
2222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002224 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2225 "cd2401_rxints", cd2401_rx_interrupt);
2226 if (ret) {
2227 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2228 goto cleanup_irq_cd2401_txints;
2229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002231 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002233 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2234 pcc2chip[PccSCCTICR] = 0x15;
2235 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002237 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2238
2239 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002241 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002243 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002245 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002247 if (tty_unregister_driver(cy_serial_driver))
2248 printk(KERN_ERR
2249 "Couldn't unregister MVME166/7 serial driver\n");
2250 put_tty_driver(cy_serial_driver);
2251 return ret;
2252} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
2254module_init(serial167_init);
2255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002257static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002259 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2260 int channel;
2261 struct cyclades_port *info;
2262 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002264 info = &cy_port[line_num];
2265 channel = info->line;
2266 printk(" channel %d\n", channel);
2267 /**/ printk(" cy_port\n");
2268 printk(" card line flags = %d %d %x\n",
2269 info->card, info->line, info->flags);
2270 printk
2271 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2272 (long)info->tty, info->read_status_mask, info->timeout,
2273 info->xmit_fifo_size);
2274 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2275 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2276 info->cor6, info->cor7);
2277 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2278 info->rbpr, info->rco);
2279 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2280 info->event, info->count);
2281 printk(" x_char blocked_open = %x %x\n", info->x_char,
2282 info->blocked_open);
2283 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002285 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
2287/* Global Registers */
2288
2289 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2290 printk(" CyCAR %x\n", base_addr[CyCAR]);
2291 printk(" CyRISR %x\n", base_addr[CyRISR]);
2292 printk(" CyTISR %x\n", base_addr[CyTISR]);
2293 printk(" CyMISR %x\n", base_addr[CyMISR]);
2294 printk(" CyRIR %x\n", base_addr[CyRIR]);
2295 printk(" CyTIR %x\n", base_addr[CyTIR]);
2296 printk(" CyMIR %x\n", base_addr[CyMIR]);
2297 printk(" CyTPR %x\n", base_addr[CyTPR]);
2298
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002299 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
2301/* Virtual Registers */
2302
2303#if 0
2304 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2305 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2306 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2307 printk(" CyMISR %x\n", base_addr[CyMISR]);
2308#endif
2309
2310/* Channel Registers */
2311
2312 printk(" CyCCR %x\n", base_addr[CyCCR]);
2313 printk(" CyIER %x\n", base_addr[CyIER]);
2314 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2315 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2316 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2317 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2318 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2319#if 0
2320 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2321 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2322#endif
2323 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2324 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2325#if 0
2326 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2327 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2328 printk(" CySCRL %x\n", base_addr[CySCRL]);
2329 printk(" CySCRH %x\n", base_addr[CySCRH]);
2330 printk(" CyLNC %x\n", base_addr[CyLNC]);
2331 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2332 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2333#endif
2334 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2335 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2336 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2337 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2338 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2339 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2340 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2341 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2342
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002343 local_irq_restore(flags);
2344} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345#endif
2346
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347#if 0
2348/* Dummy routine in mvme16x/config.c for now */
2349
2350/* Serial console setup. Called from linux/init/main.c */
2351
2352void console_setup(char *str, int *ints)
2353{
2354 char *s;
2355 int baud, bits, parity;
2356 int cflag = 0;
2357
2358 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002359 if (ints[0] > 3 || ints[1] > 3)
2360 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
2362 /* Get baud, bits and parity */
2363 baud = 2400;
2364 bits = 8;
2365 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002366 if (ints[2])
2367 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if ((s = strchr(str, ','))) {
2369 do {
2370 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002371 } while (*s >= '0' && *s <= '9');
2372 if (*s)
2373 parity = *s++;
2374 if (*s)
2375 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 }
2377
2378 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002379 switch (baud) {
2380 case 1200:
2381 cflag |= B1200;
2382 break;
2383 case 9600:
2384 cflag |= B9600;
2385 break;
2386 case 19200:
2387 cflag |= B19200;
2388 break;
2389 case 38400:
2390 cflag |= B38400;
2391 break;
2392 case 2400:
2393 default:
2394 cflag |= B2400;
2395 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002397 switch (bits) {
2398 case 7:
2399 cflag |= CS7;
2400 break;
2401 default:
2402 case 8:
2403 cflag |= CS8;
2404 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002406 switch (parity) {
2407 case 'o':
2408 case 'O':
2409 cflag |= PARODD;
2410 break;
2411 case 'e':
2412 case 'E':
2413 cflag |= PARENB;
2414 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 }
2416
2417 serial_console_info = &cy_port[ints[1]];
2418 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002419 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420}
2421#endif
2422
2423/*
2424 * The following is probably out of date for 2.1.x serial console stuff.
2425 *
2426 * The console is registered early on from arch/m68k/kernel/setup.c, and
2427 * it therefore relies on the chip being setup correctly by 166-Bug. This
2428 * seems reasonable, as the serial port has been used to invoke the system
2429 * boot. It also means that this function must not rely on any data
2430 * initialisation performed by serial167_init() etc.
2431 *
2432 * Of course, once the console has been registered, we had better ensure
2433 * that serial167_init() doesn't leave the chip non-functional.
2434 *
2435 * The console must be locked when we get here.
2436 */
2437
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002438void serial167_console_write(struct console *co, const char *str,
2439 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002441 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 unsigned long flags;
2443 volatile u_char sink;
2444 u_char ier;
2445 int port;
2446 u_char do_lf = 0;
2447 int i = 0;
2448
2449 local_irq_save(flags);
2450
2451 /* Ensure transmitter is enabled! */
2452
2453 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002454 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 while (base_addr[CyCCR])
2456 ;
2457 base_addr[CyCCR] = CyENB_XMTR;
2458
2459 ier = base_addr[CyIER];
2460 base_addr[CyIER] = CyTxMpty;
2461
2462 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002463 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 /* We have a Tx int. Acknowledge it */
2465 sink = pcc2chip[PccTPIACKR];
2466 if ((base_addr[CyLICR] >> 2) == port) {
2467 if (i == count) {
2468 /* Last char of string is now output */
2469 base_addr[CyTEOIR] = CyNOTRANS;
2470 break;
2471 }
2472 if (do_lf) {
2473 base_addr[CyTDR] = '\n';
2474 str++;
2475 i++;
2476 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002477 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 base_addr[CyTDR] = '\r';
2479 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002480 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 base_addr[CyTDR] = *str++;
2482 i++;
2483 }
2484 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002485 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 base_addr[CyTEOIR] = CyNOTRANS;
2487 }
2488 }
2489
2490 base_addr[CyIER] = ier;
2491
2492 local_irq_restore(flags);
2493}
2494
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002495static struct tty_driver *serial167_console_device(struct console *c,
2496 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497{
2498 *index = c->index;
2499 return cy_serial_driver;
2500}
2501
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002503 .name = "ttyS",
2504 .write = serial167_console_write,
2505 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002506 .flags = CON_PRINTBUFFER,
2507 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508};
2509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510static int __init serial167_console_init(void)
2511{
2512 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002513 vme_brdtype == VME_TYPE_MVME167 ||
2514 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 mvme167_serial_console_setup(0);
2516 register_console(&sercons);
2517 }
2518 return 0;
2519}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521console_initcall(serial167_console_init);
2522
2523#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002524void putDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002526 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 unsigned long flags;
2528 volatile u_char sink;
2529 u_char ier;
2530 int port;
2531
2532 local_irq_save(flags);
2533
2534 /* Ensure transmitter is enabled! */
2535
2536 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002537 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 while (base_addr[CyCCR])
2539 ;
2540 base_addr[CyCCR] = CyENB_XMTR;
2541
2542 ier = base_addr[CyIER];
2543 base_addr[CyIER] = CyTxMpty;
2544
2545 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002546 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 /* We have a Tx int. Acknowledge it */
2548 sink = pcc2chip[PccTPIACKR];
2549 if ((base_addr[CyLICR] >> 2) == port) {
2550 base_addr[CyTDR] = c;
2551 base_addr[CyTEOIR] = 0;
2552 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002553 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 base_addr[CyTEOIR] = CyNOTRANS;
2555 }
2556 }
2557
2558 base_addr[CyIER] = ier;
2559
2560 local_irq_restore(flags);
2561}
2562
2563int getDebugChar()
2564{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002565 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 unsigned long flags;
2567 volatile u_char sink;
2568 u_char ier;
2569 int port;
2570 int i, c;
2571
2572 i = debugiq.out;
2573 if (i != debugiq.in) {
2574 c = debugiq.buf[i];
2575 if (++i == DEBUG_LEN)
2576 i = 0;
2577 debugiq.out = i;
2578 return c;
2579 }
2580 /* OK, nothing in queue, wait in poll loop */
2581
2582 local_irq_save(flags);
2583
2584 /* Ensure receiver is enabled! */
2585
2586 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002587 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588#if 0
2589 while (base_addr[CyCCR])
2590 ;
2591 base_addr[CyCCR] = CyENB_RCVR;
2592#endif
2593 ier = base_addr[CyIER];
2594 base_addr[CyIER] = CyRxData;
2595
2596 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002597 if (pcc2chip[PccSCCRICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* We have a Rx int. Acknowledge it */
2599 sink = pcc2chip[PccRPIACKR];
2600 if ((base_addr[CyLICR] >> 2) == port) {
2601 int cnt = base_addr[CyRFOC];
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002602 while (cnt-- > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 c = base_addr[CyRDR];
2604 if (c == 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002605 printk
2606 ("!! debug char is null (cnt=%d) !!",
2607 cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 else
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002609 queueDebugChar(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 }
2611 base_addr[CyREOIR] = 0;
2612 i = debugiq.out;
2613 if (i == debugiq.in)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002614 panic("Debug input queue empty!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 c = debugiq.buf[i];
2616 if (++i == DEBUG_LEN)
2617 i = 0;
2618 debugiq.out = i;
2619 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002620 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 base_addr[CyREOIR] = CyNOTRANS;
2622 }
2623 }
2624
2625 base_addr[CyIER] = ier;
2626
2627 local_irq_restore(flags);
2628
2629 return (c);
2630}
2631
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002632void queueDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633{
2634 int i;
2635
2636 i = debugiq.in;
2637 debugiq.buf[i] = c;
2638 if (++i == DEBUG_LEN)
2639 i = 0;
2640 if (i != debugiq.out)
2641 debugiq.in = i;
2642}
2643
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002644static void debug_setup()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002646 unsigned long flags;
2647 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2648 int i, cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002650 cflag = B19200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002652 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002654 for (i = 0; i < 4; i++) {
2655 base_addr[CyCAR] = i;
2656 base_addr[CyLICR] = i << 2;
2657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002659 debugiq.in = debugiq.out = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002661 base_addr[CyCAR] = DEBUG_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002663 /* baud rate */
2664 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002666 base_addr[CyIER] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002668 base_addr[CyCMR] = CyASYNC;
2669 base_addr[CyLICR] = DEBUG_PORT << 2;
2670 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002672 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002674 base_addr[CyTCOR] = baud_co[i];
2675 base_addr[CyTBPR] = baud_bpr[i];
2676 base_addr[CyRCOR] = baud_co[i] >> 5;
2677 base_addr[CyRBPR] = baud_bpr[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002679 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002681 base_addr[CySCHR1] = 0;
2682 base_addr[CySCHR2] = 0;
2683 base_addr[CySCRL] = 0;
2684 base_addr[CySCRH] = 0;
2685 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2686 base_addr[CyCOR2] = 0;
2687 base_addr[CyCOR3] = Cy_1_STOP;
2688 base_addr[CyCOR4] = baud_cor4[i];
2689 base_addr[CyCOR5] = 0;
2690 base_addr[CyCOR6] = 0;
2691 base_addr[CyCOR7] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002693 write_cy_cmd(base_addr, CyINIT_CHAN);
2694 write_cy_cmd(base_addr, CyENB_RCVR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002696 base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002698 base_addr[CyRTPRL] = 2;
2699 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002701 base_addr[CyMSVR1] = CyRTS;
2702 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002704 base_addr[CyIER] = CyRxData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002706 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002708} /* debug_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
2710#endif
2711
2712MODULE_LICENSE("GPL");