blob: fda90643ead7604356e7ee7ce8bba129dde75aae [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>
55#include <linux/string.h>
56#include <linux/fcntl.h>
57#include <linux/ptrace.h>
58#include <linux/serial167.h>
59#include <linux/delay.h>
60#include <linux/major.h>
61#include <linux/mm.h>
62#include <linux/console.h>
63#include <linux/module.h>
64#include <linux/bitops.h>
Geert Uytterhoeven81e859a2006-10-09 22:27:42 +020065#include <linux/tty_flip.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090066#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68#include <asm/system.h>
69#include <asm/io.h>
70#include <asm/mvme16xhw.h>
71#include <asm/bootinfo.h>
72#include <asm/setup.h>
73
74#include <linux/types.h>
75#include <linux/kernel.h>
76
77#include <asm/uaccess.h>
78#include <linux/init.h>
79
80#define SERIAL_PARANOIA_CHECK
81#undef SERIAL_DEBUG_OPEN
82#undef SERIAL_DEBUG_THROTTLE
83#undef SERIAL_DEBUG_OTHER
84#undef SERIAL_DEBUG_IO
85#undef SERIAL_DEBUG_COUNT
86#undef SERIAL_DEBUG_DTR
87#undef CYCLOM_16Y_HACK
88#define CYCLOM_ENABLE_MONITORING
89
90#define WAKEUP_CHARS 256
91
92#define STD_COM_FLAGS (0)
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static struct tty_driver *cy_serial_driver;
95extern int serial_console;
96static struct cyclades_port *serial_console_info = NULL;
97static unsigned int serial_console_cflag = 0;
98u_char initial_console_speed;
99
100/* Base address of cd2401 chip on mvme166/7 */
101
102#define BASE_ADDR (0xfff45000)
103#define pcc2chip ((volatile u_char *)0xfff42000)
104#define PccSCCMICR 0x1d
105#define PccSCCTICR 0x1e
106#define PccSCCRICR 0x1f
107#define PccTPIACKR 0x25
108#define PccRPIACKR 0x27
109#define PccIMLR 0x3f
110
111/* This is the per-port data structure */
112struct cyclades_port cy_port[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800113 /* CARD# */
114 {-1}, /* ttyS0 */
115 {-1}, /* ttyS1 */
116 {-1}, /* ttyS2 */
117 {-1}, /* ttyS3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800119
Tobias Klauserfe971072006-01-09 20:54:02 -0800120#define NR_PORTS ARRAY_SIZE(cy_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 * This is used to look up the divisor speeds and the timeouts
124 * We're normally limited to 15 distinct baud rates. The extra
125 * are accessed via settings in info->flags.
126 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
127 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
128 * HI VHI
129 */
130static int baud_table[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800131 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
132 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
133 0
134};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800137static char baud_co[] = { /* 25 MHz clock option table */
138 /* value => 00 01 02 03 04 */
139 /* divide by 8 32 128 512 2048 */
140 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
141 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
142};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800144static char baud_bpr[] = { /* 25 MHz baud rate period table */
145 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
146 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
147};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148#endif
149
150/* I think 166 brd clocks 2401 at 20MHz.... */
151
152/* These values are written directly to tcor, and >> 5 for writing to rcor */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800153static u_char baud_co[] = { /* 20 MHz clock option table */
154 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40,
155 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
156};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158/* These values written directly to tbpr/rbpr */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800159static u_char baud_bpr[] = { /* 20 MHz baud rate period table */
160 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81,
161 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10
162};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800164static u_char baud_cor4[] = { /* receive threshold */
165 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
166 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07
167};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169static void shutdown(struct cyclades_port *);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800170static int startup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void cy_throttle(struct tty_struct *);
172static void cy_unthrottle(struct tty_struct *);
173static void config_setup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#ifdef CYCLOM_SHOW_STATUS
175static void show_status(int);
176#endif
177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178/*
179 * I have my own version of udelay(), as it is needed when initialising
180 * the chip, before the delay loop has been calibrated. Should probably
181 * reference one of the vmechip2 or pccchip2 counter for an accurate
182 * delay, but this wild guess will do for now.
183 */
184
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800185void my_udelay(long us)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
187 u_char x;
188 volatile u_char *p = &x;
189 int i;
190
191 while (us--)
192 for (i = 100; i; i--)
193 x |= *p;
194}
195
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800196static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
197 const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
199#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800200 if (!info) {
201 printk("Warning: null cyclades_port for (%s) in %s\n", name,
202 routine);
203 return 1;
204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Roel Kluinf23fc152009-10-01 15:44:25 -0700206 if (info < &cy_port[0] || info >= &cy_port[NR_PORTS]) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800207 printk("Warning: cyclades_port out of range for (%s) in %s\n",
208 name, routine);
209 return 1;
210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800212 if (info->magic != CYCLADES_MAGIC) {
213 printk("Warning: bad magic number for serial struct (%s) in "
214 "%s\n", name, routine);
215 return 1;
216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217#endif
218 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800219} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221#if 0
222/* The following diagnostic routines allow the driver to spew
223 information on the screen, even (especially!) during interrupts.
224 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800225void SP(char *data)
226{
227 unsigned long flags;
228 local_irq_save(flags);
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700229 printk(KERN_EMERG "%s", data);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800230 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800233char scrn[2];
234void CP(char data)
235{
236 unsigned long flags;
237 local_irq_save(flags);
238 scrn[0] = data;
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700239 printk(KERN_EMERG "%c", scrn);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800240 local_irq_restore(flags);
241} /* CP */
242
243void CP1(int data)
244{
245 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
246} /* CP1 */
247void CP2(int data)
248{
249 CP1((data >> 4) & 0x0f);
250 CP1(data & 0x0f);
251} /* CP2 */
252void CP4(int data)
253{
254 CP2((data >> 8) & 0xff);
255 CP2(data & 0xff);
256} /* CP4 */
257void CP8(long data)
258{
259 CP4((data >> 16) & 0xffff);
260 CP4(data & 0xffff);
261} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262#endif
263
264/* This routine waits up to 1000 micro-seconds for the previous
265 command to the Cirrus chip to complete and then issues the
266 new command. An error is returned if the previous command
267 didn't finish within the time limit.
268 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800269u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800271 unsigned long flags;
272 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800274 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800276 for (i = 0; i < 100; i++) {
277 if (base_addr[CyCCR] == 0) {
278 break;
279 }
280 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800283 didn't finish within the "reasonable time" */
284 if (i == 10) {
285 local_irq_restore(flags);
286 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
288
289 /* Issue the new command */
290 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800291 local_irq_restore(flags);
292 return (0);
293} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295/* cy_start and cy_stop provide software output flow control as a
296 function of XON/XOFF, software CTS, and other such stuff. */
297
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800298static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
Alan Coxc9f19e92009-01-02 13:47:26 +0000300 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800301 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
302 int channel;
303 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800306 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307#endif
308
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800309 if (serial_paranoia_check(info, tty->name, "cy_stop"))
310 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800312 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800314 local_irq_save(flags);
315 base_addr[CyCAR] = (u_char) (channel); /* index channel */
316 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
317 local_irq_restore(flags);
318} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800320static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Alan Coxc9f19e92009-01-02 13:47:26 +0000322 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800323 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
324 int channel;
325 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800328 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#endif
330
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800331 if (serial_paranoia_check(info, tty->name, "cy_start"))
332 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800334 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800336 local_irq_save(flags);
337 base_addr[CyCAR] = (u_char) (channel);
338 base_addr[CyIER] |= CyTxMpty;
339 local_irq_restore(flags);
340} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342/* The real interrupt service routines are called
343 whenever the card wants its hand held--chars
344 received, out buffer empty, modem change, etc.
345 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800346static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800348 struct tty_struct *tty;
349 struct cyclades_port *info;
350 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
351 unsigned char err, rfoc;
352 int channel;
353 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800355 /* determine the channel and change to that context */
356 channel = (u_short) (base_addr[CyLICR] >> 2);
357 info = &cy_port[channel];
358 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800360 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
361 /* This is a receive timeout interrupt, ignore it */
362 base_addr[CyREOIR] = CyNOTRANS;
363 return IRQ_HANDLED;
364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800366 /* Read a byte of data if there is any - assume the error
367 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800369 if ((rfoc = base_addr[CyRFOC]) != 0)
370 data = base_addr[CyRDR];
371 else
372 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800374 /* if there is nowhere to put the data, discard it */
375 if (info->tty == 0) {
376 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
377 return IRQ_HANDLED;
378 } else { /* there is an open port for this data */
379 tty = info->tty;
380 if (err & info->ignore_status_mask) {
381 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
382 return IRQ_HANDLED;
383 }
384 if (tty_buffer_request_room(tty, 1) != 0) {
385 if (err & info->read_status_mask) {
386 if (err & CyBREAK) {
387 tty_insert_flip_char(tty, data,
388 TTY_BREAK);
389 if (info->flags & ASYNC_SAK) {
390 do_SAK(tty);
391 }
392 } else if (err & CyFRAME) {
393 tty_insert_flip_char(tty, data,
394 TTY_FRAME);
395 } else if (err & CyPARITY) {
396 tty_insert_flip_char(tty, data,
397 TTY_PARITY);
398 } else if (err & CyOVERRUN) {
399 tty_insert_flip_char(tty, 0,
400 TTY_OVERRUN);
401 /*
402 If the flip buffer itself is
Nick Andrewc4f01242008-12-05 16:34:46 +0000403 overflowing, we still lose
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800404 the next incoming character.
405 */
406 if (tty_buffer_request_room(tty, 1) !=
407 0) {
408 tty_insert_flip_char(tty, data,
409 TTY_FRAME);
410 }
411 /* These two conditions may imply */
412 /* a normal read should be done. */
413 /* else if(data & CyTIMEOUT) */
414 /* else if(data & CySPECHAR) */
415 } else {
416 tty_insert_flip_char(tty, 0,
417 TTY_NORMAL);
418 }
419 } else {
420 tty_insert_flip_char(tty, data, TTY_NORMAL);
421 }
422 } else {
423 /* there was a software buffer overrun
424 and nothing could be done about it!!! */
425 }
426 }
427 tty_schedule_flip(tty);
428 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
430 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800431} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800433static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800435 struct cyclades_port *info;
436 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
437 int channel;
438 int mdm_change;
439 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800441 /* determine the channel and change to that context */
442 channel = (u_short) (base_addr[CyLICR] >> 2);
443 info = &cy_port[channel];
444 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800446 mdm_change = base_addr[CyMISR];
447 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800449 if (info->tty == 0) { /* nowhere to put the data, ignore it */
450 ;
451 } else {
452 if ((mdm_change & CyDCD)
453 && (info->flags & ASYNC_CHECK_CD)) {
454 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455/* CP('!'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800456 wake_up_interruptible(&info->open_wait);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800457 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458/* CP('@'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800459 tty_hangup(info->tty);
460 wake_up_interruptible(&info->open_wait);
461 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800464 if ((mdm_change & CyCTS)
465 && (info->flags & ASYNC_CTS_FLOW)) {
466 if (info->tty->stopped) {
467 if (mdm_status & CyCTS) {
468 /* !!! cy_start isn't used because... */
469 info->tty->stopped = 0;
470 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800471 tty_wakeup(info->tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800472 }
473 } else {
474 if (!(mdm_status & CyCTS)) {
475 /* !!! cy_stop isn't used because... */
476 info->tty->stopped = 1;
477 base_addr[CyIER] &=
478 ~(CyTxMpty | CyTxRdy);
479 }
480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800482 if (mdm_status & CyDSR) {
483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800485 base_addr[CyMEOIR] = 0;
486 return IRQ_HANDLED;
487} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800489static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800491 struct cyclades_port *info;
492 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
493 int channel;
494 int char_count, saved_cnt;
495 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800497 /* determine the channel and change to that context */
498 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800500 /* validate the port number (as configured and open) */
501 if ((channel < 0) || (NR_PORTS <= channel)) {
502 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
503 base_addr[CyTEOIR] = CyNOTRANS;
504 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
Roel Kluinf23fc152009-10-01 15:44:25 -0700506 info = &cy_port[channel];
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800507 info->last_active = jiffies;
508 if (info->tty == 0) {
509 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800510 base_addr[CyTEOIR] = CyNOTRANS;
511 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800513
514 /* load the on-chip space available for outbound data */
515 saved_cnt = char_count = base_addr[CyTFTC];
516
517 if (info->x_char) { /* send special char */
518 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800521 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800524 if (info->x_break) {
525 /* The Cirrus chip requires the "Embedded Transmit
526 Commands" of start break, delay, and end break
527 sequences to be sent. The duration of the
528 break is given in TICs, which runs at HZ
529 (typically 100) and the PPR runs at 200 Hz,
530 so the delay is duration * 200/HZ, and thus a
531 break can run from 1/100 sec to about 5/4 sec.
532 Need to check these values - RGH 141095.
533 */
534 base_addr[CyTDR] = 0; /* start break */
535 base_addr[CyTDR] = 0x81;
536 base_addr[CyTDR] = 0; /* delay a bit */
537 base_addr[CyTDR] = 0x82;
538 base_addr[CyTDR] = info->x_break * 200 / HZ;
539 base_addr[CyTDR] = 0; /* terminate break */
540 base_addr[CyTDR] = 0x83;
541 char_count -= 7;
542 info->x_break = 0;
543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800545 while (char_count > 0) {
546 if (!info->xmit_cnt) {
547 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
548 break;
549 }
550 if (info->xmit_buf == 0) {
551 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
552 break;
553 }
554 if (info->tty->stopped || info->tty->hw_stopped) {
555 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
556 break;
557 }
558 /* Because the Embedded Transmit Commands have been
559 enabled, we must check to see if the escape
560 character, NULL, is being sent. If it is, we
561 must ensure that there is room for it to be
562 doubled in the output stream. Therefore we
563 no longer advance the pointer when the character
564 is fetched, but rather wait until after the check
565 for a NULL output character. (This is necessary
566 because there may not be room for the two chars
567 needed to send a NULL.
568 */
569 outch = info->xmit_buf[info->xmit_tail];
570 if (outch) {
571 info->xmit_cnt--;
572 info->xmit_tail = (info->xmit_tail + 1)
573 & (PAGE_SIZE - 1);
574 base_addr[CyTDR] = outch;
575 char_count--;
576 } else {
577 if (char_count > 1) {
578 info->xmit_cnt--;
579 info->xmit_tail = (info->xmit_tail + 1)
580 & (PAGE_SIZE - 1);
581 base_addr[CyTDR] = outch;
582 base_addr[CyTDR] = 0;
583 char_count--;
584 char_count--;
585 } else {
586 break;
587 }
588 }
589 }
590
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800591 if (info->xmit_cnt < WAKEUP_CHARS)
592 tty_wakeup(info->tty);
593
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800594 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
595 return IRQ_HANDLED;
596} /* cy_tx_interrupt */
597
598static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800600 struct tty_struct *tty;
601 struct cyclades_port *info;
602 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
603 int channel;
604 char data;
605 int char_count;
606 int save_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800608 /* determine the channel and change to that context */
609 channel = (u_short) (base_addr[CyLICR] >> 2);
610 info = &cy_port[channel];
611 info->last_active = jiffies;
612 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800614 /* if there is nowhere to put the data, discard it */
615 if (info->tty == 0) {
616 while (char_count--) {
617 data = base_addr[CyRDR];
618 }
619 } else { /* there is an open port for this data */
620 tty = info->tty;
621 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800624 ++info->mon.int_count;
625 info->mon.char_count += char_count;
626 if (char_count > info->mon.char_max)
627 info->mon.char_max = char_count;
628 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629#endif
Alan Cox4165fe42010-02-17 13:07:13 +0000630 while (char_count--) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800631 data = base_addr[CyRDR];
632 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800634 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800636 }
637 tty_schedule_flip(tty);
638 }
639 /* end of service */
640 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
641 return IRQ_HANDLED;
642} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644/* This is called whenever a port becomes active;
645 interrupts are enabled and DTR & RTS are turned on.
646 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800647static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800649 unsigned long flags;
650 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
651 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800653 if (info->flags & ASYNC_INITIALIZED) {
654 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800656
657 if (!info->type) {
658 if (info->tty) {
659 set_bit(TTY_IO_ERROR, &info->tty->flags);
660 }
661 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800663 if (!info->xmit_buf) {
664 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
665 if (!info->xmit_buf) {
666 return -ENOMEM;
667 }
668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800670 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800672 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800675 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676#endif
677
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800678 local_irq_save(flags);
679 base_addr[CyCAR] = (u_char) channel;
680 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800682 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 base_addr[CyMSVR1] = CyRTS;
684/* CP('S');CP('1'); */
685 base_addr[CyMSVR2] = CyDTR;
686
687#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800688 printk("cyc: %d: raising DTR\n", __LINE__);
689 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
690 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691#endif
692
693 base_addr[CyIER] |= CyRxData;
694 info->flags |= ASYNC_INITIALIZED;
695
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800696 if (info->tty) {
697 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 }
699 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
700
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800701 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800704 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800706 return 0;
707} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800709void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800711 unsigned long flags;
712 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
713 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800715 channel = info->line;
716 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 base_addr[CyCAR] = channel;
718 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800719 local_irq_restore(flags);
720} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722/*
723 * This routine shuts down a serial port; interrupts are disabled,
724 * and DTR is dropped if the hangup on close termio flag is on.
725 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800726static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800728 unsigned long flags;
729 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
730 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800732 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800734 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 }
736
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800737 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800739#ifdef SERIAL_DEBUG_OPEN
740 printk("shutdown channel %d\n", channel);
741#endif
742
743 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
744 SENT BEFORE DROPPING THE LINE !!! (Perhaps
745 set some flag that is read when XMTY happens.)
746 Other choices are to delay some fixed interval
747 or schedule some later processing.
748 */
749 local_irq_save(flags);
750 if (info->xmit_buf) {
751 free_page((unsigned long)info->xmit_buf);
752 info->xmit_buf = NULL;
753 }
754
755 base_addr[CyCAR] = (u_char) channel;
756 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
757 base_addr[CyMSVR1] = 0;
758/* CP('C');CP('1'); */
759 base_addr[CyMSVR2] = 0;
760#ifdef SERIAL_DEBUG_DTR
761 printk("cyc: %d: dropping DTR\n", __LINE__);
762 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
763 base_addr[CyMSVR2]);
764#endif
765 }
766 write_cy_cmd(base_addr, CyDIS_RCVR);
767 /* it may be appropriate to clear _XMIT at
768 some later date (after testing)!!! */
769
770 if (info->tty) {
771 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
773 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800774 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800777 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800779} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781/*
782 * This routine finds or computes the various line characteristics.
783 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800784static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800786 unsigned long flags;
787 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
788 int channel;
789 unsigned cflag;
790 int i;
791 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800793 if (!info->tty || !info->tty->termios) {
794 return;
795 }
796 if (info->line == -1) {
797 return;
798 }
799 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800801 /* baud rate */
802 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803#ifdef CBAUDEX
804/* Starting with kernel 1.1.65, there is direct support for
805 higher baud rates. The following code supports those
806 changes. The conditional aspect allows this driver to be
807 used for earlier as well as later kernel versions. (The
808 mapping is slightly different from serial.c because there
809 is still the possibility of supporting 75 kbit/sec with
810 the Cyclades board.)
811 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800812 if (i & CBAUDEX) {
813 if (i == B57600)
814 i = 16;
815 else if (i == B115200)
816 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800818 else if (i == B78600)
819 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800821 else
822 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800825 if (i == 15) {
826 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
827 i += 1;
828 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
829 i += 3;
830 }
831 /* Don't ever change the speed of the console port. It will
832 * run at the speed specified in bootinfo, or at 19.2K */
833 /* Actually, it should run at whatever speed 166Bug was using */
834 /* Note info->timeout isn't used at present */
835 if (info != serial_console_info) {
836 info->tbpr = baud_bpr[i]; /* Tx BPR */
837 info->tco = baud_co[i]; /* Tx CO */
838 info->rbpr = baud_bpr[i]; /* Rx BPR */
839 info->rco = baud_co[i] >> 5; /* Rx CO */
840 if (baud_table[i] == 134) {
841 info->timeout =
842 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
843 /* get it right for 134.5 baud */
844 } else if (baud_table[i]) {
845 info->timeout =
846 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
847 2;
848 /* this needs to be propagated into the card info */
849 } else {
850 info->timeout = 0;
851 }
852 }
853 /* By tradition (is it a standard?) a baud rate of zero
854 implies the line should be/has been closed. A bit
855 later in this routine such a test is performed. */
856
857 /* byte size and parity */
858 info->cor7 = 0;
859 info->cor6 = 0;
860 info->cor5 = 0;
861 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
862 /* Following two lines added 101295, RGH. */
863 /* It is obviously wrong to access CyCORx, and not info->corx here,
864 * try and remember to fix it later! */
865 channel = info->line;
866 base_addr[CyCAR] = (u_char) channel;
867 if (C_CLOCAL(info->tty)) {
868 if (base_addr[CyIER] & CyMdmCh)
869 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
870 /* ignore 1->0 modem transitions */
871 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
872 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
873 /* ignore 0->1 modem transitions */
874 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
875 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
876 } else {
877 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
878 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
879 /* act on 1->0 modem transitions */
880 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
881 (CyDSR | CyCTS | CyDCD))
882 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
883 /* act on 0->1 modem transitions */
884 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
885 (CyDSR | CyCTS | CyDCD))
886 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
887 }
888 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
889 info->cor2 = CyETC;
890 switch (cflag & CSIZE) {
891 case CS5:
892 info->cor1 = Cy_5_BITS;
893 break;
894 case CS6:
895 info->cor1 = Cy_6_BITS;
896 break;
897 case CS7:
898 info->cor1 = Cy_7_BITS;
899 break;
900 case CS8:
901 info->cor1 = Cy_8_BITS;
902 break;
903 }
904 if (cflag & PARENB) {
905 if (cflag & PARODD) {
906 info->cor1 |= CyPARITY_O;
907 } else {
908 info->cor1 |= CyPARITY_E;
909 }
910 } else {
911 info->cor1 |= CyPARITY_NONE;
912 }
913
914 /* CTS flow control flag */
915#if 0
916 /* Don't complcate matters for now! RGH 141095 */
917 if (cflag & CRTSCTS) {
918 info->flags |= ASYNC_CTS_FLOW;
919 info->cor2 |= CyCtsAE;
920 } else {
921 info->flags &= ~ASYNC_CTS_FLOW;
922 info->cor2 &= ~CyCtsAE;
923 }
924#endif
925 if (cflag & CLOCAL)
926 info->flags &= ~ASYNC_CHECK_CD;
927 else
928 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930 /***********************************************
931 The hardware option, CyRtsAO, presents RTS when
932 the chip has characters to send. Since most modems
933 use RTS as reverse (inbound) flow control, this
934 option is not used. If inbound flow control is
935 necessary, DTR can be programmed to provide the
936 appropriate signals for use with a non-standard
937 cable. Contact Marcio Saito for details.
938 ***********************************************/
939
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800940 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800942 local_irq_save(flags);
943 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 /* CyCMR set once only in mvme167_init_serial() */
946 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800947 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800949 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800951 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800954 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800956 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800958 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800960 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800962 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
964 /* set line characteristics according configuration */
965
966 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800967 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800969 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800971 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800973 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800975 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800977 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800979 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800981 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800983 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800985 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800987 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800990 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800992 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994 /* 2ms default rx timeout */
995 ti = info->default_timeout ? info->default_timeout : 0x02;
996 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800997 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800999 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001002 if (i == 0) { /* baud rate is zero, turn off line */
1003 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1004 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001006 printk("cyc: %d: dropping DTR\n", __LINE__);
1007 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1008 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001010 } else {
1011 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1012 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001014 printk("cyc: %d: raising DTR\n", __LINE__);
1015 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1016 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017#endif
1018 }
1019
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001020 if (info->tty) {
1021 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001024 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001026} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Alan Coxa5b08c62008-04-30 00:54:05 -07001028static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Alan Coxc9f19e92009-01-02 13:47:26 +00001030 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001031 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001034 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035#endif
1036
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001037 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001038 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001040 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001041 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001043 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001045 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001046 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048
1049 info->xmit_buf[info->xmit_head++] = ch;
1050 info->xmit_head &= PAGE_SIZE - 1;
1051 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001052 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001053 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001054} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001056static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057{
Alan Coxc9f19e92009-01-02 13:47:26 +00001058 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001059 unsigned long flags;
1060 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1061 int channel;
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001064 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065#endif
1066
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001067 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1068 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001070 if (info->xmit_cnt <= 0 || tty->stopped
1071 || tty->hw_stopped || !info->xmit_buf)
1072 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001074 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001076 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 base_addr[CyCAR] = channel;
1078 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001079 local_irq_restore(flags);
1080} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082/* This routine gets called when tty_write has put something into
1083 the write_queue. If the port is not already transmitting stuff,
1084 start it off by enabling interrupts. The interrupt service
1085 routine will then ensure that the characters are sent. If the
1086 port is already active, there is no need to kick it.
1087 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001088static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
Alan Coxc9f19e92009-01-02 13:47:26 +00001090 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001091 unsigned long flags;
1092 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001095 printk("cy_write %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_write")) {
1099 return 0;
1100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001102 if (!info->xmit_buf) {
1103 return 0;
1104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001106 while (1) {
1107 local_irq_save(flags);
1108 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1109 SERIAL_XMIT_SIZE - info->xmit_head));
1110 if (c <= 0) {
1111 local_irq_restore(flags);
1112 break;
1113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001115 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1116 info->xmit_head =
1117 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1118 info->xmit_cnt += c;
1119 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001121 buf += c;
1122 count -= c;
1123 total += c;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001126 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1127 start_xmit(info);
1128 }
1129 return total;
1130} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001132static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
Alan Coxc9f19e92009-01-02 13:47:26 +00001134 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001135 int ret;
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001138 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139#endif
1140
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001141 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1142 return 0;
1143 ret = PAGE_SIZE - info->xmit_cnt - 1;
1144 if (ret < 0)
1145 ret = 0;
1146 return ret;
1147} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001149static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
Alan Coxc9f19e92009-01-02 13:47:26 +00001151 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001154 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155#endif
1156
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001157 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1158 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001160 return info->xmit_cnt;
1161} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001163static void cy_flush_buffer(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 unsigned long flags;
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001169 printk("cy_flush_buffer %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_flush_buffer"))
1173 return;
1174 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001176 local_irq_restore(flags);
1177 tty_wakeup(tty);
1178} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180/* This routine is called by the upper-layer tty layer to signal
1181 that incoming characters should be throttled or that the
1182 throttle should be released.
1183 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001184static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185{
Alan Coxc9f19e92009-01-02 13:47:26 +00001186 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001187 unsigned long flags;
1188 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1189 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
1191#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001192 char buf[64];
1193
1194 printk("throttle %s: %d....\n", tty_name(tty, buf),
1195 tty->ldisc.chars_in_buffer(tty));
1196 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197#endif
1198
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001199 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1200 return;
1201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001203 if (I_IXOFF(tty)) {
1204 info->x_char = STOP_CHAR(tty);
1205 /* Should use the "Send Special Character" feature!!! */
1206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001208 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001210 local_irq_save(flags);
1211 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001213 local_irq_restore(flags);
1214} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001216static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
Alan Coxc9f19e92009-01-02 13:47:26 +00001218 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001219 unsigned long flags;
1220 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1221 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001224 char buf[64];
1225
1226 printk("throttle %s: %d....\n", tty_name(tty, buf),
1227 tty->ldisc.chars_in_buffer(tty));
1228 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229#endif
1230
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001231 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1232 return;
1233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001235 if (I_IXOFF(tty)) {
1236 info->x_char = START_CHAR(tty);
1237 /* Should use the "Send Special Character" feature!!! */
1238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001240 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001242 local_irq_save(flags);
1243 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001245 local_irq_restore(flags);
1246} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001249get_serial_info(struct cyclades_port *info,
1250 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001252 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001255 if (!retinfo)
1256 return -EFAULT;
1257 memset(&tmp, 0, sizeof(tmp));
1258 tmp.type = info->type;
1259 tmp.line = info->line;
1260 tmp.port = info->line;
1261 tmp.irq = 0;
1262 tmp.flags = info->flags;
1263 tmp.baud_base = 0; /*!!! */
1264 tmp.close_delay = info->close_delay;
1265 tmp.custom_divisor = 0; /*!!! */
1266 tmp.hub6 = 0; /*!!! */
1267 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1268} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001271set_serial_info(struct cyclades_port *info,
1272 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001274 struct serial_struct new_serial;
1275 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001278 if (!new_info)
1279 return -EFAULT;
1280 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1281 return -EFAULT;
1282 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001284 if (!capable(CAP_SYS_ADMIN)) {
1285 if ((new_serial.close_delay != info->close_delay) ||
1286 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1287 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1288 return -EPERM;
1289 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1290 (new_serial.flags & ASYNC_USR_MASK));
1291 goto check_and_exit;
1292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001294 /*
1295 * OK, past this point, all the error checking has been done.
1296 * At this point, we start making changes.....
1297 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001299 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1300 (new_serial.flags & ASYNC_FLAGS));
1301 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001304 if (info->flags & ASYNC_INITIALIZED) {
1305 config_setup(info);
1306 return 0;
1307 }
1308 return startup(info);
1309} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Alan Cox60b33c12011-02-14 16:26:14 +00001311static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
Alan Coxc9f19e92009-01-02 13:47:26 +00001313 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001314 int channel;
1315 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1316 unsigned long flags;
1317 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001319 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001321 local_irq_save(flags);
1322 base_addr[CyCAR] = (u_char) channel;
1323 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1324 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001326 return ((status & CyRTS) ? TIOCM_RTS : 0)
1327 | ((status & CyDTR) ? TIOCM_DTR : 0)
1328 | ((status & CyDCD) ? TIOCM_CAR : 0)
1329 | ((status & CyDSR) ? TIOCM_DSR : 0)
1330 | ((status & CyCTS) ? TIOCM_CTS : 0);
1331} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
1333static int
1334cy_tiocmset(struct tty_struct *tty, struct file *file,
1335 unsigned int set, unsigned int clear)
1336{
Alan Coxc9f19e92009-01-02 13:47:26 +00001337 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001338 int channel;
1339 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1340 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001342 channel = info->line;
1343
1344 if (set & TIOCM_RTS) {
1345 local_irq_save(flags);
1346 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001348 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001350 if (set & TIOCM_DTR) {
1351 local_irq_save(flags);
1352 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001354 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001356 printk("cyc: %d: raising DTR\n", __LINE__);
1357 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1358 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001360 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 }
1362
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001363 if (clear & TIOCM_RTS) {
1364 local_irq_save(flags);
1365 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001367 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001369 if (clear & TIOCM_DTR) {
1370 local_irq_save(flags);
1371 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001373 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001375 printk("cyc: %d: dropping DTR\n", __LINE__);
1376 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1377 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001379 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
1381
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001382 return 0;
1383} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001385static void send_break(struct cyclades_port *info, int duration)
1386{ /* Let the transmit ISR take care of this (since it
1387 requires stuffing characters into the output stream).
1388 */
1389 info->x_break = duration;
1390 if (!info->xmit_cnt) {
1391 start_xmit(info);
1392 }
1393} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001396get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
1398
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001399 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1400 return -EFAULT;
1401 info->mon.int_count = 0;
1402 info->mon.char_count = 0;
1403 info->mon.char_max = 0;
1404 info->mon.char_last = 0;
1405 return 0;
1406}
1407
1408static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1409{
1410 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1411 unsigned long value;
1412 int channel;
1413
1414 if (get_user(value, arg))
1415 return -EFAULT;
1416
1417 channel = info->line;
1418 info->cor4 &= ~CyREC_FIFO;
1419 info->cor4 |= value & CyREC_FIFO;
1420 base_addr[CyCOR4] = info->cor4;
1421 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422}
1423
1424static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001425get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001427 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1428 int channel;
1429 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001431 channel = info->line;
1432
1433 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1434 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435}
1436
1437static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001438set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001440 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001442 if (get_user(value, arg))
1443 return -EFAULT;
1444
1445 info->default_threshold = value & 0x0f;
1446 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447}
1448
1449static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001450get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001452 return put_user(info->default_threshold, value);
1453}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001455static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1456{
1457 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1458 int channel;
1459 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001461 if (get_user(value, arg))
1462 return -EFAULT;
1463
1464 channel = info->line;
1465
1466 base_addr[CyRTPRL] = value & 0xff;
1467 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1468 return 0;
1469}
1470
1471static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1472{
1473 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1474 int channel;
1475 unsigned long tmp;
1476
1477 channel = info->line;
1478
1479 tmp = base_addr[CyRTPRL];
1480 return put_user(tmp, value);
1481}
1482
1483static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1484{
1485 info->default_timeout = value & 0xff;
1486 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487}
1488
1489static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001490get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001492 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493}
1494
1495static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001496cy_ioctl(struct tty_struct *tty, struct file *file,
1497 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498{
Alan Coxc9f19e92009-01-02 13:47:26 +00001499 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001500 int ret_val = 0;
1501 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001504 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505#endif
1506
Arnd Bergmannec79d602010-06-01 22:53:01 +02001507 tty_lock();
Alan Cox638157b2008-04-30 00:53:22 -07001508
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001509 switch (cmd) {
1510 case CYGETMON:
1511 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001513 case CYGETTHRESH:
1514 ret_val = get_threshold(info, argp);
1515 break;
1516 case CYSETTHRESH:
1517 ret_val = set_threshold(info, argp);
1518 break;
1519 case CYGETDEFTHRESH:
1520 ret_val = get_default_threshold(info, argp);
1521 break;
1522 case CYSETDEFTHRESH:
1523 ret_val = set_default_threshold(info, argp);
1524 break;
1525 case CYGETTIMEOUT:
1526 ret_val = get_timeout(info, argp);
1527 break;
1528 case CYSETTIMEOUT:
1529 ret_val = set_timeout(info, argp);
1530 break;
1531 case CYGETDEFTIMEOUT:
1532 ret_val = get_default_timeout(info, argp);
1533 break;
1534 case CYSETDEFTIMEOUT:
1535 ret_val = set_default_timeout(info, (unsigned long)arg);
1536 break;
1537 case TCSBRK: /* SVID version: non-zero arg --> no break */
1538 ret_val = tty_check_change(tty);
1539 if (ret_val)
1540 break;
1541 tty_wait_until_sent(tty, 0);
1542 if (!arg)
1543 send_break(info, HZ / 4); /* 1/4 second */
1544 break;
1545 case TCSBRKP: /* support for POSIX tcsendbreak() */
1546 ret_val = tty_check_change(tty);
1547 if (ret_val)
1548 break;
1549 tty_wait_until_sent(tty, 0);
1550 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1551 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001554 case TIOCGSERIAL:
1555 ret_val = get_serial_info(info, argp);
1556 break;
1557 case TIOCSSERIAL:
1558 ret_val = set_serial_info(info, argp);
1559 break;
1560 default:
1561 ret_val = -ENOIOCTLCMD;
1562 }
Arnd Bergmannec79d602010-06-01 22:53:01 +02001563 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
1565#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001566 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567#endif
1568
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001569 return ret_val;
1570} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001572static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573{
Alan Coxc9f19e92009-01-02 13:47:26 +00001574 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001577 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578#endif
1579
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001580 if (tty->termios->c_cflag == old_termios->c_cflag)
1581 return;
1582 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001584 if ((old_termios->c_cflag & CRTSCTS) &&
1585 !(tty->termios->c_cflag & CRTSCTS)) {
1586 tty->stopped = 0;
1587 cy_start(tty);
1588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001590 if (!(old_termios->c_cflag & CLOCAL) &&
1591 (tty->termios->c_cflag & CLOCAL))
1592 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001594} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001596static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
Alan Coxc9f19e92009-01-02 13:47:26 +00001598 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
1600/* CP('C'); */
1601#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001602 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603#endif
1604
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001605 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1606 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001608#ifdef SERIAL_DEBUG_OPEN
1609 printk("cy_close %s, count = %d\n", tty->name, info->count);
1610#endif
1611
1612 if ((tty->count == 1) && (info->count != 1)) {
1613 /*
1614 * Uh, oh. tty->count is 1, which means that the tty
1615 * structure will be freed. Info->count should always
1616 * be one in these conditions. If it's greater than
1617 * one, we've got real problems, since it means the
1618 * serial port won't be shutdown.
1619 */
1620 printk("cy_close: bad serial port count; tty->count is 1, "
1621 "info->count is %d\n", info->count);
1622 info->count = 1;
1623 }
1624#ifdef SERIAL_DEBUG_COUNT
1625 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1626 info->count - 1);
1627#endif
1628 if (--info->count < 0) {
1629 printk("cy_close: bad serial port count for ttys%d: %d\n",
1630 info->line, info->count);
1631#ifdef SERIAL_DEBUG_COUNT
1632 printk("cyc: %d: setting count to 0\n", __LINE__);
1633#endif
1634 info->count = 0;
1635 }
1636 if (info->count)
1637 return;
1638 info->flags |= ASYNC_CLOSING;
1639 if (info->flags & ASYNC_INITIALIZED)
1640 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1641 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001642 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001643 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001644 info->tty = NULL;
1645 if (info->blocked_open) {
1646 if (info->close_delay) {
1647 msleep_interruptible(jiffies_to_msecs
1648 (info->close_delay));
1649 }
1650 wake_up_interruptible(&info->open_wait);
1651 }
1652 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1653 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001656 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001658} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660/*
1661 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1662 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001663void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664{
Alan Coxc9f19e92009-01-02 13:47:26 +00001665 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001666
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001668 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669#endif
1670
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001671 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1672 return;
1673
1674 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001676 info->event = 0;
1677 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001679 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001681 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001683 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1684 wake_up_interruptible(&info->open_wait);
1685} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687/*
1688 * ------------------------------------------------------------
1689 * cy_open() and friends
1690 * ------------------------------------------------------------
1691 */
1692
1693static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001694block_til_ready(struct tty_struct *tty, struct file *filp,
1695 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001697 DECLARE_WAITQUEUE(wait, current);
1698 unsigned long flags;
1699 int channel;
1700 int retval;
1701 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001703 /*
1704 * If the device is in the middle of being closed, then block
1705 * until it's done, and then try again.
1706 */
1707 if (info->flags & ASYNC_CLOSING) {
1708 interruptible_sleep_on(&info->close_wait);
1709 if (info->flags & ASYNC_HUP_NOTIFY) {
1710 return -EAGAIN;
1711 } else {
1712 return -ERESTARTSYS;
1713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001716 /*
1717 * If non-blocking mode is set, then make the check up front
1718 * and then exit.
1719 */
1720 if (filp->f_flags & O_NONBLOCK) {
1721 info->flags |= ASYNC_NORMAL_ACTIVE;
1722 return 0;
1723 }
1724
1725 /*
1726 * Block waiting for the carrier detect and the line to become
1727 * free (i.e., not in use by the callout). While we are in
1728 * this loop, info->count is dropped by one, so that
1729 * cy_close() knows when to free things. We restore it upon
1730 * exit, either normal or abnormal.
1731 */
1732 retval = 0;
1733 add_wait_queue(&info->open_wait, &wait);
1734#ifdef SERIAL_DEBUG_OPEN
1735 printk("block_til_ready before block: %s, count = %d\n",
1736 tty->name, info->count);
1737 /**/
1738#endif
1739 info->count--;
1740#ifdef SERIAL_DEBUG_COUNT
1741 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1742#endif
1743 info->blocked_open++;
1744
1745 channel = info->line;
1746
1747 while (1) {
1748 local_irq_save(flags);
1749 base_addr[CyCAR] = (u_char) channel;
1750 base_addr[CyMSVR1] = CyRTS;
1751/* CP('S');CP('4'); */
1752 base_addr[CyMSVR2] = CyDTR;
1753#ifdef SERIAL_DEBUG_DTR
1754 printk("cyc: %d: raising DTR\n", __LINE__);
1755 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1756 base_addr[CyMSVR2]);
1757#endif
1758 local_irq_restore(flags);
1759 set_current_state(TASK_INTERRUPTIBLE);
1760 if (tty_hung_up_p(filp)
1761 || !(info->flags & ASYNC_INITIALIZED)) {
1762 if (info->flags & ASYNC_HUP_NOTIFY) {
1763 retval = -EAGAIN;
1764 } else {
1765 retval = -ERESTARTSYS;
1766 }
1767 break;
1768 }
1769 local_irq_save(flags);
1770 base_addr[CyCAR] = (u_char) channel;
1771/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1772 if (!(info->flags & ASYNC_CLOSING)
1773 && (C_CLOCAL(tty)
1774 || (base_addr[CyMSVR1] & CyDCD))) {
1775 local_irq_restore(flags);
1776 break;
1777 }
1778 local_irq_restore(flags);
1779 if (signal_pending(current)) {
1780 retval = -ERESTARTSYS;
1781 break;
1782 }
1783#ifdef SERIAL_DEBUG_OPEN
1784 printk("block_til_ready blocking: %s, count = %d\n",
1785 tty->name, info->count);
1786 /**/
1787#endif
Arnd Bergmanne142a312010-06-01 22:53:10 +02001788 tty_unlock();
1789 schedule();
1790 tty_lock();
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001791 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001792 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001793 remove_wait_queue(&info->open_wait, &wait);
1794 if (!tty_hung_up_p(filp)) {
1795 info->count++;
1796#ifdef SERIAL_DEBUG_COUNT
1797 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1798 info->count);
1799#endif
1800 }
1801 info->blocked_open--;
1802#ifdef SERIAL_DEBUG_OPEN
1803 printk("block_til_ready after blocking: %s, count = %d\n",
1804 tty->name, info->count);
1805 /**/
1806#endif
1807 if (retval)
1808 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 info->flags |= ASYNC_NORMAL_ACTIVE;
1810 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001811} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
1813/*
1814 * This routine is called whenever a serial port is opened. It
1815 * performs the serial-specific initialization for the tty structure.
1816 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001817int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001819 struct cyclades_port *info;
1820 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001823 line = tty->index;
1824 if ((line < 0) || (NR_PORTS <= line)) {
1825 return -ENODEV;
1826 }
1827 info = &cy_port[line];
1828 if (info->line < 0) {
1829 return -ENODEV;
1830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001832 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001834 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1835 return -ENODEV;
1836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001838 printk("cy_open %s, count = %d\n", tty->name, info->count);
1839 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001841 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001843 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001845 tty->driver_data = info;
1846 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001848 /*
1849 * Start up serial port
1850 */
1851 retval = startup(info);
1852 if (retval) {
1853 return retval;
1854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001856 retval = block_til_ready(tty, filp, info);
1857 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001859 printk("cy_open returning after block_til_ready with %d\n",
1860 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001862 return retval;
1863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001865 printk("cy_open done\n");
1866 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001868 return 0;
1869} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871/*
1872 * ---------------------------------------------------------------------
1873 * serial167_init() and friends
1874 *
1875 * serial167_init() is called at boot-time to initialize the serial driver.
1876 * ---------------------------------------------------------------------
1877 */
1878
1879/*
1880 * This routine prints out the appropriate serial driver version
1881 * number, and identifies which options were configured into this
1882 * driver.
1883 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001884static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001886 printk("MVME166/167 cd2401 driver\n");
1887} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889/* initialize chips on card -- return number of valid
1890 chips (which is number of ports/4) */
1891
1892/*
1893 * This initialises the hardware to a reasonable state. It should
1894 * probe the chip first so as to copy 166-Bug setup as a default for
1895 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1896 * as to limit the number of CyINIT_CHAN commands in normal running.
1897 *
1898 * ... I wonder what I should do if this fails ...
1899 */
1900
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001901void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001903 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 int ch;
1905 u_char spd;
1906 u_char rcor, rbpr, badspeed = 0;
1907 unsigned long flags;
1908
1909 local_irq_save(flags);
1910
1911 /*
1912 * First probe channel zero of the chip, to see what speed has
1913 * been selected.
1914 */
1915
1916 base_addr[CyCAR] = 0;
1917
1918 rcor = base_addr[CyRCOR] << 5;
1919 rbpr = base_addr[CyRBPR];
1920
1921 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1922 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1923 break;
1924 if (spd >= sizeof(baud_bpr)) {
1925 spd = 14; /* 19200 */
1926 badspeed = 1; /* Failed to identify speed */
1927 }
1928 initial_console_speed = spd;
1929
1930 /* OK, we have chosen a speed, now reset and reinitialise */
1931
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001932 my_udelay(20000L); /* Allow time for any active o/p to complete */
1933 if (base_addr[CyCCR] != 0x00) {
1934 local_irq_restore(flags);
1935 /* printk(" chip is never idle (CCR != 0)\n"); */
1936 return;
1937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001939 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1940 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001942 if (base_addr[CyGFRCR] == 0x00) {
1943 local_irq_restore(flags);
1944 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1945 return;
1946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
1948 /*
1949 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1950 * tick
1951 */
1952
1953 base_addr[CyTPR] = 10;
1954
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001955 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1956 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1957 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
1959 /*
1960 * Attempt to set up all channels to something reasonable, and
1961 * bang out a INIT_CHAN command. We should then be able to limit
Uwe Kleine-König9ddc5b62010-01-20 17:02:24 +01001962 * the amount of fiddling we have to do in normal running.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 */
1964
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001965 for (ch = 3; ch >= 0; ch--) {
1966 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 base_addr[CyIER] = 0;
1968 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001969 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 base_addr[CyLIVR] = 0x5c;
1971 base_addr[CyTCOR] = baud_co[spd];
1972 base_addr[CyTBPR] = baud_bpr[spd];
1973 base_addr[CyRCOR] = baud_co[spd] >> 5;
1974 base_addr[CyRBPR] = baud_bpr[spd];
1975 base_addr[CySCHR1] = 'Q' & 0x1f;
1976 base_addr[CySCHR2] = 'X' & 0x1f;
1977 base_addr[CySCRL] = 0;
1978 base_addr[CySCRH] = 0;
1979 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
1980 base_addr[CyCOR2] = 0;
1981 base_addr[CyCOR3] = Cy_1_STOP;
1982 base_addr[CyCOR4] = baud_cor4[spd];
1983 base_addr[CyCOR5] = 0;
1984 base_addr[CyCOR6] = 0;
1985 base_addr[CyCOR7] = 0;
1986 base_addr[CyRTPRL] = 2;
1987 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001988 base_addr[CyMSVR1] = 0;
1989 base_addr[CyMSVR2] = 0;
1990 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 }
1992
1993 /*
1994 * Now do specials for channel zero....
1995 */
1996
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001997 base_addr[CyMSVR1] = CyRTS;
1998 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002000 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 local_irq_restore(flags);
2003
2004 my_udelay(20000L); /* Let it all settle down */
2005
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002006 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002008 printk
2009 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2010 rcor >> 5, rbpr);
2011} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002013static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 .open = cy_open,
2015 .close = cy_close,
2016 .write = cy_write,
2017 .put_char = cy_put_char,
2018 .flush_chars = cy_flush_chars,
2019 .write_room = cy_write_room,
2020 .chars_in_buffer = cy_chars_in_buffer,
2021 .flush_buffer = cy_flush_buffer,
2022 .ioctl = cy_ioctl,
2023 .throttle = cy_throttle,
2024 .unthrottle = cy_unthrottle,
2025 .set_termios = cy_set_termios,
2026 .stop = cy_stop,
2027 .start = cy_start,
2028 .hangup = cy_hangup,
2029 .tiocmget = cy_tiocmget,
2030 .tiocmset = cy_tiocmset,
2031};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033/* The serial driver boot-time initialization code!
2034 Hardware I/O ports are mapped to character special devices on a
2035 first found, first allocated manner. That is, this code searches
2036 for Cyclom cards in the system. As each is found, it is probed
2037 to discover how many chips (and thus how many ports) are present.
2038 These ports are mapped to the tty ports 64 and upward in monotonic
2039 fashion. If an 8-port card is replaced with a 16-port card, the
2040 port mapping on a following card will shift.
2041
2042 This approach is different from what is used in the other serial
2043 device driver because the Cyclom is more properly a multiplexer,
2044 not just an aggregation of serial ports on one card.
2045
2046 If there are more cards with more ports than have been statically
2047 allocated above, a warning is printed and the extra ports are ignored.
2048 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002049static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002051 struct cyclades_port *info;
2052 int ret = 0;
2053 int good_ports = 0;
2054 int port_num = 0;
2055 int index;
2056 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002058 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059#endif
2060
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002061 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2062 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002064 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2065 if (!cy_serial_driver)
2066 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
2068#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002069 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070#endif
2071
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002072 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002074 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2075 if (serial_console_cflag)
2076 DefSpeed = serial_console_cflag & 0017;
2077 else {
2078 DefSpeed = initial_console_speed;
2079 serial_console_info = &cy_port[0];
2080 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002082 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002085
2086 /* Initialize the tty_driver structure */
2087
2088 cy_serial_driver->owner = THIS_MODULE;
2089 cy_serial_driver->name = "ttyS";
2090 cy_serial_driver->major = TTY_MAJOR;
2091 cy_serial_driver->minor_start = 64;
2092 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2093 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2094 cy_serial_driver->init_termios = tty_std_termios;
2095 cy_serial_driver->init_termios.c_cflag =
2096 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2097 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2098 tty_set_operations(cy_serial_driver, &cy_ops);
2099
2100 ret = tty_register_driver(cy_serial_driver);
2101 if (ret) {
2102 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2103 put_tty_driver(cy_serial_driver);
2104 return ret;
2105 }
2106
2107 port_num = 0;
2108 info = cy_port;
2109 for (index = 0; index < 1; index++) {
2110
2111 good_ports = 4;
2112
2113 if (port_num < NR_PORTS) {
2114 while (good_ports-- && port_num < NR_PORTS) {
2115 /*** initialize port ***/
2116 info->magic = CYCLADES_MAGIC;
2117 info->type = PORT_CIRRUS;
2118 info->card = index;
2119 info->line = port_num;
2120 info->flags = STD_COM_FLAGS;
2121 info->tty = NULL;
2122 info->xmit_fifo_size = 12;
2123 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2124 info->cor2 = CyETC;
2125 info->cor3 = Cy_1_STOP;
2126 info->cor4 = 0x08; /* _very_ small receive threshold */
2127 info->cor5 = 0;
2128 info->cor6 = 0;
2129 info->cor7 = 0;
2130 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2131 info->tco = baud_co[DefSpeed]; /* Tx CO */
2132 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2133 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2134 info->close_delay = 0;
2135 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002136 info->count = 0;
2137#ifdef SERIAL_DEBUG_COUNT
2138 printk("cyc: %d: setting count to 0\n",
2139 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002141 info->blocked_open = 0;
2142 info->default_threshold = 0;
2143 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002144 init_waitqueue_head(&info->open_wait);
2145 init_waitqueue_head(&info->close_wait);
2146 /* info->session */
2147 /* info->pgrp */
2148/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2149 info->read_status_mask =
2150 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2151 CyFRAME | CyOVERRUN;
2152 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002154 printk("ttyS%d ", info->line);
2155 port_num++;
2156 info++;
2157 if (!(port_num & 7)) {
2158 printk("\n ");
2159 }
2160 }
2161 }
2162 printk("\n");
2163 }
2164 while (port_num < NR_PORTS) {
2165 info->line = -1;
2166 port_num++;
2167 info++;
2168 }
Christoph Egger0dbb5672010-05-17 17:25:54 +02002169
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002170 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2171 "cd2401_errors", cd2401_rxerr_interrupt);
2172 if (ret) {
2173 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2174 goto cleanup_serial_driver;
2175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002177 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2178 "cd2401_modem", cd2401_modem_interrupt);
2179 if (ret) {
2180 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2181 goto cleanup_irq_cd2401_errors;
2182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002184 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2185 "cd2401_txints", cd2401_tx_interrupt);
2186 if (ret) {
2187 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2188 goto cleanup_irq_cd2401_modem;
2189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002191 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2192 "cd2401_rxints", cd2401_rx_interrupt);
2193 if (ret) {
2194 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2195 goto cleanup_irq_cd2401_txints;
2196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002198 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002200 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2201 pcc2chip[PccSCCTICR] = 0x15;
2202 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002204 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2205
2206 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002208 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002210 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002212 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002214 if (tty_unregister_driver(cy_serial_driver))
2215 printk(KERN_ERR
2216 "Couldn't unregister MVME166/7 serial driver\n");
2217 put_tty_driver(cy_serial_driver);
2218 return ret;
2219} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
2221module_init(serial167_init);
2222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002224static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002226 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2227 int channel;
2228 struct cyclades_port *info;
2229 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002231 info = &cy_port[line_num];
2232 channel = info->line;
2233 printk(" channel %d\n", channel);
2234 /**/ printk(" cy_port\n");
2235 printk(" card line flags = %d %d %x\n",
2236 info->card, info->line, info->flags);
2237 printk
2238 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2239 (long)info->tty, info->read_status_mask, info->timeout,
2240 info->xmit_fifo_size);
2241 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2242 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2243 info->cor6, info->cor7);
2244 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2245 info->rbpr, info->rco);
2246 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2247 info->event, info->count);
2248 printk(" x_char blocked_open = %x %x\n", info->x_char,
2249 info->blocked_open);
2250 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002252 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
2254/* Global Registers */
2255
2256 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2257 printk(" CyCAR %x\n", base_addr[CyCAR]);
2258 printk(" CyRISR %x\n", base_addr[CyRISR]);
2259 printk(" CyTISR %x\n", base_addr[CyTISR]);
2260 printk(" CyMISR %x\n", base_addr[CyMISR]);
2261 printk(" CyRIR %x\n", base_addr[CyRIR]);
2262 printk(" CyTIR %x\n", base_addr[CyTIR]);
2263 printk(" CyMIR %x\n", base_addr[CyMIR]);
2264 printk(" CyTPR %x\n", base_addr[CyTPR]);
2265
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002266 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
2268/* Virtual Registers */
2269
2270#if 0
2271 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2272 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2273 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2274 printk(" CyMISR %x\n", base_addr[CyMISR]);
2275#endif
2276
2277/* Channel Registers */
2278
2279 printk(" CyCCR %x\n", base_addr[CyCCR]);
2280 printk(" CyIER %x\n", base_addr[CyIER]);
2281 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2282 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2283 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2284 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2285 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2286#if 0
2287 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2288 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2289#endif
2290 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2291 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2292#if 0
2293 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2294 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2295 printk(" CySCRL %x\n", base_addr[CySCRL]);
2296 printk(" CySCRH %x\n", base_addr[CySCRH]);
2297 printk(" CyLNC %x\n", base_addr[CyLNC]);
2298 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2299 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2300#endif
2301 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2302 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2303 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2304 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2305 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2306 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2307 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2308 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2309
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002310 local_irq_restore(flags);
2311} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312#endif
2313
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314#if 0
2315/* Dummy routine in mvme16x/config.c for now */
2316
2317/* Serial console setup. Called from linux/init/main.c */
2318
2319void console_setup(char *str, int *ints)
2320{
2321 char *s;
2322 int baud, bits, parity;
2323 int cflag = 0;
2324
2325 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002326 if (ints[0] > 3 || ints[1] > 3)
2327 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
2329 /* Get baud, bits and parity */
2330 baud = 2400;
2331 bits = 8;
2332 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002333 if (ints[2])
2334 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 if ((s = strchr(str, ','))) {
2336 do {
2337 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002338 } while (*s >= '0' && *s <= '9');
2339 if (*s)
2340 parity = *s++;
2341 if (*s)
2342 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 }
2344
2345 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002346 switch (baud) {
2347 case 1200:
2348 cflag |= B1200;
2349 break;
2350 case 9600:
2351 cflag |= B9600;
2352 break;
2353 case 19200:
2354 cflag |= B19200;
2355 break;
2356 case 38400:
2357 cflag |= B38400;
2358 break;
2359 case 2400:
2360 default:
2361 cflag |= B2400;
2362 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002364 switch (bits) {
2365 case 7:
2366 cflag |= CS7;
2367 break;
2368 default:
2369 case 8:
2370 cflag |= CS8;
2371 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002373 switch (parity) {
2374 case 'o':
2375 case 'O':
2376 cflag |= PARODD;
2377 break;
2378 case 'e':
2379 case 'E':
2380 cflag |= PARENB;
2381 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 }
2383
2384 serial_console_info = &cy_port[ints[1]];
2385 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002386 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387}
2388#endif
2389
2390/*
2391 * The following is probably out of date for 2.1.x serial console stuff.
2392 *
2393 * The console is registered early on from arch/m68k/kernel/setup.c, and
2394 * it therefore relies on the chip being setup correctly by 166-Bug. This
2395 * seems reasonable, as the serial port has been used to invoke the system
2396 * boot. It also means that this function must not rely on any data
2397 * initialisation performed by serial167_init() etc.
2398 *
2399 * Of course, once the console has been registered, we had better ensure
2400 * that serial167_init() doesn't leave the chip non-functional.
2401 *
2402 * The console must be locked when we get here.
2403 */
2404
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002405void serial167_console_write(struct console *co, const char *str,
2406 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002408 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 unsigned long flags;
2410 volatile u_char sink;
2411 u_char ier;
2412 int port;
2413 u_char do_lf = 0;
2414 int i = 0;
2415
2416 local_irq_save(flags);
2417
2418 /* Ensure transmitter is enabled! */
2419
2420 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002421 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 while (base_addr[CyCCR])
2423 ;
2424 base_addr[CyCCR] = CyENB_XMTR;
2425
2426 ier = base_addr[CyIER];
2427 base_addr[CyIER] = CyTxMpty;
2428
2429 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002430 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 /* We have a Tx int. Acknowledge it */
2432 sink = pcc2chip[PccTPIACKR];
2433 if ((base_addr[CyLICR] >> 2) == port) {
2434 if (i == count) {
2435 /* Last char of string is now output */
2436 base_addr[CyTEOIR] = CyNOTRANS;
2437 break;
2438 }
2439 if (do_lf) {
2440 base_addr[CyTDR] = '\n';
2441 str++;
2442 i++;
2443 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002444 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 base_addr[CyTDR] = '\r';
2446 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002447 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 base_addr[CyTDR] = *str++;
2449 i++;
2450 }
2451 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002452 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 base_addr[CyTEOIR] = CyNOTRANS;
2454 }
2455 }
2456
2457 base_addr[CyIER] = ier;
2458
2459 local_irq_restore(flags);
2460}
2461
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002462static struct tty_driver *serial167_console_device(struct console *c,
2463 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464{
2465 *index = c->index;
2466 return cy_serial_driver;
2467}
2468
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002470 .name = "ttyS",
2471 .write = serial167_console_write,
2472 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002473 .flags = CON_PRINTBUFFER,
2474 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475};
2476
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477static int __init serial167_console_init(void)
2478{
2479 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002480 vme_brdtype == VME_TYPE_MVME167 ||
2481 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 mvme167_serial_console_setup(0);
2483 register_console(&sercons);
2484 }
2485 return 0;
2486}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488console_initcall(serial167_console_init);
2489
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490MODULE_LICENSE("GPL");