blob: 51e7a46787bea72aa23e93535e4d9ce636b63448 [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 *);
174extern void console_print(const char *);
175#ifdef CYCLOM_SHOW_STATUS
176static void show_status(int);
177#endif
178
179#ifdef CONFIG_REMOTE_DEBUG
180static void debug_setup(void);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800181void queueDebugChar(int c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182int getDebugChar(void);
183
184#define DEBUG_PORT 1
185#define DEBUG_LEN 256
186
187typedef struct {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800188 int in;
189 int out;
190 unsigned char buf[DEBUG_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191} debugq;
192
193debugq debugiq;
194#endif
195
196/*
197 * I have my own version of udelay(), as it is needed when initialising
198 * the chip, before the delay loop has been calibrated. Should probably
199 * reference one of the vmechip2 or pccchip2 counter for an accurate
200 * delay, but this wild guess will do for now.
201 */
202
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800203void my_udelay(long us)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
205 u_char x;
206 volatile u_char *p = &x;
207 int i;
208
209 while (us--)
210 for (i = 100; i; i--)
211 x |= *p;
212}
213
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800214static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
215 const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800218 if (!info) {
219 printk("Warning: null cyclades_port for (%s) in %s\n", name,
220 routine);
221 return 1;
222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800224 if ((long)info < (long)(&cy_port[0])
225 || (long)(&cy_port[NR_PORTS]) < (long)info) {
226 printk("Warning: cyclades_port out of range for (%s) in %s\n",
227 name, routine);
228 return 1;
229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800231 if (info->magic != CYCLADES_MAGIC) {
232 printk("Warning: bad magic number for serial struct (%s) in "
233 "%s\n", name, routine);
234 return 1;
235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236#endif
237 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800238} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240#if 0
241/* The following diagnostic routines allow the driver to spew
242 information on the screen, even (especially!) during interrupts.
243 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800244void SP(char *data)
245{
246 unsigned long flags;
247 local_irq_save(flags);
248 console_print(data);
249 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800252char scrn[2];
253void CP(char data)
254{
255 unsigned long flags;
256 local_irq_save(flags);
257 scrn[0] = data;
258 console_print(scrn);
259 local_irq_restore(flags);
260} /* CP */
261
262void CP1(int data)
263{
264 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
265} /* CP1 */
266void CP2(int data)
267{
268 CP1((data >> 4) & 0x0f);
269 CP1(data & 0x0f);
270} /* CP2 */
271void CP4(int data)
272{
273 CP2((data >> 8) & 0xff);
274 CP2(data & 0xff);
275} /* CP4 */
276void CP8(long data)
277{
278 CP4((data >> 16) & 0xffff);
279 CP4(data & 0xffff);
280} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281#endif
282
283/* This routine waits up to 1000 micro-seconds for the previous
284 command to the Cirrus chip to complete and then issues the
285 new command. An error is returned if the previous command
286 didn't finish within the time limit.
287 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800288u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800290 unsigned long flags;
291 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800293 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800295 for (i = 0; i < 100; i++) {
296 if (base_addr[CyCCR] == 0) {
297 break;
298 }
299 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800302 didn't finish within the "reasonable time" */
303 if (i == 10) {
304 local_irq_restore(flags);
305 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
307
308 /* Issue the new command */
309 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800310 local_irq_restore(flags);
311 return (0);
312} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314/* cy_start and cy_stop provide software output flow control as a
315 function of XON/XOFF, software CTS, and other such stuff. */
316
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800317static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Alan Coxc9f19e92009-01-02 13:47:26 +0000319 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800320 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
321 int channel;
322 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800325 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#endif
327
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800328 if (serial_paranoia_check(info, tty->name, "cy_stop"))
329 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800331 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800333 local_irq_save(flags);
334 base_addr[CyCAR] = (u_char) (channel); /* index channel */
335 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
336 local_irq_restore(flags);
337} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800339static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Alan Coxc9f19e92009-01-02 13:47:26 +0000341 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800342 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
343 int channel;
344 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800347 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348#endif
349
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800350 if (serial_paranoia_check(info, tty->name, "cy_start"))
351 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800353 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800355 local_irq_save(flags);
356 base_addr[CyCAR] = (u_char) (channel);
357 base_addr[CyIER] |= CyTxMpty;
358 local_irq_restore(flags);
359} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361/* The real interrupt service routines are called
362 whenever the card wants its hand held--chars
363 received, out buffer empty, modem change, etc.
364 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800365static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800367 struct tty_struct *tty;
368 struct cyclades_port *info;
369 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
370 unsigned char err, rfoc;
371 int channel;
372 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800374 /* determine the channel and change to that context */
375 channel = (u_short) (base_addr[CyLICR] >> 2);
376 info = &cy_port[channel];
377 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800379 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
380 /* This is a receive timeout interrupt, ignore it */
381 base_addr[CyREOIR] = CyNOTRANS;
382 return IRQ_HANDLED;
383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800385 /* Read a byte of data if there is any - assume the error
386 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800388 if ((rfoc = base_addr[CyRFOC]) != 0)
389 data = base_addr[CyRDR];
390 else
391 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800393 /* if there is nowhere to put the data, discard it */
394 if (info->tty == 0) {
395 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
396 return IRQ_HANDLED;
397 } else { /* there is an open port for this data */
398 tty = info->tty;
399 if (err & info->ignore_status_mask) {
400 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
401 return IRQ_HANDLED;
402 }
403 if (tty_buffer_request_room(tty, 1) != 0) {
404 if (err & info->read_status_mask) {
405 if (err & CyBREAK) {
406 tty_insert_flip_char(tty, data,
407 TTY_BREAK);
408 if (info->flags & ASYNC_SAK) {
409 do_SAK(tty);
410 }
411 } else if (err & CyFRAME) {
412 tty_insert_flip_char(tty, data,
413 TTY_FRAME);
414 } else if (err & CyPARITY) {
415 tty_insert_flip_char(tty, data,
416 TTY_PARITY);
417 } else if (err & CyOVERRUN) {
418 tty_insert_flip_char(tty, 0,
419 TTY_OVERRUN);
420 /*
421 If the flip buffer itself is
Nick Andrewc4f01242008-12-05 16:34:46 +0000422 overflowing, we still lose
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800423 the next incoming character.
424 */
425 if (tty_buffer_request_room(tty, 1) !=
426 0) {
427 tty_insert_flip_char(tty, data,
428 TTY_FRAME);
429 }
430 /* These two conditions may imply */
431 /* a normal read should be done. */
432 /* else if(data & CyTIMEOUT) */
433 /* else if(data & CySPECHAR) */
434 } else {
435 tty_insert_flip_char(tty, 0,
436 TTY_NORMAL);
437 }
438 } else {
439 tty_insert_flip_char(tty, data, TTY_NORMAL);
440 }
441 } else {
442 /* there was a software buffer overrun
443 and nothing could be done about it!!! */
444 }
445 }
446 tty_schedule_flip(tty);
447 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
449 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800450} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800452static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800454 struct cyclades_port *info;
455 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
456 int channel;
457 int mdm_change;
458 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800460 /* determine the channel and change to that context */
461 channel = (u_short) (base_addr[CyLICR] >> 2);
462 info = &cy_port[channel];
463 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800465 mdm_change = base_addr[CyMISR];
466 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800468 if (info->tty == 0) { /* nowhere to put the data, ignore it */
469 ;
470 } else {
471 if ((mdm_change & CyDCD)
472 && (info->flags & ASYNC_CHECK_CD)) {
473 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474/* CP('!'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800475 wake_up_interruptible(&info->open_wait);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800476 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477/* CP('@'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800478 tty_hangup(info->tty);
479 wake_up_interruptible(&info->open_wait);
480 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800483 if ((mdm_change & CyCTS)
484 && (info->flags & ASYNC_CTS_FLOW)) {
485 if (info->tty->stopped) {
486 if (mdm_status & CyCTS) {
487 /* !!! cy_start isn't used because... */
488 info->tty->stopped = 0;
489 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800490 tty_wakeup(info->tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800491 }
492 } else {
493 if (!(mdm_status & CyCTS)) {
494 /* !!! cy_stop isn't used because... */
495 info->tty->stopped = 1;
496 base_addr[CyIER] &=
497 ~(CyTxMpty | CyTxRdy);
498 }
499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800501 if (mdm_status & CyDSR) {
502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800504 base_addr[CyMEOIR] = 0;
505 return IRQ_HANDLED;
506} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800508static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800510 struct cyclades_port *info;
511 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
512 int channel;
513 int char_count, saved_cnt;
514 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800516 /* determine the channel and change to that context */
517 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800520 if (channel == DEBUG_PORT) {
521 panic("TxInt on debug port!!!");
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523#endif
524
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800525 info = &cy_port[channel];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800527 /* validate the port number (as configured and open) */
528 if ((channel < 0) || (NR_PORTS <= channel)) {
529 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
530 base_addr[CyTEOIR] = CyNOTRANS;
531 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800533 info->last_active = jiffies;
534 if (info->tty == 0) {
535 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800536 base_addr[CyTEOIR] = CyNOTRANS;
537 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800539
540 /* load the on-chip space available for outbound data */
541 saved_cnt = char_count = base_addr[CyTFTC];
542
543 if (info->x_char) { /* send special char */
544 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800547 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800550 if (info->x_break) {
551 /* The Cirrus chip requires the "Embedded Transmit
552 Commands" of start break, delay, and end break
553 sequences to be sent. The duration of the
554 break is given in TICs, which runs at HZ
555 (typically 100) and the PPR runs at 200 Hz,
556 so the delay is duration * 200/HZ, and thus a
557 break can run from 1/100 sec to about 5/4 sec.
558 Need to check these values - RGH 141095.
559 */
560 base_addr[CyTDR] = 0; /* start break */
561 base_addr[CyTDR] = 0x81;
562 base_addr[CyTDR] = 0; /* delay a bit */
563 base_addr[CyTDR] = 0x82;
564 base_addr[CyTDR] = info->x_break * 200 / HZ;
565 base_addr[CyTDR] = 0; /* terminate break */
566 base_addr[CyTDR] = 0x83;
567 char_count -= 7;
568 info->x_break = 0;
569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800571 while (char_count > 0) {
572 if (!info->xmit_cnt) {
573 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
574 break;
575 }
576 if (info->xmit_buf == 0) {
577 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
578 break;
579 }
580 if (info->tty->stopped || info->tty->hw_stopped) {
581 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
582 break;
583 }
584 /* Because the Embedded Transmit Commands have been
585 enabled, we must check to see if the escape
586 character, NULL, is being sent. If it is, we
587 must ensure that there is room for it to be
588 doubled in the output stream. Therefore we
589 no longer advance the pointer when the character
590 is fetched, but rather wait until after the check
591 for a NULL output character. (This is necessary
592 because there may not be room for the two chars
593 needed to send a NULL.
594 */
595 outch = info->xmit_buf[info->xmit_tail];
596 if (outch) {
597 info->xmit_cnt--;
598 info->xmit_tail = (info->xmit_tail + 1)
599 & (PAGE_SIZE - 1);
600 base_addr[CyTDR] = outch;
601 char_count--;
602 } else {
603 if (char_count > 1) {
604 info->xmit_cnt--;
605 info->xmit_tail = (info->xmit_tail + 1)
606 & (PAGE_SIZE - 1);
607 base_addr[CyTDR] = outch;
608 base_addr[CyTDR] = 0;
609 char_count--;
610 char_count--;
611 } else {
612 break;
613 }
614 }
615 }
616
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800617 if (info->xmit_cnt < WAKEUP_CHARS)
618 tty_wakeup(info->tty);
619
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800620 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
621 return IRQ_HANDLED;
622} /* cy_tx_interrupt */
623
624static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800626 struct tty_struct *tty;
627 struct cyclades_port *info;
628 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
629 int channel;
630 char data;
631 int char_count;
632 int save_cnt;
633 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800635 /* determine the channel and change to that context */
636 channel = (u_short) (base_addr[CyLICR] >> 2);
637 info = &cy_port[channel];
638 info->last_active = jiffies;
639 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800642 if (channel == DEBUG_PORT) {
643 while (char_count--) {
644 data = base_addr[CyRDR];
645 queueDebugChar(data);
646 }
647 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800649 /* if there is nowhere to put the data, discard it */
650 if (info->tty == 0) {
651 while (char_count--) {
652 data = base_addr[CyRDR];
653 }
654 } else { /* there is an open port for this data */
655 tty = info->tty;
656 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
658#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800659 ++info->mon.int_count;
660 info->mon.char_count += char_count;
661 if (char_count > info->mon.char_max)
662 info->mon.char_max = char_count;
663 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800665 len = tty_buffer_request_room(tty, char_count);
666 while (len--) {
667 data = base_addr[CyRDR];
668 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800670 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800672 }
673 tty_schedule_flip(tty);
674 }
675 /* end of service */
676 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
677 return IRQ_HANDLED;
678} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680/* This is called whenever a port becomes active;
681 interrupts are enabled and DTR & RTS are turned on.
682 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800683static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800685 unsigned long flags;
686 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
687 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800689 if (info->flags & ASYNC_INITIALIZED) {
690 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800692
693 if (!info->type) {
694 if (info->tty) {
695 set_bit(TTY_IO_ERROR, &info->tty->flags);
696 }
697 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800699 if (!info->xmit_buf) {
700 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
701 if (!info->xmit_buf) {
702 return -ENOMEM;
703 }
704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800706 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800708 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800711 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712#endif
713
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800714 local_irq_save(flags);
715 base_addr[CyCAR] = (u_char) channel;
716 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800718 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 base_addr[CyMSVR1] = CyRTS;
720/* CP('S');CP('1'); */
721 base_addr[CyMSVR2] = CyDTR;
722
723#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800724 printk("cyc: %d: raising DTR\n", __LINE__);
725 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
726 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727#endif
728
729 base_addr[CyIER] |= CyRxData;
730 info->flags |= ASYNC_INITIALIZED;
731
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800732 if (info->tty) {
733 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
736
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800737 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800740 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800742 return 0;
743} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800745void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800747 unsigned long flags;
748 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
749 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800751 channel = info->line;
752 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 base_addr[CyCAR] = channel;
754 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800755 local_irq_restore(flags);
756} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758/*
759 * This routine shuts down a serial port; interrupts are disabled,
760 * and DTR is dropped if the hangup on close termio flag is on.
761 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800762static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800764 unsigned long flags;
765 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
766 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800768 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800770 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800773 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800775#ifdef SERIAL_DEBUG_OPEN
776 printk("shutdown channel %d\n", channel);
777#endif
778
779 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
780 SENT BEFORE DROPPING THE LINE !!! (Perhaps
781 set some flag that is read when XMTY happens.)
782 Other choices are to delay some fixed interval
783 or schedule some later processing.
784 */
785 local_irq_save(flags);
786 if (info->xmit_buf) {
787 free_page((unsigned long)info->xmit_buf);
788 info->xmit_buf = NULL;
789 }
790
791 base_addr[CyCAR] = (u_char) channel;
792 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
793 base_addr[CyMSVR1] = 0;
794/* CP('C');CP('1'); */
795 base_addr[CyMSVR2] = 0;
796#ifdef SERIAL_DEBUG_DTR
797 printk("cyc: %d: dropping DTR\n", __LINE__);
798 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
799 base_addr[CyMSVR2]);
800#endif
801 }
802 write_cy_cmd(base_addr, CyDIS_RCVR);
803 /* it may be appropriate to clear _XMIT at
804 some later date (after testing)!!! */
805
806 if (info->tty) {
807 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
809 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800810 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800813 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800815} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817/*
818 * This routine finds or computes the various line characteristics.
819 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800820static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800822 unsigned long flags;
823 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
824 int channel;
825 unsigned cflag;
826 int i;
827 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800829 if (!info->tty || !info->tty->termios) {
830 return;
831 }
832 if (info->line == -1) {
833 return;
834 }
835 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800837 /* baud rate */
838 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839#ifdef CBAUDEX
840/* Starting with kernel 1.1.65, there is direct support for
841 higher baud rates. The following code supports those
842 changes. The conditional aspect allows this driver to be
843 used for earlier as well as later kernel versions. (The
844 mapping is slightly different from serial.c because there
845 is still the possibility of supporting 75 kbit/sec with
846 the Cyclades board.)
847 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800848 if (i & CBAUDEX) {
849 if (i == B57600)
850 i = 16;
851 else if (i == B115200)
852 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800854 else if (i == B78600)
855 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800857 else
858 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800861 if (i == 15) {
862 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
863 i += 1;
864 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
865 i += 3;
866 }
867 /* Don't ever change the speed of the console port. It will
868 * run at the speed specified in bootinfo, or at 19.2K */
869 /* Actually, it should run at whatever speed 166Bug was using */
870 /* Note info->timeout isn't used at present */
871 if (info != serial_console_info) {
872 info->tbpr = baud_bpr[i]; /* Tx BPR */
873 info->tco = baud_co[i]; /* Tx CO */
874 info->rbpr = baud_bpr[i]; /* Rx BPR */
875 info->rco = baud_co[i] >> 5; /* Rx CO */
876 if (baud_table[i] == 134) {
877 info->timeout =
878 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
879 /* get it right for 134.5 baud */
880 } else if (baud_table[i]) {
881 info->timeout =
882 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
883 2;
884 /* this needs to be propagated into the card info */
885 } else {
886 info->timeout = 0;
887 }
888 }
889 /* By tradition (is it a standard?) a baud rate of zero
890 implies the line should be/has been closed. A bit
891 later in this routine such a test is performed. */
892
893 /* byte size and parity */
894 info->cor7 = 0;
895 info->cor6 = 0;
896 info->cor5 = 0;
897 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
898 /* Following two lines added 101295, RGH. */
899 /* It is obviously wrong to access CyCORx, and not info->corx here,
900 * try and remember to fix it later! */
901 channel = info->line;
902 base_addr[CyCAR] = (u_char) channel;
903 if (C_CLOCAL(info->tty)) {
904 if (base_addr[CyIER] & CyMdmCh)
905 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
906 /* ignore 1->0 modem transitions */
907 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
908 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
909 /* ignore 0->1 modem transitions */
910 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
911 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
912 } else {
913 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
914 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
915 /* act on 1->0 modem transitions */
916 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
917 (CyDSR | CyCTS | CyDCD))
918 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
919 /* act on 0->1 modem transitions */
920 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
921 (CyDSR | CyCTS | CyDCD))
922 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
923 }
924 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
925 info->cor2 = CyETC;
926 switch (cflag & CSIZE) {
927 case CS5:
928 info->cor1 = Cy_5_BITS;
929 break;
930 case CS6:
931 info->cor1 = Cy_6_BITS;
932 break;
933 case CS7:
934 info->cor1 = Cy_7_BITS;
935 break;
936 case CS8:
937 info->cor1 = Cy_8_BITS;
938 break;
939 }
940 if (cflag & PARENB) {
941 if (cflag & PARODD) {
942 info->cor1 |= CyPARITY_O;
943 } else {
944 info->cor1 |= CyPARITY_E;
945 }
946 } else {
947 info->cor1 |= CyPARITY_NONE;
948 }
949
950 /* CTS flow control flag */
951#if 0
952 /* Don't complcate matters for now! RGH 141095 */
953 if (cflag & CRTSCTS) {
954 info->flags |= ASYNC_CTS_FLOW;
955 info->cor2 |= CyCtsAE;
956 } else {
957 info->flags &= ~ASYNC_CTS_FLOW;
958 info->cor2 &= ~CyCtsAE;
959 }
960#endif
961 if (cflag & CLOCAL)
962 info->flags &= ~ASYNC_CHECK_CD;
963 else
964 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 /***********************************************
967 The hardware option, CyRtsAO, presents RTS when
968 the chip has characters to send. Since most modems
969 use RTS as reverse (inbound) flow control, this
970 option is not used. If inbound flow control is
971 necessary, DTR can be programmed to provide the
972 appropriate signals for use with a non-standard
973 cable. Contact Marcio Saito for details.
974 ***********************************************/
975
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800976 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800978 local_irq_save(flags);
979 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 /* CyCMR set once only in mvme167_init_serial() */
982 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800983 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800985 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800987 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800990 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800992 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800994 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800996 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800998 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000 /* set line characteristics according configuration */
1001
1002 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001003 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001005 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001007 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001009 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001011 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001013 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001015 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001017 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001019 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001021 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001023 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001026 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001028 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 /* 2ms default rx timeout */
1031 ti = info->default_timeout ? info->default_timeout : 0x02;
1032 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001033 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001035 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001038 if (i == 0) { /* baud rate is zero, turn off line */
1039 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1040 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001042 printk("cyc: %d: dropping DTR\n", __LINE__);
1043 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1044 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001046 } else {
1047 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1048 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001050 printk("cyc: %d: raising DTR\n", __LINE__);
1051 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1052 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053#endif
1054 }
1055
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001056 if (info->tty) {
1057 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001060 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001062} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Alan Coxa5b08c62008-04-30 00:54:05 -07001064static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065{
Alan Coxc9f19e92009-01-02 13:47:26 +00001066 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001067 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001070 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071#endif
1072
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001073 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001074 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001076 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001079 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001081 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001082 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
1084
1085 info->xmit_buf[info->xmit_head++] = ch;
1086 info->xmit_head &= PAGE_SIZE - 1;
1087 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001088 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001089 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001090} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001092static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093{
Alan Coxc9f19e92009-01-02 13:47:26 +00001094 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001095 unsigned long flags;
1096 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1097 int channel;
1098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001100 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101#endif
1102
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001103 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1104 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001106 if (info->xmit_cnt <= 0 || tty->stopped
1107 || tty->hw_stopped || !info->xmit_buf)
1108 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001110 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001112 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 base_addr[CyCAR] = channel;
1114 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001115 local_irq_restore(flags);
1116} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118/* This routine gets called when tty_write has put something into
1119 the write_queue. If the port is not already transmitting stuff,
1120 start it off by enabling interrupts. The interrupt service
1121 routine will then ensure that the characters are sent. If the
1122 port is already active, there is no need to kick it.
1123 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001124static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125{
Alan Coxc9f19e92009-01-02 13:47:26 +00001126 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001127 unsigned long flags;
1128 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001131 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132#endif
1133
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001134 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1135 return 0;
1136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001138 if (!info->xmit_buf) {
1139 return 0;
1140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001142 while (1) {
1143 local_irq_save(flags);
1144 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1145 SERIAL_XMIT_SIZE - info->xmit_head));
1146 if (c <= 0) {
1147 local_irq_restore(flags);
1148 break;
1149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001151 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1152 info->xmit_head =
1153 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1154 info->xmit_cnt += c;
1155 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001157 buf += c;
1158 count -= c;
1159 total += c;
1160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001162 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1163 start_xmit(info);
1164 }
1165 return total;
1166} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001168static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169{
Alan Coxc9f19e92009-01-02 13:47:26 +00001170 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001171 int ret;
1172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001174 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175#endif
1176
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001177 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1178 return 0;
1179 ret = PAGE_SIZE - info->xmit_cnt - 1;
1180 if (ret < 0)
1181 ret = 0;
1182 return ret;
1183} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001185static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186{
Alan Coxc9f19e92009-01-02 13:47:26 +00001187 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001190 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191#endif
1192
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001193 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1194 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001196 return info->xmit_cnt;
1197} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001199static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
Alan Coxc9f19e92009-01-02 13:47:26 +00001201 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001202 unsigned long flags;
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001205 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206#endif
1207
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001208 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1209 return;
1210 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001212 local_irq_restore(flags);
1213 tty_wakeup(tty);
1214} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
1216/* This routine is called by the upper-layer tty layer to signal
1217 that incoming characters should be throttled or that the
1218 throttle should be released.
1219 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001220static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221{
Alan Coxc9f19e92009-01-02 13:47:26 +00001222 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001223 unsigned long flags;
1224 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1225 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001228 char buf[64];
1229
1230 printk("throttle %s: %d....\n", tty_name(tty, buf),
1231 tty->ldisc.chars_in_buffer(tty));
1232 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233#endif
1234
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001235 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1236 return;
1237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001239 if (I_IXOFF(tty)) {
1240 info->x_char = STOP_CHAR(tty);
1241 /* Should use the "Send Special Character" feature!!! */
1242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001244 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001246 local_irq_save(flags);
1247 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001249 local_irq_restore(flags);
1250} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001252static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253{
Alan Coxc9f19e92009-01-02 13:47:26 +00001254 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001255 unsigned long flags;
1256 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1257 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
1259#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001260 char buf[64];
1261
1262 printk("throttle %s: %d....\n", tty_name(tty, buf),
1263 tty->ldisc.chars_in_buffer(tty));
1264 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265#endif
1266
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001267 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1268 return;
1269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001271 if (I_IXOFF(tty)) {
1272 info->x_char = START_CHAR(tty);
1273 /* Should use the "Send Special Character" feature!!! */
1274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001276 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001278 local_irq_save(flags);
1279 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001281 local_irq_restore(flags);
1282} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001285get_serial_info(struct cyclades_port *info,
1286 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001288 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001291 if (!retinfo)
1292 return -EFAULT;
1293 memset(&tmp, 0, sizeof(tmp));
1294 tmp.type = info->type;
1295 tmp.line = info->line;
1296 tmp.port = info->line;
1297 tmp.irq = 0;
1298 tmp.flags = info->flags;
1299 tmp.baud_base = 0; /*!!! */
1300 tmp.close_delay = info->close_delay;
1301 tmp.custom_divisor = 0; /*!!! */
1302 tmp.hub6 = 0; /*!!! */
1303 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1304} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001307set_serial_info(struct cyclades_port *info,
1308 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001310 struct serial_struct new_serial;
1311 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001314 if (!new_info)
1315 return -EFAULT;
1316 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1317 return -EFAULT;
1318 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001320 if (!capable(CAP_SYS_ADMIN)) {
1321 if ((new_serial.close_delay != info->close_delay) ||
1322 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1323 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1324 return -EPERM;
1325 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1326 (new_serial.flags & ASYNC_USR_MASK));
1327 goto check_and_exit;
1328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001330 /*
1331 * OK, past this point, all the error checking has been done.
1332 * At this point, we start making changes.....
1333 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001335 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1336 (new_serial.flags & ASYNC_FLAGS));
1337 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001340 if (info->flags & ASYNC_INITIALIZED) {
1341 config_setup(info);
1342 return 0;
1343 }
1344 return startup(info);
1345} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001347static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348{
Alan Coxc9f19e92009-01-02 13:47:26 +00001349 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001350 int channel;
1351 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1352 unsigned long flags;
1353 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001355 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001357 local_irq_save(flags);
1358 base_addr[CyCAR] = (u_char) channel;
1359 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1360 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001362 return ((status & CyRTS) ? TIOCM_RTS : 0)
1363 | ((status & CyDTR) ? TIOCM_DTR : 0)
1364 | ((status & CyDCD) ? TIOCM_CAR : 0)
1365 | ((status & CyDSR) ? TIOCM_DSR : 0)
1366 | ((status & CyCTS) ? TIOCM_CTS : 0);
1367} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369static int
1370cy_tiocmset(struct tty_struct *tty, struct file *file,
1371 unsigned int set, unsigned int clear)
1372{
Alan Coxc9f19e92009-01-02 13:47:26 +00001373 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001374 int channel;
1375 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1376 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001378 channel = info->line;
1379
1380 if (set & TIOCM_RTS) {
1381 local_irq_save(flags);
1382 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001384 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001386 if (set & TIOCM_DTR) {
1387 local_irq_save(flags);
1388 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001390 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001392 printk("cyc: %d: raising DTR\n", __LINE__);
1393 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1394 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001396 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 }
1398
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001399 if (clear & TIOCM_RTS) {
1400 local_irq_save(flags);
1401 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001403 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001405 if (clear & TIOCM_DTR) {
1406 local_irq_save(flags);
1407 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001409 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001411 printk("cyc: %d: dropping DTR\n", __LINE__);
1412 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1413 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001415 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 }
1417
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001418 return 0;
1419} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001421static void send_break(struct cyclades_port *info, int duration)
1422{ /* Let the transmit ISR take care of this (since it
1423 requires stuffing characters into the output stream).
1424 */
1425 info->x_break = duration;
1426 if (!info->xmit_cnt) {
1427 start_xmit(info);
1428 }
1429} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001432get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
1434
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001435 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1436 return -EFAULT;
1437 info->mon.int_count = 0;
1438 info->mon.char_count = 0;
1439 info->mon.char_max = 0;
1440 info->mon.char_last = 0;
1441 return 0;
1442}
1443
1444static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1445{
1446 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1447 unsigned long value;
1448 int channel;
1449
1450 if (get_user(value, arg))
1451 return -EFAULT;
1452
1453 channel = info->line;
1454 info->cor4 &= ~CyREC_FIFO;
1455 info->cor4 |= value & CyREC_FIFO;
1456 base_addr[CyCOR4] = info->cor4;
1457 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458}
1459
1460static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001461get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001463 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1464 int channel;
1465 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001467 channel = info->line;
1468
1469 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1470 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471}
1472
1473static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001474set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001476 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001478 if (get_user(value, arg))
1479 return -EFAULT;
1480
1481 info->default_threshold = value & 0x0f;
1482 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483}
1484
1485static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001486get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001488 return put_user(info->default_threshold, value);
1489}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001491static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1492{
1493 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1494 int channel;
1495 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001497 if (get_user(value, arg))
1498 return -EFAULT;
1499
1500 channel = info->line;
1501
1502 base_addr[CyRTPRL] = value & 0xff;
1503 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1504 return 0;
1505}
1506
1507static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1508{
1509 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1510 int channel;
1511 unsigned long tmp;
1512
1513 channel = info->line;
1514
1515 tmp = base_addr[CyRTPRL];
1516 return put_user(tmp, value);
1517}
1518
1519static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1520{
1521 info->default_timeout = value & 0xff;
1522 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523}
1524
1525static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001526get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001528 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529}
1530
1531static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001532cy_ioctl(struct tty_struct *tty, struct file *file,
1533 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001535 unsigned long val;
Alan Coxc9f19e92009-01-02 13:47:26 +00001536 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001537 int ret_val = 0;
1538 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
1540#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001541 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542#endif
1543
Alan Cox638157b2008-04-30 00:53:22 -07001544 lock_kernel();
1545
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001546 switch (cmd) {
1547 case CYGETMON:
1548 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001550 case CYGETTHRESH:
1551 ret_val = get_threshold(info, argp);
1552 break;
1553 case CYSETTHRESH:
1554 ret_val = set_threshold(info, argp);
1555 break;
1556 case CYGETDEFTHRESH:
1557 ret_val = get_default_threshold(info, argp);
1558 break;
1559 case CYSETDEFTHRESH:
1560 ret_val = set_default_threshold(info, argp);
1561 break;
1562 case CYGETTIMEOUT:
1563 ret_val = get_timeout(info, argp);
1564 break;
1565 case CYSETTIMEOUT:
1566 ret_val = set_timeout(info, argp);
1567 break;
1568 case CYGETDEFTIMEOUT:
1569 ret_val = get_default_timeout(info, argp);
1570 break;
1571 case CYSETDEFTIMEOUT:
1572 ret_val = set_default_timeout(info, (unsigned long)arg);
1573 break;
1574 case TCSBRK: /* SVID version: non-zero arg --> no break */
1575 ret_val = tty_check_change(tty);
1576 if (ret_val)
1577 break;
1578 tty_wait_until_sent(tty, 0);
1579 if (!arg)
1580 send_break(info, HZ / 4); /* 1/4 second */
1581 break;
1582 case TCSBRKP: /* support for POSIX tcsendbreak() */
1583 ret_val = tty_check_change(tty);
1584 if (ret_val)
1585 break;
1586 tty_wait_until_sent(tty, 0);
1587 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1588 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001591 case TIOCGSERIAL:
1592 ret_val = get_serial_info(info, argp);
1593 break;
1594 case TIOCSSERIAL:
1595 ret_val = set_serial_info(info, argp);
1596 break;
1597 default:
1598 ret_val = -ENOIOCTLCMD;
1599 }
Alan Cox638157b2008-04-30 00:53:22 -07001600 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001603 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604#endif
1605
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001606 return ret_val;
1607} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001609static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610{
Alan Coxc9f19e92009-01-02 13:47:26 +00001611 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
1613#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001614 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615#endif
1616
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001617 if (tty->termios->c_cflag == old_termios->c_cflag)
1618 return;
1619 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001621 if ((old_termios->c_cflag & CRTSCTS) &&
1622 !(tty->termios->c_cflag & CRTSCTS)) {
1623 tty->stopped = 0;
1624 cy_start(tty);
1625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001627 if (!(old_termios->c_cflag & CLOCAL) &&
1628 (tty->termios->c_cflag & CLOCAL))
1629 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001631} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001633static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634{
Alan Coxc9f19e92009-01-02 13:47:26 +00001635 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637/* CP('C'); */
1638#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001639 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640#endif
1641
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001642 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1643 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001645#ifdef SERIAL_DEBUG_OPEN
1646 printk("cy_close %s, count = %d\n", tty->name, info->count);
1647#endif
1648
1649 if ((tty->count == 1) && (info->count != 1)) {
1650 /*
1651 * Uh, oh. tty->count is 1, which means that the tty
1652 * structure will be freed. Info->count should always
1653 * be one in these conditions. If it's greater than
1654 * one, we've got real problems, since it means the
1655 * serial port won't be shutdown.
1656 */
1657 printk("cy_close: bad serial port count; tty->count is 1, "
1658 "info->count is %d\n", info->count);
1659 info->count = 1;
1660 }
1661#ifdef SERIAL_DEBUG_COUNT
1662 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1663 info->count - 1);
1664#endif
1665 if (--info->count < 0) {
1666 printk("cy_close: bad serial port count for ttys%d: %d\n",
1667 info->line, info->count);
1668#ifdef SERIAL_DEBUG_COUNT
1669 printk("cyc: %d: setting count to 0\n", __LINE__);
1670#endif
1671 info->count = 0;
1672 }
1673 if (info->count)
1674 return;
1675 info->flags |= ASYNC_CLOSING;
1676 if (info->flags & ASYNC_INITIALIZED)
1677 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1678 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001679 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001680 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001681 info->tty = NULL;
1682 if (info->blocked_open) {
1683 if (info->close_delay) {
1684 msleep_interruptible(jiffies_to_msecs
1685 (info->close_delay));
1686 }
1687 wake_up_interruptible(&info->open_wait);
1688 }
1689 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1690 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001693 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001695} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697/*
1698 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1699 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001700void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701{
Alan Coxc9f19e92009-01-02 13:47:26 +00001702 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001705 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706#endif
1707
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001708 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1709 return;
1710
1711 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001713 info->event = 0;
1714 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001716 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001718 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001720 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1721 wake_up_interruptible(&info->open_wait);
1722} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724/*
1725 * ------------------------------------------------------------
1726 * cy_open() and friends
1727 * ------------------------------------------------------------
1728 */
1729
1730static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001731block_til_ready(struct tty_struct *tty, struct file *filp,
1732 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001734 DECLARE_WAITQUEUE(wait, current);
1735 unsigned long flags;
1736 int channel;
1737 int retval;
1738 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001740 /*
1741 * If the device is in the middle of being closed, then block
1742 * until it's done, and then try again.
1743 */
1744 if (info->flags & ASYNC_CLOSING) {
1745 interruptible_sleep_on(&info->close_wait);
1746 if (info->flags & ASYNC_HUP_NOTIFY) {
1747 return -EAGAIN;
1748 } else {
1749 return -ERESTARTSYS;
1750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001753 /*
1754 * If non-blocking mode is set, then make the check up front
1755 * and then exit.
1756 */
1757 if (filp->f_flags & O_NONBLOCK) {
1758 info->flags |= ASYNC_NORMAL_ACTIVE;
1759 return 0;
1760 }
1761
1762 /*
1763 * Block waiting for the carrier detect and the line to become
1764 * free (i.e., not in use by the callout). While we are in
1765 * this loop, info->count is dropped by one, so that
1766 * cy_close() knows when to free things. We restore it upon
1767 * exit, either normal or abnormal.
1768 */
1769 retval = 0;
1770 add_wait_queue(&info->open_wait, &wait);
1771#ifdef SERIAL_DEBUG_OPEN
1772 printk("block_til_ready before block: %s, count = %d\n",
1773 tty->name, info->count);
1774 /**/
1775#endif
1776 info->count--;
1777#ifdef SERIAL_DEBUG_COUNT
1778 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1779#endif
1780 info->blocked_open++;
1781
1782 channel = info->line;
1783
1784 while (1) {
1785 local_irq_save(flags);
1786 base_addr[CyCAR] = (u_char) channel;
1787 base_addr[CyMSVR1] = CyRTS;
1788/* CP('S');CP('4'); */
1789 base_addr[CyMSVR2] = CyDTR;
1790#ifdef SERIAL_DEBUG_DTR
1791 printk("cyc: %d: raising DTR\n", __LINE__);
1792 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1793 base_addr[CyMSVR2]);
1794#endif
1795 local_irq_restore(flags);
1796 set_current_state(TASK_INTERRUPTIBLE);
1797 if (tty_hung_up_p(filp)
1798 || !(info->flags & ASYNC_INITIALIZED)) {
1799 if (info->flags & ASYNC_HUP_NOTIFY) {
1800 retval = -EAGAIN;
1801 } else {
1802 retval = -ERESTARTSYS;
1803 }
1804 break;
1805 }
1806 local_irq_save(flags);
1807 base_addr[CyCAR] = (u_char) channel;
1808/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1809 if (!(info->flags & ASYNC_CLOSING)
1810 && (C_CLOCAL(tty)
1811 || (base_addr[CyMSVR1] & CyDCD))) {
1812 local_irq_restore(flags);
1813 break;
1814 }
1815 local_irq_restore(flags);
1816 if (signal_pending(current)) {
1817 retval = -ERESTARTSYS;
1818 break;
1819 }
1820#ifdef SERIAL_DEBUG_OPEN
1821 printk("block_til_ready blocking: %s, count = %d\n",
1822 tty->name, info->count);
1823 /**/
1824#endif
1825 schedule();
1826 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001827 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001828 remove_wait_queue(&info->open_wait, &wait);
1829 if (!tty_hung_up_p(filp)) {
1830 info->count++;
1831#ifdef SERIAL_DEBUG_COUNT
1832 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1833 info->count);
1834#endif
1835 }
1836 info->blocked_open--;
1837#ifdef SERIAL_DEBUG_OPEN
1838 printk("block_til_ready after blocking: %s, count = %d\n",
1839 tty->name, info->count);
1840 /**/
1841#endif
1842 if (retval)
1843 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 info->flags |= ASYNC_NORMAL_ACTIVE;
1845 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001846} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
1848/*
1849 * This routine is called whenever a serial port is opened. It
1850 * performs the serial-specific initialization for the tty structure.
1851 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001852int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001854 struct cyclades_port *info;
1855 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
1857/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001858 line = tty->index;
1859 if ((line < 0) || (NR_PORTS <= line)) {
1860 return -ENODEV;
1861 }
1862 info = &cy_port[line];
1863 if (info->line < 0) {
1864 return -ENODEV;
1865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001867 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001869 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1870 return -ENODEV;
1871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001873 printk("cy_open %s, count = %d\n", tty->name, info->count);
1874 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001876 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001878 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001880 tty->driver_data = info;
1881 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001883 /*
1884 * Start up serial port
1885 */
1886 retval = startup(info);
1887 if (retval) {
1888 return retval;
1889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001891 retval = block_til_ready(tty, filp, info);
1892 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001894 printk("cy_open returning after block_til_ready with %d\n",
1895 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001897 return retval;
1898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001900 printk("cy_open done\n");
1901 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001903 return 0;
1904} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906/*
1907 * ---------------------------------------------------------------------
1908 * serial167_init() and friends
1909 *
1910 * serial167_init() is called at boot-time to initialize the serial driver.
1911 * ---------------------------------------------------------------------
1912 */
1913
1914/*
1915 * This routine prints out the appropriate serial driver version
1916 * number, and identifies which options were configured into this
1917 * driver.
1918 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001919static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001921 printk("MVME166/167 cd2401 driver\n");
1922} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924/* initialize chips on card -- return number of valid
1925 chips (which is number of ports/4) */
1926
1927/*
1928 * This initialises the hardware to a reasonable state. It should
1929 * probe the chip first so as to copy 166-Bug setup as a default for
1930 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1931 * as to limit the number of CyINIT_CHAN commands in normal running.
1932 *
1933 * ... I wonder what I should do if this fails ...
1934 */
1935
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001936void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001938 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 int ch;
1940 u_char spd;
1941 u_char rcor, rbpr, badspeed = 0;
1942 unsigned long flags;
1943
1944 local_irq_save(flags);
1945
1946 /*
1947 * First probe channel zero of the chip, to see what speed has
1948 * been selected.
1949 */
1950
1951 base_addr[CyCAR] = 0;
1952
1953 rcor = base_addr[CyRCOR] << 5;
1954 rbpr = base_addr[CyRBPR];
1955
1956 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1957 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1958 break;
1959 if (spd >= sizeof(baud_bpr)) {
1960 spd = 14; /* 19200 */
1961 badspeed = 1; /* Failed to identify speed */
1962 }
1963 initial_console_speed = spd;
1964
1965 /* OK, we have chosen a speed, now reset and reinitialise */
1966
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001967 my_udelay(20000L); /* Allow time for any active o/p to complete */
1968 if (base_addr[CyCCR] != 0x00) {
1969 local_irq_restore(flags);
1970 /* printk(" chip is never idle (CCR != 0)\n"); */
1971 return;
1972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001974 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1975 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001977 if (base_addr[CyGFRCR] == 0x00) {
1978 local_irq_restore(flags);
1979 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1980 return;
1981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982
1983 /*
1984 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1985 * tick
1986 */
1987
1988 base_addr[CyTPR] = 10;
1989
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001990 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1991 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1992 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 /*
1995 * Attempt to set up all channels to something reasonable, and
1996 * bang out a INIT_CHAN command. We should then be able to limit
1997 * the ammount of fiddling we have to do in normal running.
1998 */
1999
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002000 for (ch = 3; ch >= 0; ch--) {
2001 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 base_addr[CyIER] = 0;
2003 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002004 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 base_addr[CyLIVR] = 0x5c;
2006 base_addr[CyTCOR] = baud_co[spd];
2007 base_addr[CyTBPR] = baud_bpr[spd];
2008 base_addr[CyRCOR] = baud_co[spd] >> 5;
2009 base_addr[CyRBPR] = baud_bpr[spd];
2010 base_addr[CySCHR1] = 'Q' & 0x1f;
2011 base_addr[CySCHR2] = 'X' & 0x1f;
2012 base_addr[CySCRL] = 0;
2013 base_addr[CySCRH] = 0;
2014 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2015 base_addr[CyCOR2] = 0;
2016 base_addr[CyCOR3] = Cy_1_STOP;
2017 base_addr[CyCOR4] = baud_cor4[spd];
2018 base_addr[CyCOR5] = 0;
2019 base_addr[CyCOR6] = 0;
2020 base_addr[CyCOR7] = 0;
2021 base_addr[CyRTPRL] = 2;
2022 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002023 base_addr[CyMSVR1] = 0;
2024 base_addr[CyMSVR2] = 0;
2025 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 }
2027
2028 /*
2029 * Now do specials for channel zero....
2030 */
2031
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002032 base_addr[CyMSVR1] = CyRTS;
2033 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002035 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
2037 local_irq_restore(flags);
2038
2039 my_udelay(20000L); /* Let it all settle down */
2040
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002041 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002043 printk
2044 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2045 rcor >> 5, rbpr);
2046} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002048static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 .open = cy_open,
2050 .close = cy_close,
2051 .write = cy_write,
2052 .put_char = cy_put_char,
2053 .flush_chars = cy_flush_chars,
2054 .write_room = cy_write_room,
2055 .chars_in_buffer = cy_chars_in_buffer,
2056 .flush_buffer = cy_flush_buffer,
2057 .ioctl = cy_ioctl,
2058 .throttle = cy_throttle,
2059 .unthrottle = cy_unthrottle,
2060 .set_termios = cy_set_termios,
2061 .stop = cy_stop,
2062 .start = cy_start,
2063 .hangup = cy_hangup,
2064 .tiocmget = cy_tiocmget,
2065 .tiocmset = cy_tiocmset,
2066};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002067
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068/* The serial driver boot-time initialization code!
2069 Hardware I/O ports are mapped to character special devices on a
2070 first found, first allocated manner. That is, this code searches
2071 for Cyclom cards in the system. As each is found, it is probed
2072 to discover how many chips (and thus how many ports) are present.
2073 These ports are mapped to the tty ports 64 and upward in monotonic
2074 fashion. If an 8-port card is replaced with a 16-port card, the
2075 port mapping on a following card will shift.
2076
2077 This approach is different from what is used in the other serial
2078 device driver because the Cyclom is more properly a multiplexer,
2079 not just an aggregation of serial ports on one card.
2080
2081 If there are more cards with more ports than have been statically
2082 allocated above, a warning is printed and the extra ports are ignored.
2083 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002084static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002086 struct cyclades_port *info;
2087 int ret = 0;
2088 int good_ports = 0;
2089 int port_num = 0;
2090 int index;
2091 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002093 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094#endif
2095
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002096 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2097 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002099 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2100 if (!cy_serial_driver)
2101 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
2103#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002104 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105#endif
2106
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002107 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002109 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2110 if (serial_console_cflag)
2111 DefSpeed = serial_console_cflag & 0017;
2112 else {
2113 DefSpeed = initial_console_speed;
2114 serial_console_info = &cy_port[0];
2115 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002117 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002120
2121 /* Initialize the tty_driver structure */
2122
2123 cy_serial_driver->owner = THIS_MODULE;
2124 cy_serial_driver->name = "ttyS";
2125 cy_serial_driver->major = TTY_MAJOR;
2126 cy_serial_driver->minor_start = 64;
2127 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2128 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2129 cy_serial_driver->init_termios = tty_std_termios;
2130 cy_serial_driver->init_termios.c_cflag =
2131 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2132 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2133 tty_set_operations(cy_serial_driver, &cy_ops);
2134
2135 ret = tty_register_driver(cy_serial_driver);
2136 if (ret) {
2137 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2138 put_tty_driver(cy_serial_driver);
2139 return ret;
2140 }
2141
2142 port_num = 0;
2143 info = cy_port;
2144 for (index = 0; index < 1; index++) {
2145
2146 good_ports = 4;
2147
2148 if (port_num < NR_PORTS) {
2149 while (good_ports-- && port_num < NR_PORTS) {
2150 /*** initialize port ***/
2151 info->magic = CYCLADES_MAGIC;
2152 info->type = PORT_CIRRUS;
2153 info->card = index;
2154 info->line = port_num;
2155 info->flags = STD_COM_FLAGS;
2156 info->tty = NULL;
2157 info->xmit_fifo_size = 12;
2158 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2159 info->cor2 = CyETC;
2160 info->cor3 = Cy_1_STOP;
2161 info->cor4 = 0x08; /* _very_ small receive threshold */
2162 info->cor5 = 0;
2163 info->cor6 = 0;
2164 info->cor7 = 0;
2165 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2166 info->tco = baud_co[DefSpeed]; /* Tx CO */
2167 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2168 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2169 info->close_delay = 0;
2170 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002171 info->count = 0;
2172#ifdef SERIAL_DEBUG_COUNT
2173 printk("cyc: %d: setting count to 0\n",
2174 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002176 info->blocked_open = 0;
2177 info->default_threshold = 0;
2178 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002179 init_waitqueue_head(&info->open_wait);
2180 init_waitqueue_head(&info->close_wait);
2181 /* info->session */
2182 /* info->pgrp */
2183/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2184 info->read_status_mask =
2185 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2186 CyFRAME | CyOVERRUN;
2187 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002189 printk("ttyS%d ", info->line);
2190 port_num++;
2191 info++;
2192 if (!(port_num & 7)) {
2193 printk("\n ");
2194 }
2195 }
2196 }
2197 printk("\n");
2198 }
2199 while (port_num < NR_PORTS) {
2200 info->line = -1;
2201 port_num++;
2202 info++;
2203 }
2204#ifdef CONFIG_REMOTE_DEBUG
2205 debug_setup();
2206#endif
2207 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2208 "cd2401_errors", cd2401_rxerr_interrupt);
2209 if (ret) {
2210 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2211 goto cleanup_serial_driver;
2212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002214 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2215 "cd2401_modem", cd2401_modem_interrupt);
2216 if (ret) {
2217 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2218 goto cleanup_irq_cd2401_errors;
2219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002221 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2222 "cd2401_txints", cd2401_tx_interrupt);
2223 if (ret) {
2224 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2225 goto cleanup_irq_cd2401_modem;
2226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002228 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2229 "cd2401_rxints", cd2401_rx_interrupt);
2230 if (ret) {
2231 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2232 goto cleanup_irq_cd2401_txints;
2233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002235 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002237 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2238 pcc2chip[PccSCCTICR] = 0x15;
2239 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002241 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2242
2243 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002245 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002247 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002249 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002251 if (tty_unregister_driver(cy_serial_driver))
2252 printk(KERN_ERR
2253 "Couldn't unregister MVME166/7 serial driver\n");
2254 put_tty_driver(cy_serial_driver);
2255 return ret;
2256} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
2258module_init(serial167_init);
2259
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002261static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002263 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2264 int channel;
2265 struct cyclades_port *info;
2266 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002268 info = &cy_port[line_num];
2269 channel = info->line;
2270 printk(" channel %d\n", channel);
2271 /**/ printk(" cy_port\n");
2272 printk(" card line flags = %d %d %x\n",
2273 info->card, info->line, info->flags);
2274 printk
2275 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2276 (long)info->tty, info->read_status_mask, info->timeout,
2277 info->xmit_fifo_size);
2278 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2279 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2280 info->cor6, info->cor7);
2281 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2282 info->rbpr, info->rco);
2283 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2284 info->event, info->count);
2285 printk(" x_char blocked_open = %x %x\n", info->x_char,
2286 info->blocked_open);
2287 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002289 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291/* Global Registers */
2292
2293 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2294 printk(" CyCAR %x\n", base_addr[CyCAR]);
2295 printk(" CyRISR %x\n", base_addr[CyRISR]);
2296 printk(" CyTISR %x\n", base_addr[CyTISR]);
2297 printk(" CyMISR %x\n", base_addr[CyMISR]);
2298 printk(" CyRIR %x\n", base_addr[CyRIR]);
2299 printk(" CyTIR %x\n", base_addr[CyTIR]);
2300 printk(" CyMIR %x\n", base_addr[CyMIR]);
2301 printk(" CyTPR %x\n", base_addr[CyTPR]);
2302
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002303 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
2305/* Virtual Registers */
2306
2307#if 0
2308 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2309 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2310 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2311 printk(" CyMISR %x\n", base_addr[CyMISR]);
2312#endif
2313
2314/* Channel Registers */
2315
2316 printk(" CyCCR %x\n", base_addr[CyCCR]);
2317 printk(" CyIER %x\n", base_addr[CyIER]);
2318 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2319 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2320 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2321 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2322 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2323#if 0
2324 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2325 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2326#endif
2327 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2328 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2329#if 0
2330 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2331 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2332 printk(" CySCRL %x\n", base_addr[CySCRL]);
2333 printk(" CySCRH %x\n", base_addr[CySCRH]);
2334 printk(" CyLNC %x\n", base_addr[CyLNC]);
2335 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2336 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2337#endif
2338 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2339 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2340 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2341 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2342 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2343 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2344 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2345 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2346
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002347 local_irq_restore(flags);
2348} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349#endif
2350
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351#if 0
2352/* Dummy routine in mvme16x/config.c for now */
2353
2354/* Serial console setup. Called from linux/init/main.c */
2355
2356void console_setup(char *str, int *ints)
2357{
2358 char *s;
2359 int baud, bits, parity;
2360 int cflag = 0;
2361
2362 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002363 if (ints[0] > 3 || ints[1] > 3)
2364 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
2366 /* Get baud, bits and parity */
2367 baud = 2400;
2368 bits = 8;
2369 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002370 if (ints[2])
2371 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 if ((s = strchr(str, ','))) {
2373 do {
2374 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002375 } while (*s >= '0' && *s <= '9');
2376 if (*s)
2377 parity = *s++;
2378 if (*s)
2379 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
2381
2382 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002383 switch (baud) {
2384 case 1200:
2385 cflag |= B1200;
2386 break;
2387 case 9600:
2388 cflag |= B9600;
2389 break;
2390 case 19200:
2391 cflag |= B19200;
2392 break;
2393 case 38400:
2394 cflag |= B38400;
2395 break;
2396 case 2400:
2397 default:
2398 cflag |= B2400;
2399 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002401 switch (bits) {
2402 case 7:
2403 cflag |= CS7;
2404 break;
2405 default:
2406 case 8:
2407 cflag |= CS8;
2408 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002410 switch (parity) {
2411 case 'o':
2412 case 'O':
2413 cflag |= PARODD;
2414 break;
2415 case 'e':
2416 case 'E':
2417 cflag |= PARENB;
2418 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 }
2420
2421 serial_console_info = &cy_port[ints[1]];
2422 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002423 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424}
2425#endif
2426
2427/*
2428 * The following is probably out of date for 2.1.x serial console stuff.
2429 *
2430 * The console is registered early on from arch/m68k/kernel/setup.c, and
2431 * it therefore relies on the chip being setup correctly by 166-Bug. This
2432 * seems reasonable, as the serial port has been used to invoke the system
2433 * boot. It also means that this function must not rely on any data
2434 * initialisation performed by serial167_init() etc.
2435 *
2436 * Of course, once the console has been registered, we had better ensure
2437 * that serial167_init() doesn't leave the chip non-functional.
2438 *
2439 * The console must be locked when we get here.
2440 */
2441
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002442void serial167_console_write(struct console *co, const char *str,
2443 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002445 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 unsigned long flags;
2447 volatile u_char sink;
2448 u_char ier;
2449 int port;
2450 u_char do_lf = 0;
2451 int i = 0;
2452
2453 local_irq_save(flags);
2454
2455 /* Ensure transmitter is enabled! */
2456
2457 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002458 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 while (base_addr[CyCCR])
2460 ;
2461 base_addr[CyCCR] = CyENB_XMTR;
2462
2463 ier = base_addr[CyIER];
2464 base_addr[CyIER] = CyTxMpty;
2465
2466 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002467 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 /* We have a Tx int. Acknowledge it */
2469 sink = pcc2chip[PccTPIACKR];
2470 if ((base_addr[CyLICR] >> 2) == port) {
2471 if (i == count) {
2472 /* Last char of string is now output */
2473 base_addr[CyTEOIR] = CyNOTRANS;
2474 break;
2475 }
2476 if (do_lf) {
2477 base_addr[CyTDR] = '\n';
2478 str++;
2479 i++;
2480 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002481 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 base_addr[CyTDR] = '\r';
2483 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002484 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 base_addr[CyTDR] = *str++;
2486 i++;
2487 }
2488 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002489 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 base_addr[CyTEOIR] = CyNOTRANS;
2491 }
2492 }
2493
2494 base_addr[CyIER] = ier;
2495
2496 local_irq_restore(flags);
2497}
2498
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002499static struct tty_driver *serial167_console_device(struct console *c,
2500 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501{
2502 *index = c->index;
2503 return cy_serial_driver;
2504}
2505
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002507 .name = "ttyS",
2508 .write = serial167_console_write,
2509 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002510 .flags = CON_PRINTBUFFER,
2511 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512};
2513
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514static int __init serial167_console_init(void)
2515{
2516 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002517 vme_brdtype == VME_TYPE_MVME167 ||
2518 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 mvme167_serial_console_setup(0);
2520 register_console(&sercons);
2521 }
2522 return 0;
2523}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002524
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525console_initcall(serial167_console_init);
2526
2527#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002528void putDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002530 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 unsigned long flags;
2532 volatile u_char sink;
2533 u_char ier;
2534 int port;
2535
2536 local_irq_save(flags);
2537
2538 /* Ensure transmitter is enabled! */
2539
2540 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002541 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 while (base_addr[CyCCR])
2543 ;
2544 base_addr[CyCCR] = CyENB_XMTR;
2545
2546 ier = base_addr[CyIER];
2547 base_addr[CyIER] = CyTxMpty;
2548
2549 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002550 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 /* We have a Tx int. Acknowledge it */
2552 sink = pcc2chip[PccTPIACKR];
2553 if ((base_addr[CyLICR] >> 2) == port) {
2554 base_addr[CyTDR] = c;
2555 base_addr[CyTEOIR] = 0;
2556 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002557 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 base_addr[CyTEOIR] = CyNOTRANS;
2559 }
2560 }
2561
2562 base_addr[CyIER] = ier;
2563
2564 local_irq_restore(flags);
2565}
2566
2567int getDebugChar()
2568{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002569 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 unsigned long flags;
2571 volatile u_char sink;
2572 u_char ier;
2573 int port;
2574 int i, c;
2575
2576 i = debugiq.out;
2577 if (i != debugiq.in) {
2578 c = debugiq.buf[i];
2579 if (++i == DEBUG_LEN)
2580 i = 0;
2581 debugiq.out = i;
2582 return c;
2583 }
2584 /* OK, nothing in queue, wait in poll loop */
2585
2586 local_irq_save(flags);
2587
2588 /* Ensure receiver is enabled! */
2589
2590 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002591 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592#if 0
2593 while (base_addr[CyCCR])
2594 ;
2595 base_addr[CyCCR] = CyENB_RCVR;
2596#endif
2597 ier = base_addr[CyIER];
2598 base_addr[CyIER] = CyRxData;
2599
2600 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002601 if (pcc2chip[PccSCCRICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 /* We have a Rx int. Acknowledge it */
2603 sink = pcc2chip[PccRPIACKR];
2604 if ((base_addr[CyLICR] >> 2) == port) {
2605 int cnt = base_addr[CyRFOC];
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002606 while (cnt-- > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 c = base_addr[CyRDR];
2608 if (c == 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002609 printk
2610 ("!! debug char is null (cnt=%d) !!",
2611 cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 else
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002613 queueDebugChar(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 }
2615 base_addr[CyREOIR] = 0;
2616 i = debugiq.out;
2617 if (i == debugiq.in)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002618 panic("Debug input queue empty!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 c = debugiq.buf[i];
2620 if (++i == DEBUG_LEN)
2621 i = 0;
2622 debugiq.out = i;
2623 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002624 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 base_addr[CyREOIR] = CyNOTRANS;
2626 }
2627 }
2628
2629 base_addr[CyIER] = ier;
2630
2631 local_irq_restore(flags);
2632
2633 return (c);
2634}
2635
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002636void queueDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637{
2638 int i;
2639
2640 i = debugiq.in;
2641 debugiq.buf[i] = c;
2642 if (++i == DEBUG_LEN)
2643 i = 0;
2644 if (i != debugiq.out)
2645 debugiq.in = i;
2646}
2647
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002648static void debug_setup()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002650 unsigned long flags;
2651 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2652 int i, cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002654 cflag = B19200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002656 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002658 for (i = 0; i < 4; i++) {
2659 base_addr[CyCAR] = i;
2660 base_addr[CyLICR] = i << 2;
2661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002663 debugiq.in = debugiq.out = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002665 base_addr[CyCAR] = DEBUG_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002667 /* baud rate */
2668 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002670 base_addr[CyIER] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002672 base_addr[CyCMR] = CyASYNC;
2673 base_addr[CyLICR] = DEBUG_PORT << 2;
2674 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002676 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002678 base_addr[CyTCOR] = baud_co[i];
2679 base_addr[CyTBPR] = baud_bpr[i];
2680 base_addr[CyRCOR] = baud_co[i] >> 5;
2681 base_addr[CyRBPR] = baud_bpr[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002683 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002685 base_addr[CySCHR1] = 0;
2686 base_addr[CySCHR2] = 0;
2687 base_addr[CySCRL] = 0;
2688 base_addr[CySCRH] = 0;
2689 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2690 base_addr[CyCOR2] = 0;
2691 base_addr[CyCOR3] = Cy_1_STOP;
2692 base_addr[CyCOR4] = baud_cor4[i];
2693 base_addr[CyCOR5] = 0;
2694 base_addr[CyCOR6] = 0;
2695 base_addr[CyCOR7] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002697 write_cy_cmd(base_addr, CyINIT_CHAN);
2698 write_cy_cmd(base_addr, CyENB_RCVR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002700 base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002702 base_addr[CyRTPRL] = 2;
2703 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002705 base_addr[CyMSVR1] = CyRTS;
2706 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002708 base_addr[CyIER] = CyRxData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002710 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002712} /* debug_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
2714#endif
2715
2716MODULE_LICENSE("GPL");