blob: 78a62ebe75c72e02c2a9f2ba1ff6a469f63a07ea [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090067#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#include <asm/system.h>
70#include <asm/io.h>
71#include <asm/mvme16xhw.h>
72#include <asm/bootinfo.h>
73#include <asm/setup.h>
74
75#include <linux/types.h>
76#include <linux/kernel.h>
77
78#include <asm/uaccess.h>
79#include <linux/init.h>
80
81#define SERIAL_PARANOIA_CHECK
82#undef SERIAL_DEBUG_OPEN
83#undef SERIAL_DEBUG_THROTTLE
84#undef SERIAL_DEBUG_OTHER
85#undef SERIAL_DEBUG_IO
86#undef SERIAL_DEBUG_COUNT
87#undef SERIAL_DEBUG_DTR
88#undef CYCLOM_16Y_HACK
89#define CYCLOM_ENABLE_MONITORING
90
91#define WAKEUP_CHARS 256
92
93#define STD_COM_FLAGS (0)
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static struct tty_driver *cy_serial_driver;
96extern int serial_console;
97static struct cyclades_port *serial_console_info = NULL;
98static unsigned int serial_console_cflag = 0;
99u_char initial_console_speed;
100
101/* Base address of cd2401 chip on mvme166/7 */
102
103#define BASE_ADDR (0xfff45000)
104#define pcc2chip ((volatile u_char *)0xfff42000)
105#define PccSCCMICR 0x1d
106#define PccSCCTICR 0x1e
107#define PccSCCRICR 0x1f
108#define PccTPIACKR 0x25
109#define PccRPIACKR 0x27
110#define PccIMLR 0x3f
111
112/* This is the per-port data structure */
113struct cyclades_port cy_port[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800114 /* CARD# */
115 {-1}, /* ttyS0 */
116 {-1}, /* ttyS1 */
117 {-1}, /* ttyS2 */
118 {-1}, /* ttyS3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800120
Tobias Klauserfe971072006-01-09 20:54:02 -0800121#define NR_PORTS ARRAY_SIZE(cy_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 * This is used to look up the divisor speeds and the timeouts
125 * We're normally limited to 15 distinct baud rates. The extra
126 * are accessed via settings in info->flags.
127 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
128 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
129 * HI VHI
130 */
131static int baud_table[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800132 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
133 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
134 0
135};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800138static char baud_co[] = { /* 25 MHz clock option table */
139 /* value => 00 01 02 03 04 */
140 /* divide by 8 32 128 512 2048 */
141 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
142 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
143};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800145static char baud_bpr[] = { /* 25 MHz baud rate period table */
146 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
147 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
148};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#endif
150
151/* I think 166 brd clocks 2401 at 20MHz.... */
152
153/* These values are written directly to tcor, and >> 5 for writing to rcor */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800154static u_char baud_co[] = { /* 20 MHz clock option table */
155 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40,
156 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
157};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159/* These values written directly to tbpr/rbpr */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800160static u_char baud_bpr[] = { /* 20 MHz baud rate period table */
161 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81,
162 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10
163};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800165static u_char baud_cor4[] = { /* receive threshold */
166 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
167 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07
168};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170static void shutdown(struct cyclades_port *);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800171static int startup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static void cy_throttle(struct tty_struct *);
173static void cy_unthrottle(struct tty_struct *);
174static void config_setup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#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
Roel Kluinf23fc152009-10-01 15:44:25 -0700224 if (info < &cy_port[0] || info >= &cy_port[NR_PORTS]) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800225 printk("Warning: cyclades_port out of range for (%s) in %s\n",
226 name, routine);
227 return 1;
228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800230 if (info->magic != CYCLADES_MAGIC) {
231 printk("Warning: bad magic number for serial struct (%s) in "
232 "%s\n", name, routine);
233 return 1;
234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#endif
236 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800237} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239#if 0
240/* The following diagnostic routines allow the driver to spew
241 information on the screen, even (especially!) during interrupts.
242 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800243void SP(char *data)
244{
245 unsigned long flags;
246 local_irq_save(flags);
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700247 printk(KERN_EMERG "%s", data);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800248 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800251char scrn[2];
252void CP(char data)
253{
254 unsigned long flags;
255 local_irq_save(flags);
256 scrn[0] = data;
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700257 printk(KERN_EMERG "%c", scrn);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800258 local_irq_restore(flags);
259} /* CP */
260
261void CP1(int data)
262{
263 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
264} /* CP1 */
265void CP2(int data)
266{
267 CP1((data >> 4) & 0x0f);
268 CP1(data & 0x0f);
269} /* CP2 */
270void CP4(int data)
271{
272 CP2((data >> 8) & 0xff);
273 CP2(data & 0xff);
274} /* CP4 */
275void CP8(long data)
276{
277 CP4((data >> 16) & 0xffff);
278 CP4(data & 0xffff);
279} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280#endif
281
282/* This routine waits up to 1000 micro-seconds for the previous
283 command to the Cirrus chip to complete and then issues the
284 new command. An error is returned if the previous command
285 didn't finish within the time limit.
286 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800287u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800289 unsigned long flags;
290 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800292 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800294 for (i = 0; i < 100; i++) {
295 if (base_addr[CyCCR] == 0) {
296 break;
297 }
298 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800301 didn't finish within the "reasonable time" */
302 if (i == 10) {
303 local_irq_restore(flags);
304 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 }
306
307 /* Issue the new command */
308 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800309 local_irq_restore(flags);
310 return (0);
311} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313/* cy_start and cy_stop provide software output flow control as a
314 function of XON/XOFF, software CTS, and other such stuff. */
315
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800316static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Alan Coxc9f19e92009-01-02 13:47:26 +0000318 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800319 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
320 int channel;
321 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800324 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325#endif
326
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800327 if (serial_paranoia_check(info, tty->name, "cy_stop"))
328 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800330 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800332 local_irq_save(flags);
333 base_addr[CyCAR] = (u_char) (channel); /* index channel */
334 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
335 local_irq_restore(flags);
336} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800338static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Alan Coxc9f19e92009-01-02 13:47:26 +0000340 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800341 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
342 int channel;
343 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800346 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#endif
348
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800349 if (serial_paranoia_check(info, tty->name, "cy_start"))
350 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800352 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800354 local_irq_save(flags);
355 base_addr[CyCAR] = (u_char) (channel);
356 base_addr[CyIER] |= CyTxMpty;
357 local_irq_restore(flags);
358} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360/* The real interrupt service routines are called
361 whenever the card wants its hand held--chars
362 received, out buffer empty, modem change, etc.
363 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800364static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800366 struct tty_struct *tty;
367 struct cyclades_port *info;
368 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
369 unsigned char err, rfoc;
370 int channel;
371 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800373 /* determine the channel and change to that context */
374 channel = (u_short) (base_addr[CyLICR] >> 2);
375 info = &cy_port[channel];
376 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800378 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
379 /* This is a receive timeout interrupt, ignore it */
380 base_addr[CyREOIR] = CyNOTRANS;
381 return IRQ_HANDLED;
382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800384 /* Read a byte of data if there is any - assume the error
385 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800387 if ((rfoc = base_addr[CyRFOC]) != 0)
388 data = base_addr[CyRDR];
389 else
390 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800392 /* if there is nowhere to put the data, discard it */
393 if (info->tty == 0) {
394 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
395 return IRQ_HANDLED;
396 } else { /* there is an open port for this data */
397 tty = info->tty;
398 if (err & info->ignore_status_mask) {
399 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
400 return IRQ_HANDLED;
401 }
402 if (tty_buffer_request_room(tty, 1) != 0) {
403 if (err & info->read_status_mask) {
404 if (err & CyBREAK) {
405 tty_insert_flip_char(tty, data,
406 TTY_BREAK);
407 if (info->flags & ASYNC_SAK) {
408 do_SAK(tty);
409 }
410 } else if (err & CyFRAME) {
411 tty_insert_flip_char(tty, data,
412 TTY_FRAME);
413 } else if (err & CyPARITY) {
414 tty_insert_flip_char(tty, data,
415 TTY_PARITY);
416 } else if (err & CyOVERRUN) {
417 tty_insert_flip_char(tty, 0,
418 TTY_OVERRUN);
419 /*
420 If the flip buffer itself is
Nick Andrewc4f01242008-12-05 16:34:46 +0000421 overflowing, we still lose
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800422 the next incoming character.
423 */
424 if (tty_buffer_request_room(tty, 1) !=
425 0) {
426 tty_insert_flip_char(tty, data,
427 TTY_FRAME);
428 }
429 /* These two conditions may imply */
430 /* a normal read should be done. */
431 /* else if(data & CyTIMEOUT) */
432 /* else if(data & CySPECHAR) */
433 } else {
434 tty_insert_flip_char(tty, 0,
435 TTY_NORMAL);
436 }
437 } else {
438 tty_insert_flip_char(tty, data, TTY_NORMAL);
439 }
440 } else {
441 /* there was a software buffer overrun
442 and nothing could be done about it!!! */
443 }
444 }
445 tty_schedule_flip(tty);
446 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
448 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800449} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800451static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800453 struct cyclades_port *info;
454 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
455 int channel;
456 int mdm_change;
457 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800459 /* determine the channel and change to that context */
460 channel = (u_short) (base_addr[CyLICR] >> 2);
461 info = &cy_port[channel];
462 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800464 mdm_change = base_addr[CyMISR];
465 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800467 if (info->tty == 0) { /* nowhere to put the data, ignore it */
468 ;
469 } else {
470 if ((mdm_change & CyDCD)
471 && (info->flags & ASYNC_CHECK_CD)) {
472 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/* CP('!'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800474 wake_up_interruptible(&info->open_wait);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800475 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476/* CP('@'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800477 tty_hangup(info->tty);
478 wake_up_interruptible(&info->open_wait);
479 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800482 if ((mdm_change & CyCTS)
483 && (info->flags & ASYNC_CTS_FLOW)) {
484 if (info->tty->stopped) {
485 if (mdm_status & CyCTS) {
486 /* !!! cy_start isn't used because... */
487 info->tty->stopped = 0;
488 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800489 tty_wakeup(info->tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800490 }
491 } else {
492 if (!(mdm_status & CyCTS)) {
493 /* !!! cy_stop isn't used because... */
494 info->tty->stopped = 1;
495 base_addr[CyIER] &=
496 ~(CyTxMpty | CyTxRdy);
497 }
498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800500 if (mdm_status & CyDSR) {
501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800503 base_addr[CyMEOIR] = 0;
504 return IRQ_HANDLED;
505} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800507static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800509 struct cyclades_port *info;
510 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
511 int channel;
512 int char_count, saved_cnt;
513 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800515 /* determine the channel and change to that context */
516 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800519 if (channel == DEBUG_PORT) {
520 panic("TxInt on debug port!!!");
521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800523 /* validate the port number (as configured and open) */
524 if ((channel < 0) || (NR_PORTS <= channel)) {
525 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
526 base_addr[CyTEOIR] = CyNOTRANS;
527 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 }
Roel Kluinf23fc152009-10-01 15:44:25 -0700529 info = &cy_port[channel];
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800530 info->last_active = jiffies;
531 if (info->tty == 0) {
532 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800533 base_addr[CyTEOIR] = CyNOTRANS;
534 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800536
537 /* load the on-chip space available for outbound data */
538 saved_cnt = char_count = base_addr[CyTFTC];
539
540 if (info->x_char) { /* send special char */
541 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800544 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800547 if (info->x_break) {
548 /* The Cirrus chip requires the "Embedded Transmit
549 Commands" of start break, delay, and end break
550 sequences to be sent. The duration of the
551 break is given in TICs, which runs at HZ
552 (typically 100) and the PPR runs at 200 Hz,
553 so the delay is duration * 200/HZ, and thus a
554 break can run from 1/100 sec to about 5/4 sec.
555 Need to check these values - RGH 141095.
556 */
557 base_addr[CyTDR] = 0; /* start break */
558 base_addr[CyTDR] = 0x81;
559 base_addr[CyTDR] = 0; /* delay a bit */
560 base_addr[CyTDR] = 0x82;
561 base_addr[CyTDR] = info->x_break * 200 / HZ;
562 base_addr[CyTDR] = 0; /* terminate break */
563 base_addr[CyTDR] = 0x83;
564 char_count -= 7;
565 info->x_break = 0;
566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800568 while (char_count > 0) {
569 if (!info->xmit_cnt) {
570 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
571 break;
572 }
573 if (info->xmit_buf == 0) {
574 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
575 break;
576 }
577 if (info->tty->stopped || info->tty->hw_stopped) {
578 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
579 break;
580 }
581 /* Because the Embedded Transmit Commands have been
582 enabled, we must check to see if the escape
583 character, NULL, is being sent. If it is, we
584 must ensure that there is room for it to be
585 doubled in the output stream. Therefore we
586 no longer advance the pointer when the character
587 is fetched, but rather wait until after the check
588 for a NULL output character. (This is necessary
589 because there may not be room for the two chars
590 needed to send a NULL.
591 */
592 outch = info->xmit_buf[info->xmit_tail];
593 if (outch) {
594 info->xmit_cnt--;
595 info->xmit_tail = (info->xmit_tail + 1)
596 & (PAGE_SIZE - 1);
597 base_addr[CyTDR] = outch;
598 char_count--;
599 } else {
600 if (char_count > 1) {
601 info->xmit_cnt--;
602 info->xmit_tail = (info->xmit_tail + 1)
603 & (PAGE_SIZE - 1);
604 base_addr[CyTDR] = outch;
605 base_addr[CyTDR] = 0;
606 char_count--;
607 char_count--;
608 } else {
609 break;
610 }
611 }
612 }
613
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800614 if (info->xmit_cnt < WAKEUP_CHARS)
615 tty_wakeup(info->tty);
616
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800617 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
618 return IRQ_HANDLED;
619} /* cy_tx_interrupt */
620
621static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800623 struct tty_struct *tty;
624 struct cyclades_port *info;
625 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
626 int channel;
627 char data;
628 int char_count;
629 int save_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800631 /* determine the channel and change to that context */
632 channel = (u_short) (base_addr[CyLICR] >> 2);
633 info = &cy_port[channel];
634 info->last_active = jiffies;
635 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800638 if (channel == DEBUG_PORT) {
639 while (char_count--) {
640 data = base_addr[CyRDR];
641 queueDebugChar(data);
642 }
643 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800645 /* if there is nowhere to put the data, discard it */
646 if (info->tty == 0) {
647 while (char_count--) {
648 data = base_addr[CyRDR];
649 }
650 } else { /* there is an open port for this data */
651 tty = info->tty;
652 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800655 ++info->mon.int_count;
656 info->mon.char_count += char_count;
657 if (char_count > info->mon.char_max)
658 info->mon.char_max = char_count;
659 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660#endif
Alan Cox4165fe42010-02-17 13:07:13 +0000661 while (char_count--) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800662 data = base_addr[CyRDR];
663 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800665 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800667 }
668 tty_schedule_flip(tty);
669 }
670 /* end of service */
671 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
672 return IRQ_HANDLED;
673} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675/* This is called whenever a port becomes active;
676 interrupts are enabled and DTR & RTS are turned on.
677 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800678static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800680 unsigned long flags;
681 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
682 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800684 if (info->flags & ASYNC_INITIALIZED) {
685 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800687
688 if (!info->type) {
689 if (info->tty) {
690 set_bit(TTY_IO_ERROR, &info->tty->flags);
691 }
692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800694 if (!info->xmit_buf) {
695 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
696 if (!info->xmit_buf) {
697 return -ENOMEM;
698 }
699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800701 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800703 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800706 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707#endif
708
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800709 local_irq_save(flags);
710 base_addr[CyCAR] = (u_char) channel;
711 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800713 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 base_addr[CyMSVR1] = CyRTS;
715/* CP('S');CP('1'); */
716 base_addr[CyMSVR2] = CyDTR;
717
718#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800719 printk("cyc: %d: raising DTR\n", __LINE__);
720 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
721 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722#endif
723
724 base_addr[CyIER] |= CyRxData;
725 info->flags |= ASYNC_INITIALIZED;
726
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800727 if (info->tty) {
728 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
731
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800732 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800735 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800737 return 0;
738} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800740void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800742 unsigned long flags;
743 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
744 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800746 channel = info->line;
747 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 base_addr[CyCAR] = channel;
749 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800750 local_irq_restore(flags);
751} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753/*
754 * This routine shuts down a serial port; interrupts are disabled,
755 * and DTR is dropped if the hangup on close termio flag is on.
756 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800757static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800759 unsigned long flags;
760 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
761 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800763 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800765 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800768 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800770#ifdef SERIAL_DEBUG_OPEN
771 printk("shutdown channel %d\n", channel);
772#endif
773
774 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
775 SENT BEFORE DROPPING THE LINE !!! (Perhaps
776 set some flag that is read when XMTY happens.)
777 Other choices are to delay some fixed interval
778 or schedule some later processing.
779 */
780 local_irq_save(flags);
781 if (info->xmit_buf) {
782 free_page((unsigned long)info->xmit_buf);
783 info->xmit_buf = NULL;
784 }
785
786 base_addr[CyCAR] = (u_char) channel;
787 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
788 base_addr[CyMSVR1] = 0;
789/* CP('C');CP('1'); */
790 base_addr[CyMSVR2] = 0;
791#ifdef SERIAL_DEBUG_DTR
792 printk("cyc: %d: dropping DTR\n", __LINE__);
793 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
794 base_addr[CyMSVR2]);
795#endif
796 }
797 write_cy_cmd(base_addr, CyDIS_RCVR);
798 /* it may be appropriate to clear _XMIT at
799 some later date (after testing)!!! */
800
801 if (info->tty) {
802 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800805 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800808 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800810} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812/*
813 * This routine finds or computes the various line characteristics.
814 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800815static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800817 unsigned long flags;
818 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
819 int channel;
820 unsigned cflag;
821 int i;
822 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800824 if (!info->tty || !info->tty->termios) {
825 return;
826 }
827 if (info->line == -1) {
828 return;
829 }
830 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800832 /* baud rate */
833 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834#ifdef CBAUDEX
835/* Starting with kernel 1.1.65, there is direct support for
836 higher baud rates. The following code supports those
837 changes. The conditional aspect allows this driver to be
838 used for earlier as well as later kernel versions. (The
839 mapping is slightly different from serial.c because there
840 is still the possibility of supporting 75 kbit/sec with
841 the Cyclades board.)
842 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800843 if (i & CBAUDEX) {
844 if (i == B57600)
845 i = 16;
846 else if (i == B115200)
847 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800849 else if (i == B78600)
850 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800852 else
853 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800856 if (i == 15) {
857 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
858 i += 1;
859 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
860 i += 3;
861 }
862 /* Don't ever change the speed of the console port. It will
863 * run at the speed specified in bootinfo, or at 19.2K */
864 /* Actually, it should run at whatever speed 166Bug was using */
865 /* Note info->timeout isn't used at present */
866 if (info != serial_console_info) {
867 info->tbpr = baud_bpr[i]; /* Tx BPR */
868 info->tco = baud_co[i]; /* Tx CO */
869 info->rbpr = baud_bpr[i]; /* Rx BPR */
870 info->rco = baud_co[i] >> 5; /* Rx CO */
871 if (baud_table[i] == 134) {
872 info->timeout =
873 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
874 /* get it right for 134.5 baud */
875 } else if (baud_table[i]) {
876 info->timeout =
877 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
878 2;
879 /* this needs to be propagated into the card info */
880 } else {
881 info->timeout = 0;
882 }
883 }
884 /* By tradition (is it a standard?) a baud rate of zero
885 implies the line should be/has been closed. A bit
886 later in this routine such a test is performed. */
887
888 /* byte size and parity */
889 info->cor7 = 0;
890 info->cor6 = 0;
891 info->cor5 = 0;
892 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
893 /* Following two lines added 101295, RGH. */
894 /* It is obviously wrong to access CyCORx, and not info->corx here,
895 * try and remember to fix it later! */
896 channel = info->line;
897 base_addr[CyCAR] = (u_char) channel;
898 if (C_CLOCAL(info->tty)) {
899 if (base_addr[CyIER] & CyMdmCh)
900 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
901 /* ignore 1->0 modem transitions */
902 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
903 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
904 /* ignore 0->1 modem transitions */
905 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
906 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
907 } else {
908 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
909 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
910 /* act on 1->0 modem transitions */
911 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
912 (CyDSR | CyCTS | CyDCD))
913 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
914 /* act on 0->1 modem transitions */
915 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
916 (CyDSR | CyCTS | CyDCD))
917 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
918 }
919 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
920 info->cor2 = CyETC;
921 switch (cflag & CSIZE) {
922 case CS5:
923 info->cor1 = Cy_5_BITS;
924 break;
925 case CS6:
926 info->cor1 = Cy_6_BITS;
927 break;
928 case CS7:
929 info->cor1 = Cy_7_BITS;
930 break;
931 case CS8:
932 info->cor1 = Cy_8_BITS;
933 break;
934 }
935 if (cflag & PARENB) {
936 if (cflag & PARODD) {
937 info->cor1 |= CyPARITY_O;
938 } else {
939 info->cor1 |= CyPARITY_E;
940 }
941 } else {
942 info->cor1 |= CyPARITY_NONE;
943 }
944
945 /* CTS flow control flag */
946#if 0
947 /* Don't complcate matters for now! RGH 141095 */
948 if (cflag & CRTSCTS) {
949 info->flags |= ASYNC_CTS_FLOW;
950 info->cor2 |= CyCtsAE;
951 } else {
952 info->flags &= ~ASYNC_CTS_FLOW;
953 info->cor2 &= ~CyCtsAE;
954 }
955#endif
956 if (cflag & CLOCAL)
957 info->flags &= ~ASYNC_CHECK_CD;
958 else
959 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 /***********************************************
962 The hardware option, CyRtsAO, presents RTS when
963 the chip has characters to send. Since most modems
964 use RTS as reverse (inbound) flow control, this
965 option is not used. If inbound flow control is
966 necessary, DTR can be programmed to provide the
967 appropriate signals for use with a non-standard
968 cable. Contact Marcio Saito for details.
969 ***********************************************/
970
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800971 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800973 local_irq_save(flags);
974 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 /* CyCMR set once only in mvme167_init_serial() */
977 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800978 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800980 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800982 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
984 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800985 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800987 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800989 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800991 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800993 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 /* set line characteristics according configuration */
996
997 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800998 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001000 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001002 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001004 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001006 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001008 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001010 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001012 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001014 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001016 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001018 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001021 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001023 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 /* 2ms default rx timeout */
1026 ti = info->default_timeout ? info->default_timeout : 0x02;
1027 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001028 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001030 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001033 if (i == 0) { /* baud rate is zero, turn off line */
1034 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1035 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001037 printk("cyc: %d: dropping DTR\n", __LINE__);
1038 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1039 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001041 } else {
1042 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1043 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001045 printk("cyc: %d: raising DTR\n", __LINE__);
1046 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1047 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048#endif
1049 }
1050
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001051 if (info->tty) {
1052 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001055 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001057} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Alan Coxa5b08c62008-04-30 00:54:05 -07001059static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060{
Alan Coxc9f19e92009-01-02 13:47:26 +00001061 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001062 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001065 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066#endif
1067
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001068 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001069 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001071 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001072 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001074 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001076 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 }
1079
1080 info->xmit_buf[info->xmit_head++] = ch;
1081 info->xmit_head &= PAGE_SIZE - 1;
1082 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001083 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001084 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001085} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001087static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
Alan Coxc9f19e92009-01-02 13:47:26 +00001089 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001090 unsigned long flags;
1091 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1092 int channel;
1093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001095 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096#endif
1097
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001098 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1099 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001101 if (info->xmit_cnt <= 0 || tty->stopped
1102 || tty->hw_stopped || !info->xmit_buf)
1103 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001105 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001107 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 base_addr[CyCAR] = channel;
1109 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001110 local_irq_restore(flags);
1111} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113/* This routine gets called when tty_write has put something into
1114 the write_queue. If the port is not already transmitting stuff,
1115 start it off by enabling interrupts. The interrupt service
1116 routine will then ensure that the characters are sent. If the
1117 port is already active, there is no need to kick it.
1118 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001119static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
Alan Coxc9f19e92009-01-02 13:47:26 +00001121 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001122 unsigned long flags;
1123 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001126 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127#endif
1128
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001129 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1130 return 0;
1131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001133 if (!info->xmit_buf) {
1134 return 0;
1135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001137 while (1) {
1138 local_irq_save(flags);
1139 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1140 SERIAL_XMIT_SIZE - info->xmit_head));
1141 if (c <= 0) {
1142 local_irq_restore(flags);
1143 break;
1144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001146 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1147 info->xmit_head =
1148 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1149 info->xmit_cnt += c;
1150 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001152 buf += c;
1153 count -= c;
1154 total += c;
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001157 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1158 start_xmit(info);
1159 }
1160 return total;
1161} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001163static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
Alan Coxc9f19e92009-01-02 13:47:26 +00001165 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001166 int ret;
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001169 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170#endif
1171
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001172 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1173 return 0;
1174 ret = PAGE_SIZE - info->xmit_cnt - 1;
1175 if (ret < 0)
1176 ret = 0;
1177 return ret;
1178} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001180static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
Alan Coxc9f19e92009-01-02 13:47:26 +00001182 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001185 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186#endif
1187
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001188 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1189 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001191 return info->xmit_cnt;
1192} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001194static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Alan Coxc9f19e92009-01-02 13:47:26 +00001196 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001197 unsigned long flags;
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001200 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201#endif
1202
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001203 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1204 return;
1205 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001207 local_irq_restore(flags);
1208 tty_wakeup(tty);
1209} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211/* This routine is called by the upper-layer tty layer to signal
1212 that incoming characters should be throttled or that the
1213 throttle should be released.
1214 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001215static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
Alan Coxc9f19e92009-01-02 13:47:26 +00001217 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001218 unsigned long flags;
1219 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1220 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001223 char buf[64];
1224
1225 printk("throttle %s: %d....\n", tty_name(tty, buf),
1226 tty->ldisc.chars_in_buffer(tty));
1227 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228#endif
1229
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001230 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1231 return;
1232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001234 if (I_IXOFF(tty)) {
1235 info->x_char = STOP_CHAR(tty);
1236 /* Should use the "Send Special Character" feature!!! */
1237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001239 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001241 local_irq_save(flags);
1242 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001244 local_irq_restore(flags);
1245} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001247static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248{
Alan Coxc9f19e92009-01-02 13:47:26 +00001249 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001250 unsigned long flags;
1251 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1252 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001255 char buf[64];
1256
1257 printk("throttle %s: %d....\n", tty_name(tty, buf),
1258 tty->ldisc.chars_in_buffer(tty));
1259 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260#endif
1261
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001262 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1263 return;
1264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001266 if (I_IXOFF(tty)) {
1267 info->x_char = START_CHAR(tty);
1268 /* Should use the "Send Special Character" feature!!! */
1269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001271 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001273 local_irq_save(flags);
1274 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001276 local_irq_restore(flags);
1277} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001280get_serial_info(struct cyclades_port *info,
1281 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001283 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001286 if (!retinfo)
1287 return -EFAULT;
1288 memset(&tmp, 0, sizeof(tmp));
1289 tmp.type = info->type;
1290 tmp.line = info->line;
1291 tmp.port = info->line;
1292 tmp.irq = 0;
1293 tmp.flags = info->flags;
1294 tmp.baud_base = 0; /*!!! */
1295 tmp.close_delay = info->close_delay;
1296 tmp.custom_divisor = 0; /*!!! */
1297 tmp.hub6 = 0; /*!!! */
1298 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1299} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001302set_serial_info(struct cyclades_port *info,
1303 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001305 struct serial_struct new_serial;
1306 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
1308/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001309 if (!new_info)
1310 return -EFAULT;
1311 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1312 return -EFAULT;
1313 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001315 if (!capable(CAP_SYS_ADMIN)) {
1316 if ((new_serial.close_delay != info->close_delay) ||
1317 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1318 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1319 return -EPERM;
1320 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1321 (new_serial.flags & ASYNC_USR_MASK));
1322 goto check_and_exit;
1323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001325 /*
1326 * OK, past this point, all the error checking has been done.
1327 * At this point, we start making changes.....
1328 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001330 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1331 (new_serial.flags & ASYNC_FLAGS));
1332 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001335 if (info->flags & ASYNC_INITIALIZED) {
1336 config_setup(info);
1337 return 0;
1338 }
1339 return startup(info);
1340} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001342static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
Alan Coxc9f19e92009-01-02 13:47:26 +00001344 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001345 int channel;
1346 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1347 unsigned long flags;
1348 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001350 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001352 local_irq_save(flags);
1353 base_addr[CyCAR] = (u_char) channel;
1354 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1355 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001357 return ((status & CyRTS) ? TIOCM_RTS : 0)
1358 | ((status & CyDTR) ? TIOCM_DTR : 0)
1359 | ((status & CyDCD) ? TIOCM_CAR : 0)
1360 | ((status & CyDSR) ? TIOCM_DSR : 0)
1361 | ((status & CyCTS) ? TIOCM_CTS : 0);
1362} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
1364static int
1365cy_tiocmset(struct tty_struct *tty, struct file *file,
1366 unsigned int set, unsigned int clear)
1367{
Alan Coxc9f19e92009-01-02 13:47:26 +00001368 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001369 int channel;
1370 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1371 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001373 channel = info->line;
1374
1375 if (set & TIOCM_RTS) {
1376 local_irq_save(flags);
1377 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001379 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001381 if (set & TIOCM_DTR) {
1382 local_irq_save(flags);
1383 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001385 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001387 printk("cyc: %d: raising DTR\n", __LINE__);
1388 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1389 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001391 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
1393
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001394 if (clear & TIOCM_RTS) {
1395 local_irq_save(flags);
1396 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001398 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001400 if (clear & TIOCM_DTR) {
1401 local_irq_save(flags);
1402 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001404 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001406 printk("cyc: %d: dropping DTR\n", __LINE__);
1407 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1408 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001410 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 }
1412
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001413 return 0;
1414} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001416static void send_break(struct cyclades_port *info, int duration)
1417{ /* Let the transmit ISR take care of this (since it
1418 requires stuffing characters into the output stream).
1419 */
1420 info->x_break = duration;
1421 if (!info->xmit_cnt) {
1422 start_xmit(info);
1423 }
1424} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001427get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428{
1429
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001430 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1431 return -EFAULT;
1432 info->mon.int_count = 0;
1433 info->mon.char_count = 0;
1434 info->mon.char_max = 0;
1435 info->mon.char_last = 0;
1436 return 0;
1437}
1438
1439static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1440{
1441 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1442 unsigned long value;
1443 int channel;
1444
1445 if (get_user(value, arg))
1446 return -EFAULT;
1447
1448 channel = info->line;
1449 info->cor4 &= ~CyREC_FIFO;
1450 info->cor4 |= value & CyREC_FIFO;
1451 base_addr[CyCOR4] = info->cor4;
1452 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453}
1454
1455static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001456get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001458 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1459 int channel;
1460 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001462 channel = info->line;
1463
1464 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1465 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466}
1467
1468static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001469set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001471 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001473 if (get_user(value, arg))
1474 return -EFAULT;
1475
1476 info->default_threshold = value & 0x0f;
1477 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478}
1479
1480static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001481get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001483 return put_user(info->default_threshold, value);
1484}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001486static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1487{
1488 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1489 int channel;
1490 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001492 if (get_user(value, arg))
1493 return -EFAULT;
1494
1495 channel = info->line;
1496
1497 base_addr[CyRTPRL] = value & 0xff;
1498 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1499 return 0;
1500}
1501
1502static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1503{
1504 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1505 int channel;
1506 unsigned long tmp;
1507
1508 channel = info->line;
1509
1510 tmp = base_addr[CyRTPRL];
1511 return put_user(tmp, value);
1512}
1513
1514static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1515{
1516 info->default_timeout = value & 0xff;
1517 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518}
1519
1520static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001521get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001523 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524}
1525
1526static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001527cy_ioctl(struct tty_struct *tty, struct file *file,
1528 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
Alan Coxc9f19e92009-01-02 13:47:26 +00001530 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001531 int ret_val = 0;
1532 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001535 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536#endif
1537
Alan Cox638157b2008-04-30 00:53:22 -07001538 lock_kernel();
1539
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001540 switch (cmd) {
1541 case CYGETMON:
1542 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001544 case CYGETTHRESH:
1545 ret_val = get_threshold(info, argp);
1546 break;
1547 case CYSETTHRESH:
1548 ret_val = set_threshold(info, argp);
1549 break;
1550 case CYGETDEFTHRESH:
1551 ret_val = get_default_threshold(info, argp);
1552 break;
1553 case CYSETDEFTHRESH:
1554 ret_val = set_default_threshold(info, argp);
1555 break;
1556 case CYGETTIMEOUT:
1557 ret_val = get_timeout(info, argp);
1558 break;
1559 case CYSETTIMEOUT:
1560 ret_val = set_timeout(info, argp);
1561 break;
1562 case CYGETDEFTIMEOUT:
1563 ret_val = get_default_timeout(info, argp);
1564 break;
1565 case CYSETDEFTIMEOUT:
1566 ret_val = set_default_timeout(info, (unsigned long)arg);
1567 break;
1568 case TCSBRK: /* SVID version: non-zero arg --> no break */
1569 ret_val = tty_check_change(tty);
1570 if (ret_val)
1571 break;
1572 tty_wait_until_sent(tty, 0);
1573 if (!arg)
1574 send_break(info, HZ / 4); /* 1/4 second */
1575 break;
1576 case TCSBRKP: /* support for POSIX tcsendbreak() */
1577 ret_val = tty_check_change(tty);
1578 if (ret_val)
1579 break;
1580 tty_wait_until_sent(tty, 0);
1581 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1582 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001585 case TIOCGSERIAL:
1586 ret_val = get_serial_info(info, argp);
1587 break;
1588 case TIOCSSERIAL:
1589 ret_val = set_serial_info(info, argp);
1590 break;
1591 default:
1592 ret_val = -ENOIOCTLCMD;
1593 }
Alan Cox638157b2008-04-30 00:53:22 -07001594 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001597 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598#endif
1599
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001600 return ret_val;
1601} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001603static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604{
Alan Coxc9f19e92009-01-02 13:47:26 +00001605 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001608 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609#endif
1610
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001611 if (tty->termios->c_cflag == old_termios->c_cflag)
1612 return;
1613 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001615 if ((old_termios->c_cflag & CRTSCTS) &&
1616 !(tty->termios->c_cflag & CRTSCTS)) {
1617 tty->stopped = 0;
1618 cy_start(tty);
1619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001621 if (!(old_termios->c_cflag & CLOCAL) &&
1622 (tty->termios->c_cflag & CLOCAL))
1623 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001625} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001627static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
Alan Coxc9f19e92009-01-02 13:47:26 +00001629 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631/* CP('C'); */
1632#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001633 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634#endif
1635
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001636 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1637 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001639#ifdef SERIAL_DEBUG_OPEN
1640 printk("cy_close %s, count = %d\n", tty->name, info->count);
1641#endif
1642
1643 if ((tty->count == 1) && (info->count != 1)) {
1644 /*
1645 * Uh, oh. tty->count is 1, which means that the tty
1646 * structure will be freed. Info->count should always
1647 * be one in these conditions. If it's greater than
1648 * one, we've got real problems, since it means the
1649 * serial port won't be shutdown.
1650 */
1651 printk("cy_close: bad serial port count; tty->count is 1, "
1652 "info->count is %d\n", info->count);
1653 info->count = 1;
1654 }
1655#ifdef SERIAL_DEBUG_COUNT
1656 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1657 info->count - 1);
1658#endif
1659 if (--info->count < 0) {
1660 printk("cy_close: bad serial port count for ttys%d: %d\n",
1661 info->line, info->count);
1662#ifdef SERIAL_DEBUG_COUNT
1663 printk("cyc: %d: setting count to 0\n", __LINE__);
1664#endif
1665 info->count = 0;
1666 }
1667 if (info->count)
1668 return;
1669 info->flags |= ASYNC_CLOSING;
1670 if (info->flags & ASYNC_INITIALIZED)
1671 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1672 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001673 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001674 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001675 info->tty = NULL;
1676 if (info->blocked_open) {
1677 if (info->close_delay) {
1678 msleep_interruptible(jiffies_to_msecs
1679 (info->close_delay));
1680 }
1681 wake_up_interruptible(&info->open_wait);
1682 }
1683 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1684 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
1686#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001687 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001689} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691/*
1692 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1693 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001694void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695{
Alan Coxc9f19e92009-01-02 13:47:26 +00001696 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001699 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700#endif
1701
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001702 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1703 return;
1704
1705 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001707 info->event = 0;
1708 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001710 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001712 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001714 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1715 wake_up_interruptible(&info->open_wait);
1716} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718/*
1719 * ------------------------------------------------------------
1720 * cy_open() and friends
1721 * ------------------------------------------------------------
1722 */
1723
1724static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001725block_til_ready(struct tty_struct *tty, struct file *filp,
1726 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001728 DECLARE_WAITQUEUE(wait, current);
1729 unsigned long flags;
1730 int channel;
1731 int retval;
1732 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001734 /*
1735 * If the device is in the middle of being closed, then block
1736 * until it's done, and then try again.
1737 */
1738 if (info->flags & ASYNC_CLOSING) {
1739 interruptible_sleep_on(&info->close_wait);
1740 if (info->flags & ASYNC_HUP_NOTIFY) {
1741 return -EAGAIN;
1742 } else {
1743 return -ERESTARTSYS;
1744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001747 /*
1748 * If non-blocking mode is set, then make the check up front
1749 * and then exit.
1750 */
1751 if (filp->f_flags & O_NONBLOCK) {
1752 info->flags |= ASYNC_NORMAL_ACTIVE;
1753 return 0;
1754 }
1755
1756 /*
1757 * Block waiting for the carrier detect and the line to become
1758 * free (i.e., not in use by the callout). While we are in
1759 * this loop, info->count is dropped by one, so that
1760 * cy_close() knows when to free things. We restore it upon
1761 * exit, either normal or abnormal.
1762 */
1763 retval = 0;
1764 add_wait_queue(&info->open_wait, &wait);
1765#ifdef SERIAL_DEBUG_OPEN
1766 printk("block_til_ready before block: %s, count = %d\n",
1767 tty->name, info->count);
1768 /**/
1769#endif
1770 info->count--;
1771#ifdef SERIAL_DEBUG_COUNT
1772 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1773#endif
1774 info->blocked_open++;
1775
1776 channel = info->line;
1777
1778 while (1) {
1779 local_irq_save(flags);
1780 base_addr[CyCAR] = (u_char) channel;
1781 base_addr[CyMSVR1] = CyRTS;
1782/* CP('S');CP('4'); */
1783 base_addr[CyMSVR2] = CyDTR;
1784#ifdef SERIAL_DEBUG_DTR
1785 printk("cyc: %d: raising DTR\n", __LINE__);
1786 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1787 base_addr[CyMSVR2]);
1788#endif
1789 local_irq_restore(flags);
1790 set_current_state(TASK_INTERRUPTIBLE);
1791 if (tty_hung_up_p(filp)
1792 || !(info->flags & ASYNC_INITIALIZED)) {
1793 if (info->flags & ASYNC_HUP_NOTIFY) {
1794 retval = -EAGAIN;
1795 } else {
1796 retval = -ERESTARTSYS;
1797 }
1798 break;
1799 }
1800 local_irq_save(flags);
1801 base_addr[CyCAR] = (u_char) channel;
1802/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1803 if (!(info->flags & ASYNC_CLOSING)
1804 && (C_CLOCAL(tty)
1805 || (base_addr[CyMSVR1] & CyDCD))) {
1806 local_irq_restore(flags);
1807 break;
1808 }
1809 local_irq_restore(flags);
1810 if (signal_pending(current)) {
1811 retval = -ERESTARTSYS;
1812 break;
1813 }
1814#ifdef SERIAL_DEBUG_OPEN
1815 printk("block_til_ready blocking: %s, count = %d\n",
1816 tty->name, info->count);
1817 /**/
1818#endif
1819 schedule();
1820 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001821 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001822 remove_wait_queue(&info->open_wait, &wait);
1823 if (!tty_hung_up_p(filp)) {
1824 info->count++;
1825#ifdef SERIAL_DEBUG_COUNT
1826 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1827 info->count);
1828#endif
1829 }
1830 info->blocked_open--;
1831#ifdef SERIAL_DEBUG_OPEN
1832 printk("block_til_ready after blocking: %s, count = %d\n",
1833 tty->name, info->count);
1834 /**/
1835#endif
1836 if (retval)
1837 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 info->flags |= ASYNC_NORMAL_ACTIVE;
1839 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001840} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
1842/*
1843 * This routine is called whenever a serial port is opened. It
1844 * performs the serial-specific initialization for the tty structure.
1845 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001846int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001848 struct cyclades_port *info;
1849 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001852 line = tty->index;
1853 if ((line < 0) || (NR_PORTS <= line)) {
1854 return -ENODEV;
1855 }
1856 info = &cy_port[line];
1857 if (info->line < 0) {
1858 return -ENODEV;
1859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001861 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001863 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1864 return -ENODEV;
1865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001867 printk("cy_open %s, count = %d\n", tty->name, info->count);
1868 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001870 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001872 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001874 tty->driver_data = info;
1875 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001877 /*
1878 * Start up serial port
1879 */
1880 retval = startup(info);
1881 if (retval) {
1882 return retval;
1883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001885 retval = block_til_ready(tty, filp, info);
1886 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001888 printk("cy_open returning after block_til_ready with %d\n",
1889 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001891 return retval;
1892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001894 printk("cy_open done\n");
1895 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001897 return 0;
1898} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900/*
1901 * ---------------------------------------------------------------------
1902 * serial167_init() and friends
1903 *
1904 * serial167_init() is called at boot-time to initialize the serial driver.
1905 * ---------------------------------------------------------------------
1906 */
1907
1908/*
1909 * This routine prints out the appropriate serial driver version
1910 * number, and identifies which options were configured into this
1911 * driver.
1912 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001913static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001915 printk("MVME166/167 cd2401 driver\n");
1916} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918/* initialize chips on card -- return number of valid
1919 chips (which is number of ports/4) */
1920
1921/*
1922 * This initialises the hardware to a reasonable state. It should
1923 * probe the chip first so as to copy 166-Bug setup as a default for
1924 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1925 * as to limit the number of CyINIT_CHAN commands in normal running.
1926 *
1927 * ... I wonder what I should do if this fails ...
1928 */
1929
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001930void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001932 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 int ch;
1934 u_char spd;
1935 u_char rcor, rbpr, badspeed = 0;
1936 unsigned long flags;
1937
1938 local_irq_save(flags);
1939
1940 /*
1941 * First probe channel zero of the chip, to see what speed has
1942 * been selected.
1943 */
1944
1945 base_addr[CyCAR] = 0;
1946
1947 rcor = base_addr[CyRCOR] << 5;
1948 rbpr = base_addr[CyRBPR];
1949
1950 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1951 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1952 break;
1953 if (spd >= sizeof(baud_bpr)) {
1954 spd = 14; /* 19200 */
1955 badspeed = 1; /* Failed to identify speed */
1956 }
1957 initial_console_speed = spd;
1958
1959 /* OK, we have chosen a speed, now reset and reinitialise */
1960
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001961 my_udelay(20000L); /* Allow time for any active o/p to complete */
1962 if (base_addr[CyCCR] != 0x00) {
1963 local_irq_restore(flags);
1964 /* printk(" chip is never idle (CCR != 0)\n"); */
1965 return;
1966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001968 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1969 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001971 if (base_addr[CyGFRCR] == 0x00) {
1972 local_irq_restore(flags);
1973 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1974 return;
1975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 /*
1978 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1979 * tick
1980 */
1981
1982 base_addr[CyTPR] = 10;
1983
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001984 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1985 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1986 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
1988 /*
1989 * Attempt to set up all channels to something reasonable, and
1990 * bang out a INIT_CHAN command. We should then be able to limit
Uwe Kleine-König9ddc5b62010-01-20 17:02:24 +01001991 * the amount of fiddling we have to do in normal running.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 */
1993
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001994 for (ch = 3; ch >= 0; ch--) {
1995 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 base_addr[CyIER] = 0;
1997 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001998 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 base_addr[CyLIVR] = 0x5c;
2000 base_addr[CyTCOR] = baud_co[spd];
2001 base_addr[CyTBPR] = baud_bpr[spd];
2002 base_addr[CyRCOR] = baud_co[spd] >> 5;
2003 base_addr[CyRBPR] = baud_bpr[spd];
2004 base_addr[CySCHR1] = 'Q' & 0x1f;
2005 base_addr[CySCHR2] = 'X' & 0x1f;
2006 base_addr[CySCRL] = 0;
2007 base_addr[CySCRH] = 0;
2008 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2009 base_addr[CyCOR2] = 0;
2010 base_addr[CyCOR3] = Cy_1_STOP;
2011 base_addr[CyCOR4] = baud_cor4[spd];
2012 base_addr[CyCOR5] = 0;
2013 base_addr[CyCOR6] = 0;
2014 base_addr[CyCOR7] = 0;
2015 base_addr[CyRTPRL] = 2;
2016 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002017 base_addr[CyMSVR1] = 0;
2018 base_addr[CyMSVR2] = 0;
2019 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
2021
2022 /*
2023 * Now do specials for channel zero....
2024 */
2025
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002026 base_addr[CyMSVR1] = CyRTS;
2027 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002029 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031 local_irq_restore(flags);
2032
2033 my_udelay(20000L); /* Let it all settle down */
2034
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002035 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002037 printk
2038 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2039 rcor >> 5, rbpr);
2040} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002042static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 .open = cy_open,
2044 .close = cy_close,
2045 .write = cy_write,
2046 .put_char = cy_put_char,
2047 .flush_chars = cy_flush_chars,
2048 .write_room = cy_write_room,
2049 .chars_in_buffer = cy_chars_in_buffer,
2050 .flush_buffer = cy_flush_buffer,
2051 .ioctl = cy_ioctl,
2052 .throttle = cy_throttle,
2053 .unthrottle = cy_unthrottle,
2054 .set_termios = cy_set_termios,
2055 .stop = cy_stop,
2056 .start = cy_start,
2057 .hangup = cy_hangup,
2058 .tiocmget = cy_tiocmget,
2059 .tiocmset = cy_tiocmset,
2060};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062/* The serial driver boot-time initialization code!
2063 Hardware I/O ports are mapped to character special devices on a
2064 first found, first allocated manner. That is, this code searches
2065 for Cyclom cards in the system. As each is found, it is probed
2066 to discover how many chips (and thus how many ports) are present.
2067 These ports are mapped to the tty ports 64 and upward in monotonic
2068 fashion. If an 8-port card is replaced with a 16-port card, the
2069 port mapping on a following card will shift.
2070
2071 This approach is different from what is used in the other serial
2072 device driver because the Cyclom is more properly a multiplexer,
2073 not just an aggregation of serial ports on one card.
2074
2075 If there are more cards with more ports than have been statically
2076 allocated above, a warning is printed and the extra ports are ignored.
2077 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002078static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002080 struct cyclades_port *info;
2081 int ret = 0;
2082 int good_ports = 0;
2083 int port_num = 0;
2084 int index;
2085 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002087 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088#endif
2089
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002090 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2091 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002093 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2094 if (!cy_serial_driver)
2095 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
2097#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002098 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099#endif
2100
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002101 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002103 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2104 if (serial_console_cflag)
2105 DefSpeed = serial_console_cflag & 0017;
2106 else {
2107 DefSpeed = initial_console_speed;
2108 serial_console_info = &cy_port[0];
2109 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002111 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002114
2115 /* Initialize the tty_driver structure */
2116
2117 cy_serial_driver->owner = THIS_MODULE;
2118 cy_serial_driver->name = "ttyS";
2119 cy_serial_driver->major = TTY_MAJOR;
2120 cy_serial_driver->minor_start = 64;
2121 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2122 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2123 cy_serial_driver->init_termios = tty_std_termios;
2124 cy_serial_driver->init_termios.c_cflag =
2125 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2126 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2127 tty_set_operations(cy_serial_driver, &cy_ops);
2128
2129 ret = tty_register_driver(cy_serial_driver);
2130 if (ret) {
2131 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2132 put_tty_driver(cy_serial_driver);
2133 return ret;
2134 }
2135
2136 port_num = 0;
2137 info = cy_port;
2138 for (index = 0; index < 1; index++) {
2139
2140 good_ports = 4;
2141
2142 if (port_num < NR_PORTS) {
2143 while (good_ports-- && port_num < NR_PORTS) {
2144 /*** initialize port ***/
2145 info->magic = CYCLADES_MAGIC;
2146 info->type = PORT_CIRRUS;
2147 info->card = index;
2148 info->line = port_num;
2149 info->flags = STD_COM_FLAGS;
2150 info->tty = NULL;
2151 info->xmit_fifo_size = 12;
2152 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2153 info->cor2 = CyETC;
2154 info->cor3 = Cy_1_STOP;
2155 info->cor4 = 0x08; /* _very_ small receive threshold */
2156 info->cor5 = 0;
2157 info->cor6 = 0;
2158 info->cor7 = 0;
2159 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2160 info->tco = baud_co[DefSpeed]; /* Tx CO */
2161 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2162 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2163 info->close_delay = 0;
2164 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002165 info->count = 0;
2166#ifdef SERIAL_DEBUG_COUNT
2167 printk("cyc: %d: setting count to 0\n",
2168 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002170 info->blocked_open = 0;
2171 info->default_threshold = 0;
2172 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002173 init_waitqueue_head(&info->open_wait);
2174 init_waitqueue_head(&info->close_wait);
2175 /* info->session */
2176 /* info->pgrp */
2177/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2178 info->read_status_mask =
2179 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2180 CyFRAME | CyOVERRUN;
2181 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002183 printk("ttyS%d ", info->line);
2184 port_num++;
2185 info++;
2186 if (!(port_num & 7)) {
2187 printk("\n ");
2188 }
2189 }
2190 }
2191 printk("\n");
2192 }
2193 while (port_num < NR_PORTS) {
2194 info->line = -1;
2195 port_num++;
2196 info++;
2197 }
2198#ifdef CONFIG_REMOTE_DEBUG
2199 debug_setup();
2200#endif
2201 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2202 "cd2401_errors", cd2401_rxerr_interrupt);
2203 if (ret) {
2204 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2205 goto cleanup_serial_driver;
2206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002208 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2209 "cd2401_modem", cd2401_modem_interrupt);
2210 if (ret) {
2211 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2212 goto cleanup_irq_cd2401_errors;
2213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002215 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2216 "cd2401_txints", cd2401_tx_interrupt);
2217 if (ret) {
2218 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2219 goto cleanup_irq_cd2401_modem;
2220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002222 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2223 "cd2401_rxints", cd2401_rx_interrupt);
2224 if (ret) {
2225 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2226 goto cleanup_irq_cd2401_txints;
2227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002229 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002231 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2232 pcc2chip[PccSCCTICR] = 0x15;
2233 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002235 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2236
2237 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002239 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002241 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002243 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002245 if (tty_unregister_driver(cy_serial_driver))
2246 printk(KERN_ERR
2247 "Couldn't unregister MVME166/7 serial driver\n");
2248 put_tty_driver(cy_serial_driver);
2249 return ret;
2250} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
2252module_init(serial167_init);
2253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002255static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002257 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2258 int channel;
2259 struct cyclades_port *info;
2260 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002262 info = &cy_port[line_num];
2263 channel = info->line;
2264 printk(" channel %d\n", channel);
2265 /**/ printk(" cy_port\n");
2266 printk(" card line flags = %d %d %x\n",
2267 info->card, info->line, info->flags);
2268 printk
2269 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2270 (long)info->tty, info->read_status_mask, info->timeout,
2271 info->xmit_fifo_size);
2272 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2273 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2274 info->cor6, info->cor7);
2275 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2276 info->rbpr, info->rco);
2277 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2278 info->event, info->count);
2279 printk(" x_char blocked_open = %x %x\n", info->x_char,
2280 info->blocked_open);
2281 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002283 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
2285/* Global Registers */
2286
2287 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2288 printk(" CyCAR %x\n", base_addr[CyCAR]);
2289 printk(" CyRISR %x\n", base_addr[CyRISR]);
2290 printk(" CyTISR %x\n", base_addr[CyTISR]);
2291 printk(" CyMISR %x\n", base_addr[CyMISR]);
2292 printk(" CyRIR %x\n", base_addr[CyRIR]);
2293 printk(" CyTIR %x\n", base_addr[CyTIR]);
2294 printk(" CyMIR %x\n", base_addr[CyMIR]);
2295 printk(" CyTPR %x\n", base_addr[CyTPR]);
2296
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002297 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299/* Virtual Registers */
2300
2301#if 0
2302 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2303 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2304 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2305 printk(" CyMISR %x\n", base_addr[CyMISR]);
2306#endif
2307
2308/* Channel Registers */
2309
2310 printk(" CyCCR %x\n", base_addr[CyCCR]);
2311 printk(" CyIER %x\n", base_addr[CyIER]);
2312 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2313 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2314 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2315 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2316 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2317#if 0
2318 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2319 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2320#endif
2321 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2322 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2323#if 0
2324 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2325 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2326 printk(" CySCRL %x\n", base_addr[CySCRL]);
2327 printk(" CySCRH %x\n", base_addr[CySCRH]);
2328 printk(" CyLNC %x\n", base_addr[CyLNC]);
2329 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2330 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2331#endif
2332 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2333 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2334 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2335 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2336 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2337 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2338 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2339 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2340
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002341 local_irq_restore(flags);
2342} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343#endif
2344
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345#if 0
2346/* Dummy routine in mvme16x/config.c for now */
2347
2348/* Serial console setup. Called from linux/init/main.c */
2349
2350void console_setup(char *str, int *ints)
2351{
2352 char *s;
2353 int baud, bits, parity;
2354 int cflag = 0;
2355
2356 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002357 if (ints[0] > 3 || ints[1] > 3)
2358 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
2360 /* Get baud, bits and parity */
2361 baud = 2400;
2362 bits = 8;
2363 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002364 if (ints[2])
2365 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 if ((s = strchr(str, ','))) {
2367 do {
2368 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002369 } while (*s >= '0' && *s <= '9');
2370 if (*s)
2371 parity = *s++;
2372 if (*s)
2373 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 }
2375
2376 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002377 switch (baud) {
2378 case 1200:
2379 cflag |= B1200;
2380 break;
2381 case 9600:
2382 cflag |= B9600;
2383 break;
2384 case 19200:
2385 cflag |= B19200;
2386 break;
2387 case 38400:
2388 cflag |= B38400;
2389 break;
2390 case 2400:
2391 default:
2392 cflag |= B2400;
2393 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002395 switch (bits) {
2396 case 7:
2397 cflag |= CS7;
2398 break;
2399 default:
2400 case 8:
2401 cflag |= CS8;
2402 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002404 switch (parity) {
2405 case 'o':
2406 case 'O':
2407 cflag |= PARODD;
2408 break;
2409 case 'e':
2410 case 'E':
2411 cflag |= PARENB;
2412 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 }
2414
2415 serial_console_info = &cy_port[ints[1]];
2416 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002417 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418}
2419#endif
2420
2421/*
2422 * The following is probably out of date for 2.1.x serial console stuff.
2423 *
2424 * The console is registered early on from arch/m68k/kernel/setup.c, and
2425 * it therefore relies on the chip being setup correctly by 166-Bug. This
2426 * seems reasonable, as the serial port has been used to invoke the system
2427 * boot. It also means that this function must not rely on any data
2428 * initialisation performed by serial167_init() etc.
2429 *
2430 * Of course, once the console has been registered, we had better ensure
2431 * that serial167_init() doesn't leave the chip non-functional.
2432 *
2433 * The console must be locked when we get here.
2434 */
2435
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002436void serial167_console_write(struct console *co, const char *str,
2437 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002439 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 unsigned long flags;
2441 volatile u_char sink;
2442 u_char ier;
2443 int port;
2444 u_char do_lf = 0;
2445 int i = 0;
2446
2447 local_irq_save(flags);
2448
2449 /* Ensure transmitter is enabled! */
2450
2451 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002452 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 while (base_addr[CyCCR])
2454 ;
2455 base_addr[CyCCR] = CyENB_XMTR;
2456
2457 ier = base_addr[CyIER];
2458 base_addr[CyIER] = CyTxMpty;
2459
2460 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002461 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* We have a Tx int. Acknowledge it */
2463 sink = pcc2chip[PccTPIACKR];
2464 if ((base_addr[CyLICR] >> 2) == port) {
2465 if (i == count) {
2466 /* Last char of string is now output */
2467 base_addr[CyTEOIR] = CyNOTRANS;
2468 break;
2469 }
2470 if (do_lf) {
2471 base_addr[CyTDR] = '\n';
2472 str++;
2473 i++;
2474 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002475 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 base_addr[CyTDR] = '\r';
2477 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002478 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 base_addr[CyTDR] = *str++;
2480 i++;
2481 }
2482 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002483 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 base_addr[CyTEOIR] = CyNOTRANS;
2485 }
2486 }
2487
2488 base_addr[CyIER] = ier;
2489
2490 local_irq_restore(flags);
2491}
2492
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002493static struct tty_driver *serial167_console_device(struct console *c,
2494 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495{
2496 *index = c->index;
2497 return cy_serial_driver;
2498}
2499
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002501 .name = "ttyS",
2502 .write = serial167_console_write,
2503 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002504 .flags = CON_PRINTBUFFER,
2505 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506};
2507
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508static int __init serial167_console_init(void)
2509{
2510 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002511 vme_brdtype == VME_TYPE_MVME167 ||
2512 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 mvme167_serial_console_setup(0);
2514 register_console(&sercons);
2515 }
2516 return 0;
2517}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002518
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519console_initcall(serial167_console_init);
2520
2521#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002522void putDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002524 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 unsigned long flags;
2526 volatile u_char sink;
2527 u_char ier;
2528 int port;
2529
2530 local_irq_save(flags);
2531
2532 /* Ensure transmitter is enabled! */
2533
2534 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002535 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 while (base_addr[CyCCR])
2537 ;
2538 base_addr[CyCCR] = CyENB_XMTR;
2539
2540 ier = base_addr[CyIER];
2541 base_addr[CyIER] = CyTxMpty;
2542
2543 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002544 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 /* We have a Tx int. Acknowledge it */
2546 sink = pcc2chip[PccTPIACKR];
2547 if ((base_addr[CyLICR] >> 2) == port) {
2548 base_addr[CyTDR] = c;
2549 base_addr[CyTEOIR] = 0;
2550 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002551 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 base_addr[CyTEOIR] = CyNOTRANS;
2553 }
2554 }
2555
2556 base_addr[CyIER] = ier;
2557
2558 local_irq_restore(flags);
2559}
2560
2561int getDebugChar()
2562{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002563 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 unsigned long flags;
2565 volatile u_char sink;
2566 u_char ier;
2567 int port;
2568 int i, c;
2569
2570 i = debugiq.out;
2571 if (i != debugiq.in) {
2572 c = debugiq.buf[i];
2573 if (++i == DEBUG_LEN)
2574 i = 0;
2575 debugiq.out = i;
2576 return c;
2577 }
2578 /* OK, nothing in queue, wait in poll loop */
2579
2580 local_irq_save(flags);
2581
2582 /* Ensure receiver is enabled! */
2583
2584 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002585 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586#if 0
2587 while (base_addr[CyCCR])
2588 ;
2589 base_addr[CyCCR] = CyENB_RCVR;
2590#endif
2591 ier = base_addr[CyIER];
2592 base_addr[CyIER] = CyRxData;
2593
2594 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002595 if (pcc2chip[PccSCCRICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 /* We have a Rx int. Acknowledge it */
2597 sink = pcc2chip[PccRPIACKR];
2598 if ((base_addr[CyLICR] >> 2) == port) {
2599 int cnt = base_addr[CyRFOC];
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002600 while (cnt-- > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 c = base_addr[CyRDR];
2602 if (c == 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002603 printk
2604 ("!! debug char is null (cnt=%d) !!",
2605 cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 else
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002607 queueDebugChar(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 }
2609 base_addr[CyREOIR] = 0;
2610 i = debugiq.out;
2611 if (i == debugiq.in)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002612 panic("Debug input queue empty!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 c = debugiq.buf[i];
2614 if (++i == DEBUG_LEN)
2615 i = 0;
2616 debugiq.out = i;
2617 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002618 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 base_addr[CyREOIR] = CyNOTRANS;
2620 }
2621 }
2622
2623 base_addr[CyIER] = ier;
2624
2625 local_irq_restore(flags);
2626
2627 return (c);
2628}
2629
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002630void queueDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631{
2632 int i;
2633
2634 i = debugiq.in;
2635 debugiq.buf[i] = c;
2636 if (++i == DEBUG_LEN)
2637 i = 0;
2638 if (i != debugiq.out)
2639 debugiq.in = i;
2640}
2641
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002642static void debug_setup()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002644 unsigned long flags;
2645 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2646 int i, cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002648 cflag = B19200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002650 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002652 for (i = 0; i < 4; i++) {
2653 base_addr[CyCAR] = i;
2654 base_addr[CyLICR] = i << 2;
2655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002657 debugiq.in = debugiq.out = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002659 base_addr[CyCAR] = DEBUG_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002661 /* baud rate */
2662 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002664 base_addr[CyIER] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002666 base_addr[CyCMR] = CyASYNC;
2667 base_addr[CyLICR] = DEBUG_PORT << 2;
2668 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002670 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002672 base_addr[CyTCOR] = baud_co[i];
2673 base_addr[CyTBPR] = baud_bpr[i];
2674 base_addr[CyRCOR] = baud_co[i] >> 5;
2675 base_addr[CyRBPR] = baud_bpr[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002677 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002679 base_addr[CySCHR1] = 0;
2680 base_addr[CySCHR2] = 0;
2681 base_addr[CySCRL] = 0;
2682 base_addr[CySCRH] = 0;
2683 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2684 base_addr[CyCOR2] = 0;
2685 base_addr[CyCOR3] = Cy_1_STOP;
2686 base_addr[CyCOR4] = baud_cor4[i];
2687 base_addr[CyCOR5] = 0;
2688 base_addr[CyCOR6] = 0;
2689 base_addr[CyCOR7] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002691 write_cy_cmd(base_addr, CyINIT_CHAN);
2692 write_cy_cmd(base_addr, CyENB_RCVR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002694 base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002696 base_addr[CyRTPRL] = 2;
2697 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002699 base_addr[CyMSVR1] = CyRTS;
2700 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002702 base_addr[CyIER] = CyRxData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002704 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002706} /* debug_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
2708#endif
2709
2710MODULE_LICENSE("GPL");