blob: 5942a9d674c0051885bd796fc005b39f14622657 [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
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800223 if ((long)info < (long)(&cy_port[0])
224 || (long)(&cy_port[NR_PORTS]) < (long)info) {
225 printk("Warning: cyclades_port out of range for (%s) in %s\n",
226 name, routine);
227 return 1;
228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800230 if (info->magic != CYCLADES_MAGIC) {
231 printk("Warning: bad magic number for serial struct (%s) in "
232 "%s\n", name, routine);
233 return 1;
234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#endif
236 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800237} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239#if 0
240/* The following diagnostic routines allow the driver to spew
241 information on the screen, even (especially!) during interrupts.
242 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800243void SP(char *data)
244{
245 unsigned long flags;
246 local_irq_save(flags);
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700247 printk(KERN_EMERG "%s", data);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800248 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800251char scrn[2];
252void CP(char data)
253{
254 unsigned long flags;
255 local_irq_save(flags);
256 scrn[0] = data;
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700257 printk(KERN_EMERG "%c", scrn);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800258 local_irq_restore(flags);
259} /* CP */
260
261void CP1(int data)
262{
263 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
264} /* CP1 */
265void CP2(int data)
266{
267 CP1((data >> 4) & 0x0f);
268 CP1(data & 0x0f);
269} /* CP2 */
270void CP4(int data)
271{
272 CP2((data >> 8) & 0xff);
273 CP2(data & 0xff);
274} /* CP4 */
275void CP8(long data)
276{
277 CP4((data >> 16) & 0xffff);
278 CP4(data & 0xffff);
279} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280#endif
281
282/* This routine waits up to 1000 micro-seconds for the previous
283 command to the Cirrus chip to complete and then issues the
284 new command. An error is returned if the previous command
285 didn't finish within the time limit.
286 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800287u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800289 unsigned long flags;
290 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800292 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800294 for (i = 0; i < 100; i++) {
295 if (base_addr[CyCCR] == 0) {
296 break;
297 }
298 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800301 didn't finish within the "reasonable time" */
302 if (i == 10) {
303 local_irq_restore(flags);
304 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 }
306
307 /* Issue the new command */
308 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800309 local_irq_restore(flags);
310 return (0);
311} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313/* cy_start and cy_stop provide software output flow control as a
314 function of XON/XOFF, software CTS, and other such stuff. */
315
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800316static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Alan Coxc9f19e92009-01-02 13:47:26 +0000318 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800319 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
320 int channel;
321 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800324 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325#endif
326
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800327 if (serial_paranoia_check(info, tty->name, "cy_stop"))
328 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800330 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800332 local_irq_save(flags);
333 base_addr[CyCAR] = (u_char) (channel); /* index channel */
334 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
335 local_irq_restore(flags);
336} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800338static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Alan Coxc9f19e92009-01-02 13:47:26 +0000340 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800341 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
342 int channel;
343 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800346 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#endif
348
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800349 if (serial_paranoia_check(info, tty->name, "cy_start"))
350 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800352 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800354 local_irq_save(flags);
355 base_addr[CyCAR] = (u_char) (channel);
356 base_addr[CyIER] |= CyTxMpty;
357 local_irq_restore(flags);
358} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360/* The real interrupt service routines are called
361 whenever the card wants its hand held--chars
362 received, out buffer empty, modem change, etc.
363 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800364static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800366 struct tty_struct *tty;
367 struct cyclades_port *info;
368 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
369 unsigned char err, rfoc;
370 int channel;
371 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800373 /* determine the channel and change to that context */
374 channel = (u_short) (base_addr[CyLICR] >> 2);
375 info = &cy_port[channel];
376 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800378 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
379 /* This is a receive timeout interrupt, ignore it */
380 base_addr[CyREOIR] = CyNOTRANS;
381 return IRQ_HANDLED;
382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800384 /* Read a byte of data if there is any - assume the error
385 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800387 if ((rfoc = base_addr[CyRFOC]) != 0)
388 data = base_addr[CyRDR];
389 else
390 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800392 /* if there is nowhere to put the data, discard it */
393 if (info->tty == 0) {
394 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
395 return IRQ_HANDLED;
396 } else { /* there is an open port for this data */
397 tty = info->tty;
398 if (err & info->ignore_status_mask) {
399 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
400 return IRQ_HANDLED;
401 }
402 if (tty_buffer_request_room(tty, 1) != 0) {
403 if (err & info->read_status_mask) {
404 if (err & CyBREAK) {
405 tty_insert_flip_char(tty, data,
406 TTY_BREAK);
407 if (info->flags & ASYNC_SAK) {
408 do_SAK(tty);
409 }
410 } else if (err & CyFRAME) {
411 tty_insert_flip_char(tty, data,
412 TTY_FRAME);
413 } else if (err & CyPARITY) {
414 tty_insert_flip_char(tty, data,
415 TTY_PARITY);
416 } else if (err & CyOVERRUN) {
417 tty_insert_flip_char(tty, 0,
418 TTY_OVERRUN);
419 /*
420 If the flip buffer itself is
Nick Andrewc4f01242008-12-05 16:34:46 +0000421 overflowing, we still lose
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800422 the next incoming character.
423 */
424 if (tty_buffer_request_room(tty, 1) !=
425 0) {
426 tty_insert_flip_char(tty, data,
427 TTY_FRAME);
428 }
429 /* These two conditions may imply */
430 /* a normal read should be done. */
431 /* else if(data & CyTIMEOUT) */
432 /* else if(data & CySPECHAR) */
433 } else {
434 tty_insert_flip_char(tty, 0,
435 TTY_NORMAL);
436 }
437 } else {
438 tty_insert_flip_char(tty, data, TTY_NORMAL);
439 }
440 } else {
441 /* there was a software buffer overrun
442 and nothing could be done about it!!! */
443 }
444 }
445 tty_schedule_flip(tty);
446 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
448 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800449} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800451static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800453 struct cyclades_port *info;
454 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
455 int channel;
456 int mdm_change;
457 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800459 /* determine the channel and change to that context */
460 channel = (u_short) (base_addr[CyLICR] >> 2);
461 info = &cy_port[channel];
462 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800464 mdm_change = base_addr[CyMISR];
465 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800467 if (info->tty == 0) { /* nowhere to put the data, ignore it */
468 ;
469 } else {
470 if ((mdm_change & CyDCD)
471 && (info->flags & ASYNC_CHECK_CD)) {
472 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/* CP('!'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800474 wake_up_interruptible(&info->open_wait);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800475 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476/* CP('@'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800477 tty_hangup(info->tty);
478 wake_up_interruptible(&info->open_wait);
479 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800482 if ((mdm_change & CyCTS)
483 && (info->flags & ASYNC_CTS_FLOW)) {
484 if (info->tty->stopped) {
485 if (mdm_status & CyCTS) {
486 /* !!! cy_start isn't used because... */
487 info->tty->stopped = 0;
488 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800489 tty_wakeup(info->tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800490 }
491 } else {
492 if (!(mdm_status & CyCTS)) {
493 /* !!! cy_stop isn't used because... */
494 info->tty->stopped = 1;
495 base_addr[CyIER] &=
496 ~(CyTxMpty | CyTxRdy);
497 }
498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800500 if (mdm_status & CyDSR) {
501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800503 base_addr[CyMEOIR] = 0;
504 return IRQ_HANDLED;
505} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800507static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800509 struct cyclades_port *info;
510 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
511 int channel;
512 int char_count, saved_cnt;
513 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800515 /* determine the channel and change to that context */
516 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800519 if (channel == DEBUG_PORT) {
520 panic("TxInt on debug port!!!");
521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522#endif
523
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800524 info = &cy_port[channel];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800526 /* validate the port number (as configured and open) */
527 if ((channel < 0) || (NR_PORTS <= channel)) {
528 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
529 base_addr[CyTEOIR] = CyNOTRANS;
530 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800532 info->last_active = jiffies;
533 if (info->tty == 0) {
534 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800535 base_addr[CyTEOIR] = CyNOTRANS;
536 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800538
539 /* load the on-chip space available for outbound data */
540 saved_cnt = char_count = base_addr[CyTFTC];
541
542 if (info->x_char) { /* send special char */
543 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800546 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800549 if (info->x_break) {
550 /* The Cirrus chip requires the "Embedded Transmit
551 Commands" of start break, delay, and end break
552 sequences to be sent. The duration of the
553 break is given in TICs, which runs at HZ
554 (typically 100) and the PPR runs at 200 Hz,
555 so the delay is duration * 200/HZ, and thus a
556 break can run from 1/100 sec to about 5/4 sec.
557 Need to check these values - RGH 141095.
558 */
559 base_addr[CyTDR] = 0; /* start break */
560 base_addr[CyTDR] = 0x81;
561 base_addr[CyTDR] = 0; /* delay a bit */
562 base_addr[CyTDR] = 0x82;
563 base_addr[CyTDR] = info->x_break * 200 / HZ;
564 base_addr[CyTDR] = 0; /* terminate break */
565 base_addr[CyTDR] = 0x83;
566 char_count -= 7;
567 info->x_break = 0;
568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800570 while (char_count > 0) {
571 if (!info->xmit_cnt) {
572 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
573 break;
574 }
575 if (info->xmit_buf == 0) {
576 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
577 break;
578 }
579 if (info->tty->stopped || info->tty->hw_stopped) {
580 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
581 break;
582 }
583 /* Because the Embedded Transmit Commands have been
584 enabled, we must check to see if the escape
585 character, NULL, is being sent. If it is, we
586 must ensure that there is room for it to be
587 doubled in the output stream. Therefore we
588 no longer advance the pointer when the character
589 is fetched, but rather wait until after the check
590 for a NULL output character. (This is necessary
591 because there may not be room for the two chars
592 needed to send a NULL.
593 */
594 outch = info->xmit_buf[info->xmit_tail];
595 if (outch) {
596 info->xmit_cnt--;
597 info->xmit_tail = (info->xmit_tail + 1)
598 & (PAGE_SIZE - 1);
599 base_addr[CyTDR] = outch;
600 char_count--;
601 } else {
602 if (char_count > 1) {
603 info->xmit_cnt--;
604 info->xmit_tail = (info->xmit_tail + 1)
605 & (PAGE_SIZE - 1);
606 base_addr[CyTDR] = outch;
607 base_addr[CyTDR] = 0;
608 char_count--;
609 char_count--;
610 } else {
611 break;
612 }
613 }
614 }
615
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800616 if (info->xmit_cnt < WAKEUP_CHARS)
617 tty_wakeup(info->tty);
618
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800619 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
620 return IRQ_HANDLED;
621} /* cy_tx_interrupt */
622
623static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800625 struct tty_struct *tty;
626 struct cyclades_port *info;
627 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
628 int channel;
629 char data;
630 int char_count;
631 int save_cnt;
632 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800634 /* determine the channel and change to that context */
635 channel = (u_short) (base_addr[CyLICR] >> 2);
636 info = &cy_port[channel];
637 info->last_active = jiffies;
638 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800641 if (channel == DEBUG_PORT) {
642 while (char_count--) {
643 data = base_addr[CyRDR];
644 queueDebugChar(data);
645 }
646 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800648 /* if there is nowhere to put the data, discard it */
649 if (info->tty == 0) {
650 while (char_count--) {
651 data = base_addr[CyRDR];
652 }
653 } else { /* there is an open port for this data */
654 tty = info->tty;
655 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800658 ++info->mon.int_count;
659 info->mon.char_count += char_count;
660 if (char_count > info->mon.char_max)
661 info->mon.char_max = char_count;
662 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800664 len = tty_buffer_request_room(tty, char_count);
665 while (len--) {
666 data = base_addr[CyRDR];
667 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800669 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800671 }
672 tty_schedule_flip(tty);
673 }
674 /* end of service */
675 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
676 return IRQ_HANDLED;
677} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679/* This is called whenever a port becomes active;
680 interrupts are enabled and DTR & RTS are turned on.
681 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800682static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800684 unsigned long flags;
685 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
686 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800688 if (info->flags & ASYNC_INITIALIZED) {
689 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800691
692 if (!info->type) {
693 if (info->tty) {
694 set_bit(TTY_IO_ERROR, &info->tty->flags);
695 }
696 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800698 if (!info->xmit_buf) {
699 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
700 if (!info->xmit_buf) {
701 return -ENOMEM;
702 }
703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800705 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800707 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800710 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711#endif
712
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800713 local_irq_save(flags);
714 base_addr[CyCAR] = (u_char) channel;
715 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800717 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 base_addr[CyMSVR1] = CyRTS;
719/* CP('S');CP('1'); */
720 base_addr[CyMSVR2] = CyDTR;
721
722#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800723 printk("cyc: %d: raising DTR\n", __LINE__);
724 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
725 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726#endif
727
728 base_addr[CyIER] |= CyRxData;
729 info->flags |= ASYNC_INITIALIZED;
730
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800731 if (info->tty) {
732 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
735
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800736 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800739 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800741 return 0;
742} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800744void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800746 unsigned long flags;
747 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
748 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800750 channel = info->line;
751 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 base_addr[CyCAR] = channel;
753 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800754 local_irq_restore(flags);
755} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757/*
758 * This routine shuts down a serial port; interrupts are disabled,
759 * and DTR is dropped if the hangup on close termio flag is on.
760 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800761static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800763 unsigned long flags;
764 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
765 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800767 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800769 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 }
771
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800772 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800774#ifdef SERIAL_DEBUG_OPEN
775 printk("shutdown channel %d\n", channel);
776#endif
777
778 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
779 SENT BEFORE DROPPING THE LINE !!! (Perhaps
780 set some flag that is read when XMTY happens.)
781 Other choices are to delay some fixed interval
782 or schedule some later processing.
783 */
784 local_irq_save(flags);
785 if (info->xmit_buf) {
786 free_page((unsigned long)info->xmit_buf);
787 info->xmit_buf = NULL;
788 }
789
790 base_addr[CyCAR] = (u_char) channel;
791 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
792 base_addr[CyMSVR1] = 0;
793/* CP('C');CP('1'); */
794 base_addr[CyMSVR2] = 0;
795#ifdef SERIAL_DEBUG_DTR
796 printk("cyc: %d: dropping DTR\n", __LINE__);
797 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
798 base_addr[CyMSVR2]);
799#endif
800 }
801 write_cy_cmd(base_addr, CyDIS_RCVR);
802 /* it may be appropriate to clear _XMIT at
803 some later date (after testing)!!! */
804
805 if (info->tty) {
806 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 }
808 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800809 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800812 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800814} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816/*
817 * This routine finds or computes the various line characteristics.
818 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800819static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800821 unsigned long flags;
822 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
823 int channel;
824 unsigned cflag;
825 int i;
826 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800828 if (!info->tty || !info->tty->termios) {
829 return;
830 }
831 if (info->line == -1) {
832 return;
833 }
834 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800836 /* baud rate */
837 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838#ifdef CBAUDEX
839/* Starting with kernel 1.1.65, there is direct support for
840 higher baud rates. The following code supports those
841 changes. The conditional aspect allows this driver to be
842 used for earlier as well as later kernel versions. (The
843 mapping is slightly different from serial.c because there
844 is still the possibility of supporting 75 kbit/sec with
845 the Cyclades board.)
846 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800847 if (i & CBAUDEX) {
848 if (i == B57600)
849 i = 16;
850 else if (i == B115200)
851 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800853 else if (i == B78600)
854 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800856 else
857 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800860 if (i == 15) {
861 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
862 i += 1;
863 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
864 i += 3;
865 }
866 /* Don't ever change the speed of the console port. It will
867 * run at the speed specified in bootinfo, or at 19.2K */
868 /* Actually, it should run at whatever speed 166Bug was using */
869 /* Note info->timeout isn't used at present */
870 if (info != serial_console_info) {
871 info->tbpr = baud_bpr[i]; /* Tx BPR */
872 info->tco = baud_co[i]; /* Tx CO */
873 info->rbpr = baud_bpr[i]; /* Rx BPR */
874 info->rco = baud_co[i] >> 5; /* Rx CO */
875 if (baud_table[i] == 134) {
876 info->timeout =
877 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
878 /* get it right for 134.5 baud */
879 } else if (baud_table[i]) {
880 info->timeout =
881 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
882 2;
883 /* this needs to be propagated into the card info */
884 } else {
885 info->timeout = 0;
886 }
887 }
888 /* By tradition (is it a standard?) a baud rate of zero
889 implies the line should be/has been closed. A bit
890 later in this routine such a test is performed. */
891
892 /* byte size and parity */
893 info->cor7 = 0;
894 info->cor6 = 0;
895 info->cor5 = 0;
896 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
897 /* Following two lines added 101295, RGH. */
898 /* It is obviously wrong to access CyCORx, and not info->corx here,
899 * try and remember to fix it later! */
900 channel = info->line;
901 base_addr[CyCAR] = (u_char) channel;
902 if (C_CLOCAL(info->tty)) {
903 if (base_addr[CyIER] & CyMdmCh)
904 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
905 /* ignore 1->0 modem transitions */
906 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
907 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
908 /* ignore 0->1 modem transitions */
909 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
910 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
911 } else {
912 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
913 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
914 /* act on 1->0 modem transitions */
915 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
916 (CyDSR | CyCTS | CyDCD))
917 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
918 /* act on 0->1 modem transitions */
919 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
920 (CyDSR | CyCTS | CyDCD))
921 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
922 }
923 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
924 info->cor2 = CyETC;
925 switch (cflag & CSIZE) {
926 case CS5:
927 info->cor1 = Cy_5_BITS;
928 break;
929 case CS6:
930 info->cor1 = Cy_6_BITS;
931 break;
932 case CS7:
933 info->cor1 = Cy_7_BITS;
934 break;
935 case CS8:
936 info->cor1 = Cy_8_BITS;
937 break;
938 }
939 if (cflag & PARENB) {
940 if (cflag & PARODD) {
941 info->cor1 |= CyPARITY_O;
942 } else {
943 info->cor1 |= CyPARITY_E;
944 }
945 } else {
946 info->cor1 |= CyPARITY_NONE;
947 }
948
949 /* CTS flow control flag */
950#if 0
951 /* Don't complcate matters for now! RGH 141095 */
952 if (cflag & CRTSCTS) {
953 info->flags |= ASYNC_CTS_FLOW;
954 info->cor2 |= CyCtsAE;
955 } else {
956 info->flags &= ~ASYNC_CTS_FLOW;
957 info->cor2 &= ~CyCtsAE;
958 }
959#endif
960 if (cflag & CLOCAL)
961 info->flags &= ~ASYNC_CHECK_CD;
962 else
963 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 /***********************************************
966 The hardware option, CyRtsAO, presents RTS when
967 the chip has characters to send. Since most modems
968 use RTS as reverse (inbound) flow control, this
969 option is not used. If inbound flow control is
970 necessary, DTR can be programmed to provide the
971 appropriate signals for use with a non-standard
972 cable. Contact Marcio Saito for details.
973 ***********************************************/
974
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800975 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800977 local_irq_save(flags);
978 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 /* CyCMR set once only in mvme167_init_serial() */
981 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800982 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800984 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800986 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800989 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800991 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800993 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800995 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800997 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
999 /* set line characteristics according configuration */
1000
1001 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001002 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001004 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001006 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001008 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001010 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001012 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001014 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001016 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001018 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001020 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001022 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001025 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001027 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
1029 /* 2ms default rx timeout */
1030 ti = info->default_timeout ? info->default_timeout : 0x02;
1031 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001032 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001034 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
1036 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001037 if (i == 0) { /* baud rate is zero, turn off line */
1038 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1039 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001041 printk("cyc: %d: dropping DTR\n", __LINE__);
1042 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1043 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001045 } else {
1046 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1047 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001049 printk("cyc: %d: raising DTR\n", __LINE__);
1050 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1051 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052#endif
1053 }
1054
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001055 if (info->tty) {
1056 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
1058
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001059 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001061} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Alan Coxa5b08c62008-04-30 00:54:05 -07001063static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Alan Coxc9f19e92009-01-02 13:47:26 +00001065 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001066 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001069 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070#endif
1071
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001072 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001073 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001075 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001076 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001078 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001080 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001081 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083
1084 info->xmit_buf[info->xmit_head++] = ch;
1085 info->xmit_head &= PAGE_SIZE - 1;
1086 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001087 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001088 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001089} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001091static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092{
Alan Coxc9f19e92009-01-02 13:47:26 +00001093 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001094 unsigned long flags;
1095 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1096 int channel;
1097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001099 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100#endif
1101
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001102 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1103 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001105 if (info->xmit_cnt <= 0 || tty->stopped
1106 || tty->hw_stopped || !info->xmit_buf)
1107 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001109 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001111 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 base_addr[CyCAR] = channel;
1113 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001114 local_irq_restore(flags);
1115} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117/* This routine gets called when tty_write has put something into
1118 the write_queue. If the port is not already transmitting stuff,
1119 start it off by enabling interrupts. The interrupt service
1120 routine will then ensure that the characters are sent. If the
1121 port is already active, there is no need to kick it.
1122 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001123static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124{
Alan Coxc9f19e92009-01-02 13:47:26 +00001125 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001126 unsigned long flags;
1127 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001130 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131#endif
1132
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001133 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1134 return 0;
1135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001137 if (!info->xmit_buf) {
1138 return 0;
1139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001141 while (1) {
1142 local_irq_save(flags);
1143 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1144 SERIAL_XMIT_SIZE - info->xmit_head));
1145 if (c <= 0) {
1146 local_irq_restore(flags);
1147 break;
1148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001150 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1151 info->xmit_head =
1152 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1153 info->xmit_cnt += c;
1154 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001156 buf += c;
1157 count -= c;
1158 total += c;
1159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001161 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1162 start_xmit(info);
1163 }
1164 return total;
1165} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001167static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
Alan Coxc9f19e92009-01-02 13:47:26 +00001169 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001170 int ret;
1171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001173 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174#endif
1175
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001176 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1177 return 0;
1178 ret = PAGE_SIZE - info->xmit_cnt - 1;
1179 if (ret < 0)
1180 ret = 0;
1181 return ret;
1182} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001184static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185{
Alan Coxc9f19e92009-01-02 13:47:26 +00001186 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001189 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190#endif
1191
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001192 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1193 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001195 return info->xmit_cnt;
1196} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001198static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
Alan Coxc9f19e92009-01-02 13:47:26 +00001200 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001201 unsigned long flags;
1202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001204 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205#endif
1206
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001207 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1208 return;
1209 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001211 local_irq_restore(flags);
1212 tty_wakeup(tty);
1213} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
1215/* This routine is called by the upper-layer tty layer to signal
1216 that incoming characters should be throttled or that the
1217 throttle should be released.
1218 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001219static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
Alan Coxc9f19e92009-01-02 13:47:26 +00001221 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001222 unsigned long flags;
1223 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1224 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001227 char buf[64];
1228
1229 printk("throttle %s: %d....\n", tty_name(tty, buf),
1230 tty->ldisc.chars_in_buffer(tty));
1231 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232#endif
1233
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001234 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1235 return;
1236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001238 if (I_IXOFF(tty)) {
1239 info->x_char = STOP_CHAR(tty);
1240 /* Should use the "Send Special Character" feature!!! */
1241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001243 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001245 local_irq_save(flags);
1246 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001248 local_irq_restore(flags);
1249} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001251static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252{
Alan Coxc9f19e92009-01-02 13:47:26 +00001253 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001254 unsigned long flags;
1255 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1256 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001259 char buf[64];
1260
1261 printk("throttle %s: %d....\n", tty_name(tty, buf),
1262 tty->ldisc.chars_in_buffer(tty));
1263 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264#endif
1265
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001266 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1267 return;
1268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001270 if (I_IXOFF(tty)) {
1271 info->x_char = START_CHAR(tty);
1272 /* Should use the "Send Special Character" feature!!! */
1273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001275 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001277 local_irq_save(flags);
1278 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001280 local_irq_restore(flags);
1281} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
1283static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001284get_serial_info(struct cyclades_port *info,
1285 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001287 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001290 if (!retinfo)
1291 return -EFAULT;
1292 memset(&tmp, 0, sizeof(tmp));
1293 tmp.type = info->type;
1294 tmp.line = info->line;
1295 tmp.port = info->line;
1296 tmp.irq = 0;
1297 tmp.flags = info->flags;
1298 tmp.baud_base = 0; /*!!! */
1299 tmp.close_delay = info->close_delay;
1300 tmp.custom_divisor = 0; /*!!! */
1301 tmp.hub6 = 0; /*!!! */
1302 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1303} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001306set_serial_info(struct cyclades_port *info,
1307 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001309 struct serial_struct new_serial;
1310 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
1312/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001313 if (!new_info)
1314 return -EFAULT;
1315 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1316 return -EFAULT;
1317 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001319 if (!capable(CAP_SYS_ADMIN)) {
1320 if ((new_serial.close_delay != info->close_delay) ||
1321 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1322 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1323 return -EPERM;
1324 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1325 (new_serial.flags & ASYNC_USR_MASK));
1326 goto check_and_exit;
1327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001329 /*
1330 * OK, past this point, all the error checking has been done.
1331 * At this point, we start making changes.....
1332 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001334 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1335 (new_serial.flags & ASYNC_FLAGS));
1336 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001339 if (info->flags & ASYNC_INITIALIZED) {
1340 config_setup(info);
1341 return 0;
1342 }
1343 return startup(info);
1344} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001346static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347{
Alan Coxc9f19e92009-01-02 13:47:26 +00001348 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001349 int channel;
1350 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1351 unsigned long flags;
1352 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001354 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001356 local_irq_save(flags);
1357 base_addr[CyCAR] = (u_char) channel;
1358 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1359 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001361 return ((status & CyRTS) ? TIOCM_RTS : 0)
1362 | ((status & CyDTR) ? TIOCM_DTR : 0)
1363 | ((status & CyDCD) ? TIOCM_CAR : 0)
1364 | ((status & CyDSR) ? TIOCM_DSR : 0)
1365 | ((status & CyCTS) ? TIOCM_CTS : 0);
1366} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368static int
1369cy_tiocmset(struct tty_struct *tty, struct file *file,
1370 unsigned int set, unsigned int clear)
1371{
Alan Coxc9f19e92009-01-02 13:47:26 +00001372 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001373 int channel;
1374 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1375 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001377 channel = info->line;
1378
1379 if (set & TIOCM_RTS) {
1380 local_irq_save(flags);
1381 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001383 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001385 if (set & TIOCM_DTR) {
1386 local_irq_save(flags);
1387 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001389 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001391 printk("cyc: %d: raising DTR\n", __LINE__);
1392 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1393 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001395 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 }
1397
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001398 if (clear & TIOCM_RTS) {
1399 local_irq_save(flags);
1400 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001402 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001404 if (clear & TIOCM_DTR) {
1405 local_irq_save(flags);
1406 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001408 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001410 printk("cyc: %d: dropping DTR\n", __LINE__);
1411 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1412 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001414 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 }
1416
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001417 return 0;
1418} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001420static void send_break(struct cyclades_port *info, int duration)
1421{ /* Let the transmit ISR take care of this (since it
1422 requires stuffing characters into the output stream).
1423 */
1424 info->x_break = duration;
1425 if (!info->xmit_cnt) {
1426 start_xmit(info);
1427 }
1428} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001431get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432{
1433
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001434 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1435 return -EFAULT;
1436 info->mon.int_count = 0;
1437 info->mon.char_count = 0;
1438 info->mon.char_max = 0;
1439 info->mon.char_last = 0;
1440 return 0;
1441}
1442
1443static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1444{
1445 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1446 unsigned long value;
1447 int channel;
1448
1449 if (get_user(value, arg))
1450 return -EFAULT;
1451
1452 channel = info->line;
1453 info->cor4 &= ~CyREC_FIFO;
1454 info->cor4 |= value & CyREC_FIFO;
1455 base_addr[CyCOR4] = info->cor4;
1456 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457}
1458
1459static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001460get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001462 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1463 int channel;
1464 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001466 channel = info->line;
1467
1468 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1469 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470}
1471
1472static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001473set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001475 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001477 if (get_user(value, arg))
1478 return -EFAULT;
1479
1480 info->default_threshold = value & 0x0f;
1481 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482}
1483
1484static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001485get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001487 return put_user(info->default_threshold, value);
1488}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001490static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1491{
1492 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1493 int channel;
1494 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001496 if (get_user(value, arg))
1497 return -EFAULT;
1498
1499 channel = info->line;
1500
1501 base_addr[CyRTPRL] = value & 0xff;
1502 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1503 return 0;
1504}
1505
1506static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1507{
1508 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1509 int channel;
1510 unsigned long tmp;
1511
1512 channel = info->line;
1513
1514 tmp = base_addr[CyRTPRL];
1515 return put_user(tmp, value);
1516}
1517
1518static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1519{
1520 info->default_timeout = value & 0xff;
1521 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522}
1523
1524static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001525get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001527 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528}
1529
1530static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001531cy_ioctl(struct tty_struct *tty, struct file *file,
1532 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001534 unsigned long val;
Alan Coxc9f19e92009-01-02 13:47:26 +00001535 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001536 int ret_val = 0;
1537 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001540 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541#endif
1542
Alan Cox638157b2008-04-30 00:53:22 -07001543 lock_kernel();
1544
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001545 switch (cmd) {
1546 case CYGETMON:
1547 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001549 case CYGETTHRESH:
1550 ret_val = get_threshold(info, argp);
1551 break;
1552 case CYSETTHRESH:
1553 ret_val = set_threshold(info, argp);
1554 break;
1555 case CYGETDEFTHRESH:
1556 ret_val = get_default_threshold(info, argp);
1557 break;
1558 case CYSETDEFTHRESH:
1559 ret_val = set_default_threshold(info, argp);
1560 break;
1561 case CYGETTIMEOUT:
1562 ret_val = get_timeout(info, argp);
1563 break;
1564 case CYSETTIMEOUT:
1565 ret_val = set_timeout(info, argp);
1566 break;
1567 case CYGETDEFTIMEOUT:
1568 ret_val = get_default_timeout(info, argp);
1569 break;
1570 case CYSETDEFTIMEOUT:
1571 ret_val = set_default_timeout(info, (unsigned long)arg);
1572 break;
1573 case TCSBRK: /* SVID version: non-zero arg --> no break */
1574 ret_val = tty_check_change(tty);
1575 if (ret_val)
1576 break;
1577 tty_wait_until_sent(tty, 0);
1578 if (!arg)
1579 send_break(info, HZ / 4); /* 1/4 second */
1580 break;
1581 case TCSBRKP: /* support for POSIX tcsendbreak() */
1582 ret_val = tty_check_change(tty);
1583 if (ret_val)
1584 break;
1585 tty_wait_until_sent(tty, 0);
1586 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1587 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001590 case TIOCGSERIAL:
1591 ret_val = get_serial_info(info, argp);
1592 break;
1593 case TIOCSSERIAL:
1594 ret_val = set_serial_info(info, argp);
1595 break;
1596 default:
1597 ret_val = -ENOIOCTLCMD;
1598 }
Alan Cox638157b2008-04-30 00:53:22 -07001599 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
1601#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001602 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603#endif
1604
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001605 return ret_val;
1606} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001608static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609{
Alan Coxc9f19e92009-01-02 13:47:26 +00001610 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
1612#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001613 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614#endif
1615
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001616 if (tty->termios->c_cflag == old_termios->c_cflag)
1617 return;
1618 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001620 if ((old_termios->c_cflag & CRTSCTS) &&
1621 !(tty->termios->c_cflag & CRTSCTS)) {
1622 tty->stopped = 0;
1623 cy_start(tty);
1624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001626 if (!(old_termios->c_cflag & CLOCAL) &&
1627 (tty->termios->c_cflag & CLOCAL))
1628 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001630} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001632static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633{
Alan Coxc9f19e92009-01-02 13:47:26 +00001634 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
1636/* CP('C'); */
1637#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001638 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639#endif
1640
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001641 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1642 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001644#ifdef SERIAL_DEBUG_OPEN
1645 printk("cy_close %s, count = %d\n", tty->name, info->count);
1646#endif
1647
1648 if ((tty->count == 1) && (info->count != 1)) {
1649 /*
1650 * Uh, oh. tty->count is 1, which means that the tty
1651 * structure will be freed. Info->count should always
1652 * be one in these conditions. If it's greater than
1653 * one, we've got real problems, since it means the
1654 * serial port won't be shutdown.
1655 */
1656 printk("cy_close: bad serial port count; tty->count is 1, "
1657 "info->count is %d\n", info->count);
1658 info->count = 1;
1659 }
1660#ifdef SERIAL_DEBUG_COUNT
1661 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1662 info->count - 1);
1663#endif
1664 if (--info->count < 0) {
1665 printk("cy_close: bad serial port count for ttys%d: %d\n",
1666 info->line, info->count);
1667#ifdef SERIAL_DEBUG_COUNT
1668 printk("cyc: %d: setting count to 0\n", __LINE__);
1669#endif
1670 info->count = 0;
1671 }
1672 if (info->count)
1673 return;
1674 info->flags |= ASYNC_CLOSING;
1675 if (info->flags & ASYNC_INITIALIZED)
1676 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1677 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001678 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001679 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001680 info->tty = NULL;
1681 if (info->blocked_open) {
1682 if (info->close_delay) {
1683 msleep_interruptible(jiffies_to_msecs
1684 (info->close_delay));
1685 }
1686 wake_up_interruptible(&info->open_wait);
1687 }
1688 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1689 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001692 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001694} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696/*
1697 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1698 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001699void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700{
Alan Coxc9f19e92009-01-02 13:47:26 +00001701 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001704 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705#endif
1706
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001707 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1708 return;
1709
1710 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001712 info->event = 0;
1713 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001715 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001717 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001719 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1720 wake_up_interruptible(&info->open_wait);
1721} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
1723/*
1724 * ------------------------------------------------------------
1725 * cy_open() and friends
1726 * ------------------------------------------------------------
1727 */
1728
1729static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001730block_til_ready(struct tty_struct *tty, struct file *filp,
1731 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001733 DECLARE_WAITQUEUE(wait, current);
1734 unsigned long flags;
1735 int channel;
1736 int retval;
1737 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001739 /*
1740 * If the device is in the middle of being closed, then block
1741 * until it's done, and then try again.
1742 */
1743 if (info->flags & ASYNC_CLOSING) {
1744 interruptible_sleep_on(&info->close_wait);
1745 if (info->flags & ASYNC_HUP_NOTIFY) {
1746 return -EAGAIN;
1747 } else {
1748 return -ERESTARTSYS;
1749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001752 /*
1753 * If non-blocking mode is set, then make the check up front
1754 * and then exit.
1755 */
1756 if (filp->f_flags & O_NONBLOCK) {
1757 info->flags |= ASYNC_NORMAL_ACTIVE;
1758 return 0;
1759 }
1760
1761 /*
1762 * Block waiting for the carrier detect and the line to become
1763 * free (i.e., not in use by the callout). While we are in
1764 * this loop, info->count is dropped by one, so that
1765 * cy_close() knows when to free things. We restore it upon
1766 * exit, either normal or abnormal.
1767 */
1768 retval = 0;
1769 add_wait_queue(&info->open_wait, &wait);
1770#ifdef SERIAL_DEBUG_OPEN
1771 printk("block_til_ready before block: %s, count = %d\n",
1772 tty->name, info->count);
1773 /**/
1774#endif
1775 info->count--;
1776#ifdef SERIAL_DEBUG_COUNT
1777 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1778#endif
1779 info->blocked_open++;
1780
1781 channel = info->line;
1782
1783 while (1) {
1784 local_irq_save(flags);
1785 base_addr[CyCAR] = (u_char) channel;
1786 base_addr[CyMSVR1] = CyRTS;
1787/* CP('S');CP('4'); */
1788 base_addr[CyMSVR2] = CyDTR;
1789#ifdef SERIAL_DEBUG_DTR
1790 printk("cyc: %d: raising DTR\n", __LINE__);
1791 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1792 base_addr[CyMSVR2]);
1793#endif
1794 local_irq_restore(flags);
1795 set_current_state(TASK_INTERRUPTIBLE);
1796 if (tty_hung_up_p(filp)
1797 || !(info->flags & ASYNC_INITIALIZED)) {
1798 if (info->flags & ASYNC_HUP_NOTIFY) {
1799 retval = -EAGAIN;
1800 } else {
1801 retval = -ERESTARTSYS;
1802 }
1803 break;
1804 }
1805 local_irq_save(flags);
1806 base_addr[CyCAR] = (u_char) channel;
1807/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1808 if (!(info->flags & ASYNC_CLOSING)
1809 && (C_CLOCAL(tty)
1810 || (base_addr[CyMSVR1] & CyDCD))) {
1811 local_irq_restore(flags);
1812 break;
1813 }
1814 local_irq_restore(flags);
1815 if (signal_pending(current)) {
1816 retval = -ERESTARTSYS;
1817 break;
1818 }
1819#ifdef SERIAL_DEBUG_OPEN
1820 printk("block_til_ready blocking: %s, count = %d\n",
1821 tty->name, info->count);
1822 /**/
1823#endif
1824 schedule();
1825 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001826 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001827 remove_wait_queue(&info->open_wait, &wait);
1828 if (!tty_hung_up_p(filp)) {
1829 info->count++;
1830#ifdef SERIAL_DEBUG_COUNT
1831 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1832 info->count);
1833#endif
1834 }
1835 info->blocked_open--;
1836#ifdef SERIAL_DEBUG_OPEN
1837 printk("block_til_ready after blocking: %s, count = %d\n",
1838 tty->name, info->count);
1839 /**/
1840#endif
1841 if (retval)
1842 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 info->flags |= ASYNC_NORMAL_ACTIVE;
1844 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001845} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847/*
1848 * This routine is called whenever a serial port is opened. It
1849 * performs the serial-specific initialization for the tty structure.
1850 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001851int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001853 struct cyclades_port *info;
1854 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
1856/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001857 line = tty->index;
1858 if ((line < 0) || (NR_PORTS <= line)) {
1859 return -ENODEV;
1860 }
1861 info = &cy_port[line];
1862 if (info->line < 0) {
1863 return -ENODEV;
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001866 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001868 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1869 return -ENODEV;
1870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001872 printk("cy_open %s, count = %d\n", tty->name, info->count);
1873 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001875 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001877 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001879 tty->driver_data = info;
1880 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001882 /*
1883 * Start up serial port
1884 */
1885 retval = startup(info);
1886 if (retval) {
1887 return retval;
1888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001890 retval = block_til_ready(tty, filp, info);
1891 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001893 printk("cy_open returning after block_til_ready with %d\n",
1894 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001896 return retval;
1897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001899 printk("cy_open done\n");
1900 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001902 return 0;
1903} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
1905/*
1906 * ---------------------------------------------------------------------
1907 * serial167_init() and friends
1908 *
1909 * serial167_init() is called at boot-time to initialize the serial driver.
1910 * ---------------------------------------------------------------------
1911 */
1912
1913/*
1914 * This routine prints out the appropriate serial driver version
1915 * number, and identifies which options were configured into this
1916 * driver.
1917 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001918static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001920 printk("MVME166/167 cd2401 driver\n");
1921} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923/* initialize chips on card -- return number of valid
1924 chips (which is number of ports/4) */
1925
1926/*
1927 * This initialises the hardware to a reasonable state. It should
1928 * probe the chip first so as to copy 166-Bug setup as a default for
1929 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1930 * as to limit the number of CyINIT_CHAN commands in normal running.
1931 *
1932 * ... I wonder what I should do if this fails ...
1933 */
1934
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001935void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001937 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 int ch;
1939 u_char spd;
1940 u_char rcor, rbpr, badspeed = 0;
1941 unsigned long flags;
1942
1943 local_irq_save(flags);
1944
1945 /*
1946 * First probe channel zero of the chip, to see what speed has
1947 * been selected.
1948 */
1949
1950 base_addr[CyCAR] = 0;
1951
1952 rcor = base_addr[CyRCOR] << 5;
1953 rbpr = base_addr[CyRBPR];
1954
1955 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1956 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1957 break;
1958 if (spd >= sizeof(baud_bpr)) {
1959 spd = 14; /* 19200 */
1960 badspeed = 1; /* Failed to identify speed */
1961 }
1962 initial_console_speed = spd;
1963
1964 /* OK, we have chosen a speed, now reset and reinitialise */
1965
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001966 my_udelay(20000L); /* Allow time for any active o/p to complete */
1967 if (base_addr[CyCCR] != 0x00) {
1968 local_irq_restore(flags);
1969 /* printk(" chip is never idle (CCR != 0)\n"); */
1970 return;
1971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001973 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1974 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001976 if (base_addr[CyGFRCR] == 0x00) {
1977 local_irq_restore(flags);
1978 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1979 return;
1980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
1982 /*
1983 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1984 * tick
1985 */
1986
1987 base_addr[CyTPR] = 10;
1988
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001989 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1990 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1991 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 /*
1994 * Attempt to set up all channels to something reasonable, and
1995 * bang out a INIT_CHAN command. We should then be able to limit
1996 * the ammount of fiddling we have to do in normal running.
1997 */
1998
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001999 for (ch = 3; ch >= 0; ch--) {
2000 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 base_addr[CyIER] = 0;
2002 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002003 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 base_addr[CyLIVR] = 0x5c;
2005 base_addr[CyTCOR] = baud_co[spd];
2006 base_addr[CyTBPR] = baud_bpr[spd];
2007 base_addr[CyRCOR] = baud_co[spd] >> 5;
2008 base_addr[CyRBPR] = baud_bpr[spd];
2009 base_addr[CySCHR1] = 'Q' & 0x1f;
2010 base_addr[CySCHR2] = 'X' & 0x1f;
2011 base_addr[CySCRL] = 0;
2012 base_addr[CySCRH] = 0;
2013 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2014 base_addr[CyCOR2] = 0;
2015 base_addr[CyCOR3] = Cy_1_STOP;
2016 base_addr[CyCOR4] = baud_cor4[spd];
2017 base_addr[CyCOR5] = 0;
2018 base_addr[CyCOR6] = 0;
2019 base_addr[CyCOR7] = 0;
2020 base_addr[CyRTPRL] = 2;
2021 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002022 base_addr[CyMSVR1] = 0;
2023 base_addr[CyMSVR2] = 0;
2024 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026
2027 /*
2028 * Now do specials for channel zero....
2029 */
2030
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002031 base_addr[CyMSVR1] = CyRTS;
2032 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002034 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
2036 local_irq_restore(flags);
2037
2038 my_udelay(20000L); /* Let it all settle down */
2039
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002040 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002042 printk
2043 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2044 rcor >> 5, rbpr);
2045} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002047static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 .open = cy_open,
2049 .close = cy_close,
2050 .write = cy_write,
2051 .put_char = cy_put_char,
2052 .flush_chars = cy_flush_chars,
2053 .write_room = cy_write_room,
2054 .chars_in_buffer = cy_chars_in_buffer,
2055 .flush_buffer = cy_flush_buffer,
2056 .ioctl = cy_ioctl,
2057 .throttle = cy_throttle,
2058 .unthrottle = cy_unthrottle,
2059 .set_termios = cy_set_termios,
2060 .stop = cy_stop,
2061 .start = cy_start,
2062 .hangup = cy_hangup,
2063 .tiocmget = cy_tiocmget,
2064 .tiocmset = cy_tiocmset,
2065};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002066
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067/* The serial driver boot-time initialization code!
2068 Hardware I/O ports are mapped to character special devices on a
2069 first found, first allocated manner. That is, this code searches
2070 for Cyclom cards in the system. As each is found, it is probed
2071 to discover how many chips (and thus how many ports) are present.
2072 These ports are mapped to the tty ports 64 and upward in monotonic
2073 fashion. If an 8-port card is replaced with a 16-port card, the
2074 port mapping on a following card will shift.
2075
2076 This approach is different from what is used in the other serial
2077 device driver because the Cyclom is more properly a multiplexer,
2078 not just an aggregation of serial ports on one card.
2079
2080 If there are more cards with more ports than have been statically
2081 allocated above, a warning is printed and the extra ports are ignored.
2082 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002083static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002085 struct cyclades_port *info;
2086 int ret = 0;
2087 int good_ports = 0;
2088 int port_num = 0;
2089 int index;
2090 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002092 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093#endif
2094
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002095 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2096 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002098 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2099 if (!cy_serial_driver)
2100 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002103 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104#endif
2105
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002106 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002108 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2109 if (serial_console_cflag)
2110 DefSpeed = serial_console_cflag & 0017;
2111 else {
2112 DefSpeed = initial_console_speed;
2113 serial_console_info = &cy_port[0];
2114 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002116 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002119
2120 /* Initialize the tty_driver structure */
2121
2122 cy_serial_driver->owner = THIS_MODULE;
2123 cy_serial_driver->name = "ttyS";
2124 cy_serial_driver->major = TTY_MAJOR;
2125 cy_serial_driver->minor_start = 64;
2126 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2127 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2128 cy_serial_driver->init_termios = tty_std_termios;
2129 cy_serial_driver->init_termios.c_cflag =
2130 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2131 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2132 tty_set_operations(cy_serial_driver, &cy_ops);
2133
2134 ret = tty_register_driver(cy_serial_driver);
2135 if (ret) {
2136 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2137 put_tty_driver(cy_serial_driver);
2138 return ret;
2139 }
2140
2141 port_num = 0;
2142 info = cy_port;
2143 for (index = 0; index < 1; index++) {
2144
2145 good_ports = 4;
2146
2147 if (port_num < NR_PORTS) {
2148 while (good_ports-- && port_num < NR_PORTS) {
2149 /*** initialize port ***/
2150 info->magic = CYCLADES_MAGIC;
2151 info->type = PORT_CIRRUS;
2152 info->card = index;
2153 info->line = port_num;
2154 info->flags = STD_COM_FLAGS;
2155 info->tty = NULL;
2156 info->xmit_fifo_size = 12;
2157 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2158 info->cor2 = CyETC;
2159 info->cor3 = Cy_1_STOP;
2160 info->cor4 = 0x08; /* _very_ small receive threshold */
2161 info->cor5 = 0;
2162 info->cor6 = 0;
2163 info->cor7 = 0;
2164 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2165 info->tco = baud_co[DefSpeed]; /* Tx CO */
2166 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2167 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2168 info->close_delay = 0;
2169 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002170 info->count = 0;
2171#ifdef SERIAL_DEBUG_COUNT
2172 printk("cyc: %d: setting count to 0\n",
2173 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002175 info->blocked_open = 0;
2176 info->default_threshold = 0;
2177 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002178 init_waitqueue_head(&info->open_wait);
2179 init_waitqueue_head(&info->close_wait);
2180 /* info->session */
2181 /* info->pgrp */
2182/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2183 info->read_status_mask =
2184 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2185 CyFRAME | CyOVERRUN;
2186 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002188 printk("ttyS%d ", info->line);
2189 port_num++;
2190 info++;
2191 if (!(port_num & 7)) {
2192 printk("\n ");
2193 }
2194 }
2195 }
2196 printk("\n");
2197 }
2198 while (port_num < NR_PORTS) {
2199 info->line = -1;
2200 port_num++;
2201 info++;
2202 }
2203#ifdef CONFIG_REMOTE_DEBUG
2204 debug_setup();
2205#endif
2206 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2207 "cd2401_errors", cd2401_rxerr_interrupt);
2208 if (ret) {
2209 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2210 goto cleanup_serial_driver;
2211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002213 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2214 "cd2401_modem", cd2401_modem_interrupt);
2215 if (ret) {
2216 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2217 goto cleanup_irq_cd2401_errors;
2218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002220 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2221 "cd2401_txints", cd2401_tx_interrupt);
2222 if (ret) {
2223 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2224 goto cleanup_irq_cd2401_modem;
2225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002227 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2228 "cd2401_rxints", cd2401_rx_interrupt);
2229 if (ret) {
2230 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2231 goto cleanup_irq_cd2401_txints;
2232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002234 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002236 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2237 pcc2chip[PccSCCTICR] = 0x15;
2238 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002240 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2241
2242 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002244 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002246 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002248 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002250 if (tty_unregister_driver(cy_serial_driver))
2251 printk(KERN_ERR
2252 "Couldn't unregister MVME166/7 serial driver\n");
2253 put_tty_driver(cy_serial_driver);
2254 return ret;
2255} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257module_init(serial167_init);
2258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002260static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002262 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2263 int channel;
2264 struct cyclades_port *info;
2265 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002267 info = &cy_port[line_num];
2268 channel = info->line;
2269 printk(" channel %d\n", channel);
2270 /**/ printk(" cy_port\n");
2271 printk(" card line flags = %d %d %x\n",
2272 info->card, info->line, info->flags);
2273 printk
2274 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2275 (long)info->tty, info->read_status_mask, info->timeout,
2276 info->xmit_fifo_size);
2277 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2278 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2279 info->cor6, info->cor7);
2280 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2281 info->rbpr, info->rco);
2282 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2283 info->event, info->count);
2284 printk(" x_char blocked_open = %x %x\n", info->x_char,
2285 info->blocked_open);
2286 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002288 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290/* Global Registers */
2291
2292 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2293 printk(" CyCAR %x\n", base_addr[CyCAR]);
2294 printk(" CyRISR %x\n", base_addr[CyRISR]);
2295 printk(" CyTISR %x\n", base_addr[CyTISR]);
2296 printk(" CyMISR %x\n", base_addr[CyMISR]);
2297 printk(" CyRIR %x\n", base_addr[CyRIR]);
2298 printk(" CyTIR %x\n", base_addr[CyTIR]);
2299 printk(" CyMIR %x\n", base_addr[CyMIR]);
2300 printk(" CyTPR %x\n", base_addr[CyTPR]);
2301
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002302 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304/* Virtual Registers */
2305
2306#if 0
2307 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2308 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2309 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2310 printk(" CyMISR %x\n", base_addr[CyMISR]);
2311#endif
2312
2313/* Channel Registers */
2314
2315 printk(" CyCCR %x\n", base_addr[CyCCR]);
2316 printk(" CyIER %x\n", base_addr[CyIER]);
2317 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2318 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2319 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2320 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2321 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2322#if 0
2323 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2324 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2325#endif
2326 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2327 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2328#if 0
2329 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2330 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2331 printk(" CySCRL %x\n", base_addr[CySCRL]);
2332 printk(" CySCRH %x\n", base_addr[CySCRH]);
2333 printk(" CyLNC %x\n", base_addr[CyLNC]);
2334 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2335 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2336#endif
2337 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2338 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2339 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2340 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2341 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2342 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2343 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2344 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2345
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002346 local_irq_restore(flags);
2347} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348#endif
2349
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350#if 0
2351/* Dummy routine in mvme16x/config.c for now */
2352
2353/* Serial console setup. Called from linux/init/main.c */
2354
2355void console_setup(char *str, int *ints)
2356{
2357 char *s;
2358 int baud, bits, parity;
2359 int cflag = 0;
2360
2361 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002362 if (ints[0] > 3 || ints[1] > 3)
2363 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
2365 /* Get baud, bits and parity */
2366 baud = 2400;
2367 bits = 8;
2368 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002369 if (ints[2])
2370 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 if ((s = strchr(str, ','))) {
2372 do {
2373 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002374 } while (*s >= '0' && *s <= '9');
2375 if (*s)
2376 parity = *s++;
2377 if (*s)
2378 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 }
2380
2381 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002382 switch (baud) {
2383 case 1200:
2384 cflag |= B1200;
2385 break;
2386 case 9600:
2387 cflag |= B9600;
2388 break;
2389 case 19200:
2390 cflag |= B19200;
2391 break;
2392 case 38400:
2393 cflag |= B38400;
2394 break;
2395 case 2400:
2396 default:
2397 cflag |= B2400;
2398 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002400 switch (bits) {
2401 case 7:
2402 cflag |= CS7;
2403 break;
2404 default:
2405 case 8:
2406 cflag |= CS8;
2407 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002409 switch (parity) {
2410 case 'o':
2411 case 'O':
2412 cflag |= PARODD;
2413 break;
2414 case 'e':
2415 case 'E':
2416 cflag |= PARENB;
2417 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 }
2419
2420 serial_console_info = &cy_port[ints[1]];
2421 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002422 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423}
2424#endif
2425
2426/*
2427 * The following is probably out of date for 2.1.x serial console stuff.
2428 *
2429 * The console is registered early on from arch/m68k/kernel/setup.c, and
2430 * it therefore relies on the chip being setup correctly by 166-Bug. This
2431 * seems reasonable, as the serial port has been used to invoke the system
2432 * boot. It also means that this function must not rely on any data
2433 * initialisation performed by serial167_init() etc.
2434 *
2435 * Of course, once the console has been registered, we had better ensure
2436 * that serial167_init() doesn't leave the chip non-functional.
2437 *
2438 * The console must be locked when we get here.
2439 */
2440
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002441void serial167_console_write(struct console *co, const char *str,
2442 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002444 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 unsigned long flags;
2446 volatile u_char sink;
2447 u_char ier;
2448 int port;
2449 u_char do_lf = 0;
2450 int i = 0;
2451
2452 local_irq_save(flags);
2453
2454 /* Ensure transmitter is enabled! */
2455
2456 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002457 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 while (base_addr[CyCCR])
2459 ;
2460 base_addr[CyCCR] = CyENB_XMTR;
2461
2462 ier = base_addr[CyIER];
2463 base_addr[CyIER] = CyTxMpty;
2464
2465 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002466 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 /* We have a Tx int. Acknowledge it */
2468 sink = pcc2chip[PccTPIACKR];
2469 if ((base_addr[CyLICR] >> 2) == port) {
2470 if (i == count) {
2471 /* Last char of string is now output */
2472 base_addr[CyTEOIR] = CyNOTRANS;
2473 break;
2474 }
2475 if (do_lf) {
2476 base_addr[CyTDR] = '\n';
2477 str++;
2478 i++;
2479 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002480 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 base_addr[CyTDR] = '\r';
2482 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002483 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 base_addr[CyTDR] = *str++;
2485 i++;
2486 }
2487 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002488 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 base_addr[CyTEOIR] = CyNOTRANS;
2490 }
2491 }
2492
2493 base_addr[CyIER] = ier;
2494
2495 local_irq_restore(flags);
2496}
2497
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002498static struct tty_driver *serial167_console_device(struct console *c,
2499 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500{
2501 *index = c->index;
2502 return cy_serial_driver;
2503}
2504
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002506 .name = "ttyS",
2507 .write = serial167_console_write,
2508 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002509 .flags = CON_PRINTBUFFER,
2510 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511};
2512
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513static int __init serial167_console_init(void)
2514{
2515 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002516 vme_brdtype == VME_TYPE_MVME167 ||
2517 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 mvme167_serial_console_setup(0);
2519 register_console(&sercons);
2520 }
2521 return 0;
2522}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002523
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524console_initcall(serial167_console_init);
2525
2526#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002527void putDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002529 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 unsigned long flags;
2531 volatile u_char sink;
2532 u_char ier;
2533 int port;
2534
2535 local_irq_save(flags);
2536
2537 /* Ensure transmitter is enabled! */
2538
2539 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002540 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 while (base_addr[CyCCR])
2542 ;
2543 base_addr[CyCCR] = CyENB_XMTR;
2544
2545 ier = base_addr[CyIER];
2546 base_addr[CyIER] = CyTxMpty;
2547
2548 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002549 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 /* We have a Tx int. Acknowledge it */
2551 sink = pcc2chip[PccTPIACKR];
2552 if ((base_addr[CyLICR] >> 2) == port) {
2553 base_addr[CyTDR] = c;
2554 base_addr[CyTEOIR] = 0;
2555 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002556 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 base_addr[CyTEOIR] = CyNOTRANS;
2558 }
2559 }
2560
2561 base_addr[CyIER] = ier;
2562
2563 local_irq_restore(flags);
2564}
2565
2566int getDebugChar()
2567{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002568 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 unsigned long flags;
2570 volatile u_char sink;
2571 u_char ier;
2572 int port;
2573 int i, c;
2574
2575 i = debugiq.out;
2576 if (i != debugiq.in) {
2577 c = debugiq.buf[i];
2578 if (++i == DEBUG_LEN)
2579 i = 0;
2580 debugiq.out = i;
2581 return c;
2582 }
2583 /* OK, nothing in queue, wait in poll loop */
2584
2585 local_irq_save(flags);
2586
2587 /* Ensure receiver is enabled! */
2588
2589 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002590 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591#if 0
2592 while (base_addr[CyCCR])
2593 ;
2594 base_addr[CyCCR] = CyENB_RCVR;
2595#endif
2596 ier = base_addr[CyIER];
2597 base_addr[CyIER] = CyRxData;
2598
2599 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002600 if (pcc2chip[PccSCCRICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 /* We have a Rx int. Acknowledge it */
2602 sink = pcc2chip[PccRPIACKR];
2603 if ((base_addr[CyLICR] >> 2) == port) {
2604 int cnt = base_addr[CyRFOC];
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002605 while (cnt-- > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 c = base_addr[CyRDR];
2607 if (c == 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002608 printk
2609 ("!! debug char is null (cnt=%d) !!",
2610 cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 else
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002612 queueDebugChar(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 }
2614 base_addr[CyREOIR] = 0;
2615 i = debugiq.out;
2616 if (i == debugiq.in)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002617 panic("Debug input queue empty!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 c = debugiq.buf[i];
2619 if (++i == DEBUG_LEN)
2620 i = 0;
2621 debugiq.out = i;
2622 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002623 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 base_addr[CyREOIR] = CyNOTRANS;
2625 }
2626 }
2627
2628 base_addr[CyIER] = ier;
2629
2630 local_irq_restore(flags);
2631
2632 return (c);
2633}
2634
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002635void queueDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636{
2637 int i;
2638
2639 i = debugiq.in;
2640 debugiq.buf[i] = c;
2641 if (++i == DEBUG_LEN)
2642 i = 0;
2643 if (i != debugiq.out)
2644 debugiq.in = i;
2645}
2646
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002647static void debug_setup()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002649 unsigned long flags;
2650 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2651 int i, cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002653 cflag = B19200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002655 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002657 for (i = 0; i < 4; i++) {
2658 base_addr[CyCAR] = i;
2659 base_addr[CyLICR] = i << 2;
2660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002662 debugiq.in = debugiq.out = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002664 base_addr[CyCAR] = DEBUG_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002666 /* baud rate */
2667 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002669 base_addr[CyIER] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002671 base_addr[CyCMR] = CyASYNC;
2672 base_addr[CyLICR] = DEBUG_PORT << 2;
2673 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002675 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002677 base_addr[CyTCOR] = baud_co[i];
2678 base_addr[CyTBPR] = baud_bpr[i];
2679 base_addr[CyRCOR] = baud_co[i] >> 5;
2680 base_addr[CyRBPR] = baud_bpr[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002682 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002684 base_addr[CySCHR1] = 0;
2685 base_addr[CySCHR2] = 0;
2686 base_addr[CySCRL] = 0;
2687 base_addr[CySCRH] = 0;
2688 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2689 base_addr[CyCOR2] = 0;
2690 base_addr[CyCOR3] = Cy_1_STOP;
2691 base_addr[CyCOR4] = baud_cor4[i];
2692 base_addr[CyCOR5] = 0;
2693 base_addr[CyCOR6] = 0;
2694 base_addr[CyCOR7] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002696 write_cy_cmd(base_addr, CyINIT_CHAN);
2697 write_cy_cmd(base_addr, CyENB_RCVR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002699 base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002701 base_addr[CyRTPRL] = 2;
2702 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002704 base_addr[CyMSVR1] = CyRTS;
2705 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002707 base_addr[CyIER] = CyRxData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002709 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002711} /* debug_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713#endif
2714
2715MODULE_LICENSE("GPL");