blob: f646725bd567ec279541dd968e9a1653746035fe [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/char/serial167.c
3 *
4 * Driver for MVME166/7 board serial ports, which are via a CD2401.
5 * Based very much on cyclades.c.
6 *
7 * MVME166/7 work by Richard Hirst [richard@sleepie.demon.co.uk]
8 *
9 * ==============================================================
10 *
11 * static char rcsid[] =
12 * "$Revision: 1.36.1.4 $$Date: 1995/03/29 06:14:14 $";
13 *
14 * linux/kernel/cyclades.c
15 *
16 * Maintained by Marcio Saito (cyclades@netcom.com) and
17 * Randolph Bentson (bentson@grieg.seaslug.org)
18 *
19 * Much of the design and some of the code came from serial.c
20 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
21 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
22 * and then fixed as suggested by Michael K. Johnson 12/12/92.
23 *
24 * This version does not support shared irq's.
25 *
26 * $Log: cyclades.c,v $
27 * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
28 * disambiguate between Cyclom-16Y and Cyclom-32Ye;
29 *
30 * Changes:
31 *
32 * 200 lines of changes record removed - RGH 11-10-95, starting work on
33 * converting this to drive serial ports on mvme166 (cd2401).
34 *
35 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/08/25
36 * - get rid of verify_area
37 * - use get_user to access memory from userspace in set_threshold,
38 * set_default_threshold and set_timeout
39 * - don't use the panic function in serial167_init
40 * - do resource release on failure on serial167_init
41 * - include missing restore_flags in mvme167_serial_console_setup
42 *
43 * Kars de Jong <jongk@linux-m68k.org> - 2004/09/06
44 * - replace bottom half handler with task queue handler
45 */
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/errno.h>
48#include <linux/signal.h>
49#include <linux/sched.h>
50#include <linux/timer.h>
51#include <linux/tty.h>
52#include <linux/interrupt.h>
53#include <linux/serial.h>
54#include <linux/serialP.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040055#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/string.h>
57#include <linux/fcntl.h>
58#include <linux/ptrace.h>
59#include <linux/serial167.h>
60#include <linux/delay.h>
61#include <linux/major.h>
62#include <linux/mm.h>
63#include <linux/console.h>
64#include <linux/module.h>
65#include <linux/bitops.h>
Geert Uytterhoeven81e859a2006-10-09 22:27:42 +020066#include <linux/tty_flip.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090067#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#include <asm/system.h>
70#include <asm/io.h>
71#include <asm/mvme16xhw.h>
72#include <asm/bootinfo.h>
73#include <asm/setup.h>
74
75#include <linux/types.h>
76#include <linux/kernel.h>
77
78#include <asm/uaccess.h>
79#include <linux/init.h>
80
81#define SERIAL_PARANOIA_CHECK
82#undef SERIAL_DEBUG_OPEN
83#undef SERIAL_DEBUG_THROTTLE
84#undef SERIAL_DEBUG_OTHER
85#undef SERIAL_DEBUG_IO
86#undef SERIAL_DEBUG_COUNT
87#undef SERIAL_DEBUG_DTR
88#undef CYCLOM_16Y_HACK
89#define CYCLOM_ENABLE_MONITORING
90
91#define WAKEUP_CHARS 256
92
93#define STD_COM_FLAGS (0)
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static struct tty_driver *cy_serial_driver;
96extern int serial_console;
97static struct cyclades_port *serial_console_info = NULL;
98static unsigned int serial_console_cflag = 0;
99u_char initial_console_speed;
100
101/* Base address of cd2401 chip on mvme166/7 */
102
103#define BASE_ADDR (0xfff45000)
104#define pcc2chip ((volatile u_char *)0xfff42000)
105#define PccSCCMICR 0x1d
106#define PccSCCTICR 0x1e
107#define PccSCCRICR 0x1f
108#define PccTPIACKR 0x25
109#define PccRPIACKR 0x27
110#define PccIMLR 0x3f
111
112/* This is the per-port data structure */
113struct cyclades_port cy_port[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800114 /* CARD# */
115 {-1}, /* ttyS0 */
116 {-1}, /* ttyS1 */
117 {-1}, /* ttyS2 */
118 {-1}, /* ttyS3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800120
Tobias Klauserfe971072006-01-09 20:54:02 -0800121#define NR_PORTS ARRAY_SIZE(cy_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 * This is used to look up the divisor speeds and the timeouts
125 * We're normally limited to 15 distinct baud rates. The extra
126 * are accessed via settings in info->flags.
127 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
128 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
129 * HI VHI
130 */
131static int baud_table[] = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800132 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
133 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
134 0
135};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800138static char baud_co[] = { /* 25 MHz clock option table */
139 /* value => 00 01 02 03 04 */
140 /* divide by 8 32 128 512 2048 */
141 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
142 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
143};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800145static char baud_bpr[] = { /* 25 MHz baud rate period table */
146 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
147 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
148};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#endif
150
151/* I think 166 brd clocks 2401 at 20MHz.... */
152
153/* These values are written directly to tcor, and >> 5 for writing to rcor */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800154static u_char baud_co[] = { /* 20 MHz clock option table */
155 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40,
156 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
157};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159/* These values written directly to tbpr/rbpr */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800160static u_char baud_bpr[] = { /* 20 MHz baud rate period table */
161 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81,
162 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10
163};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800165static u_char baud_cor4[] = { /* receive threshold */
166 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
167 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07
168};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170static void shutdown(struct cyclades_port *);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800171static int startup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static void cy_throttle(struct tty_struct *);
173static void cy_unthrottle(struct tty_struct *);
174static void config_setup(struct cyclades_port *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#ifdef CYCLOM_SHOW_STATUS
176static void show_status(int);
177#endif
178
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179/*
180 * I have my own version of udelay(), as it is needed when initialising
181 * the chip, before the delay loop has been calibrated. Should probably
182 * reference one of the vmechip2 or pccchip2 counter for an accurate
183 * delay, but this wild guess will do for now.
184 */
185
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800186void my_udelay(long us)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188 u_char x;
189 volatile u_char *p = &x;
190 int i;
191
192 while (us--)
193 for (i = 100; i; i--)
194 x |= *p;
195}
196
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800197static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
198 const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
200#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800201 if (!info) {
202 printk("Warning: null cyclades_port for (%s) in %s\n", name,
203 routine);
204 return 1;
205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Roel Kluinf23fc152009-10-01 15:44:25 -0700207 if (info < &cy_port[0] || info >= &cy_port[NR_PORTS]) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800208 printk("Warning: cyclades_port out of range for (%s) in %s\n",
209 name, routine);
210 return 1;
211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800213 if (info->magic != CYCLADES_MAGIC) {
214 printk("Warning: bad magic number for serial struct (%s) in "
215 "%s\n", name, routine);
216 return 1;
217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218#endif
219 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800220} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222#if 0
223/* The following diagnostic routines allow the driver to spew
224 information on the screen, even (especially!) during interrupts.
225 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800226void SP(char *data)
227{
228 unsigned long flags;
229 local_irq_save(flags);
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700230 printk(KERN_EMERG "%s", data);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800231 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800234char scrn[2];
235void CP(char data)
236{
237 unsigned long flags;
238 local_irq_save(flags);
239 scrn[0] = data;
Anirban Sinha353f6dd2009-09-14 11:13:37 -0700240 printk(KERN_EMERG "%c", scrn);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800241 local_irq_restore(flags);
242} /* CP */
243
244void CP1(int data)
245{
246 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
247} /* CP1 */
248void CP2(int data)
249{
250 CP1((data >> 4) & 0x0f);
251 CP1(data & 0x0f);
252} /* CP2 */
253void CP4(int data)
254{
255 CP2((data >> 8) & 0xff);
256 CP2(data & 0xff);
257} /* CP4 */
258void CP8(long data)
259{
260 CP4((data >> 16) & 0xffff);
261 CP4(data & 0xffff);
262} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263#endif
264
265/* This routine waits up to 1000 micro-seconds for the previous
266 command to the Cirrus chip to complete and then issues the
267 new command. An error is returned if the previous command
268 didn't finish within the time limit.
269 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800270u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800272 unsigned long flags;
273 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800275 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800277 for (i = 0; i < 100; i++) {
278 if (base_addr[CyCCR] == 0) {
279 break;
280 }
281 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
283 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800284 didn't finish within the "reasonable time" */
285 if (i == 10) {
286 local_irq_restore(flags);
287 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
289
290 /* Issue the new command */
291 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800292 local_irq_restore(flags);
293 return (0);
294} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296/* cy_start and cy_stop provide software output flow control as a
297 function of XON/XOFF, software CTS, and other such stuff. */
298
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800299static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Alan Coxc9f19e92009-01-02 13:47:26 +0000301 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800302 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
303 int channel;
304 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800307 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308#endif
309
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800310 if (serial_paranoia_check(info, tty->name, "cy_stop"))
311 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800313 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800315 local_irq_save(flags);
316 base_addr[CyCAR] = (u_char) (channel); /* index channel */
317 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
318 local_irq_restore(flags);
319} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800321static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Alan Coxc9f19e92009-01-02 13:47:26 +0000323 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800324 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
325 int channel;
326 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800329 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#endif
331
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800332 if (serial_paranoia_check(info, tty->name, "cy_start"))
333 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800335 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800337 local_irq_save(flags);
338 base_addr[CyCAR] = (u_char) (channel);
339 base_addr[CyIER] |= CyTxMpty;
340 local_irq_restore(flags);
341} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343/* The real interrupt service routines are called
344 whenever the card wants its hand held--chars
345 received, out buffer empty, modem change, etc.
346 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800347static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800349 struct tty_struct *tty;
350 struct cyclades_port *info;
351 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
352 unsigned char err, rfoc;
353 int channel;
354 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800356 /* determine the channel and change to that context */
357 channel = (u_short) (base_addr[CyLICR] >> 2);
358 info = &cy_port[channel];
359 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800361 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
362 /* This is a receive timeout interrupt, ignore it */
363 base_addr[CyREOIR] = CyNOTRANS;
364 return IRQ_HANDLED;
365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800367 /* Read a byte of data if there is any - assume the error
368 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800370 if ((rfoc = base_addr[CyRFOC]) != 0)
371 data = base_addr[CyRDR];
372 else
373 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800375 /* if there is nowhere to put the data, discard it */
376 if (info->tty == 0) {
377 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
378 return IRQ_HANDLED;
379 } else { /* there is an open port for this data */
380 tty = info->tty;
381 if (err & info->ignore_status_mask) {
382 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
383 return IRQ_HANDLED;
384 }
385 if (tty_buffer_request_room(tty, 1) != 0) {
386 if (err & info->read_status_mask) {
387 if (err & CyBREAK) {
388 tty_insert_flip_char(tty, data,
389 TTY_BREAK);
390 if (info->flags & ASYNC_SAK) {
391 do_SAK(tty);
392 }
393 } else if (err & CyFRAME) {
394 tty_insert_flip_char(tty, data,
395 TTY_FRAME);
396 } else if (err & CyPARITY) {
397 tty_insert_flip_char(tty, data,
398 TTY_PARITY);
399 } else if (err & CyOVERRUN) {
400 tty_insert_flip_char(tty, 0,
401 TTY_OVERRUN);
402 /*
403 If the flip buffer itself is
Nick Andrewc4f01242008-12-05 16:34:46 +0000404 overflowing, we still lose
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800405 the next incoming character.
406 */
407 if (tty_buffer_request_room(tty, 1) !=
408 0) {
409 tty_insert_flip_char(tty, data,
410 TTY_FRAME);
411 }
412 /* These two conditions may imply */
413 /* a normal read should be done. */
414 /* else if(data & CyTIMEOUT) */
415 /* else if(data & CySPECHAR) */
416 } else {
417 tty_insert_flip_char(tty, 0,
418 TTY_NORMAL);
419 }
420 } else {
421 tty_insert_flip_char(tty, data, TTY_NORMAL);
422 }
423 } else {
424 /* there was a software buffer overrun
425 and nothing could be done about it!!! */
426 }
427 }
428 tty_schedule_flip(tty);
429 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
431 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800432} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800434static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800436 struct cyclades_port *info;
437 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
438 int channel;
439 int mdm_change;
440 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800442 /* determine the channel and change to that context */
443 channel = (u_short) (base_addr[CyLICR] >> 2);
444 info = &cy_port[channel];
445 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800447 mdm_change = base_addr[CyMISR];
448 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800450 if (info->tty == 0) { /* nowhere to put the data, ignore it */
451 ;
452 } else {
453 if ((mdm_change & CyDCD)
454 && (info->flags & ASYNC_CHECK_CD)) {
455 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456/* CP('!'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800457 wake_up_interruptible(&info->open_wait);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800458 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459/* CP('@'); */
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800460 tty_hangup(info->tty);
461 wake_up_interruptible(&info->open_wait);
462 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800465 if ((mdm_change & CyCTS)
466 && (info->flags & ASYNC_CTS_FLOW)) {
467 if (info->tty->stopped) {
468 if (mdm_status & CyCTS) {
469 /* !!! cy_start isn't used because... */
470 info->tty->stopped = 0;
471 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800472 tty_wakeup(info->tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800473 }
474 } else {
475 if (!(mdm_status & CyCTS)) {
476 /* !!! cy_stop isn't used because... */
477 info->tty->stopped = 1;
478 base_addr[CyIER] &=
479 ~(CyTxMpty | CyTxRdy);
480 }
481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800483 if (mdm_status & CyDSR) {
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800486 base_addr[CyMEOIR] = 0;
487 return IRQ_HANDLED;
488} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800490static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800492 struct cyclades_port *info;
493 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
494 int channel;
495 int char_count, saved_cnt;
496 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800498 /* determine the channel and change to that context */
499 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800501 /* validate the port number (as configured and open) */
502 if ((channel < 0) || (NR_PORTS <= channel)) {
503 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
504 base_addr[CyTEOIR] = CyNOTRANS;
505 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
Roel Kluinf23fc152009-10-01 15:44:25 -0700507 info = &cy_port[channel];
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800508 info->last_active = jiffies;
509 if (info->tty == 0) {
510 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800511 base_addr[CyTEOIR] = CyNOTRANS;
512 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800514
515 /* load the on-chip space available for outbound data */
516 saved_cnt = char_count = base_addr[CyTFTC];
517
518 if (info->x_char) { /* send special char */
519 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800522 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800525 if (info->x_break) {
526 /* The Cirrus chip requires the "Embedded Transmit
527 Commands" of start break, delay, and end break
528 sequences to be sent. The duration of the
529 break is given in TICs, which runs at HZ
530 (typically 100) and the PPR runs at 200 Hz,
531 so the delay is duration * 200/HZ, and thus a
532 break can run from 1/100 sec to about 5/4 sec.
533 Need to check these values - RGH 141095.
534 */
535 base_addr[CyTDR] = 0; /* start break */
536 base_addr[CyTDR] = 0x81;
537 base_addr[CyTDR] = 0; /* delay a bit */
538 base_addr[CyTDR] = 0x82;
539 base_addr[CyTDR] = info->x_break * 200 / HZ;
540 base_addr[CyTDR] = 0; /* terminate break */
541 base_addr[CyTDR] = 0x83;
542 char_count -= 7;
543 info->x_break = 0;
544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800546 while (char_count > 0) {
547 if (!info->xmit_cnt) {
548 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
549 break;
550 }
551 if (info->xmit_buf == 0) {
552 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
553 break;
554 }
555 if (info->tty->stopped || info->tty->hw_stopped) {
556 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
557 break;
558 }
559 /* Because the Embedded Transmit Commands have been
560 enabled, we must check to see if the escape
561 character, NULL, is being sent. If it is, we
562 must ensure that there is room for it to be
563 doubled in the output stream. Therefore we
564 no longer advance the pointer when the character
565 is fetched, but rather wait until after the check
566 for a NULL output character. (This is necessary
567 because there may not be room for the two chars
568 needed to send a NULL.
569 */
570 outch = info->xmit_buf[info->xmit_tail];
571 if (outch) {
572 info->xmit_cnt--;
573 info->xmit_tail = (info->xmit_tail + 1)
574 & (PAGE_SIZE - 1);
575 base_addr[CyTDR] = outch;
576 char_count--;
577 } else {
578 if (char_count > 1) {
579 info->xmit_cnt--;
580 info->xmit_tail = (info->xmit_tail + 1)
581 & (PAGE_SIZE - 1);
582 base_addr[CyTDR] = outch;
583 base_addr[CyTDR] = 0;
584 char_count--;
585 char_count--;
586 } else {
587 break;
588 }
589 }
590 }
591
Jiri Slaby3099bbc2008-02-07 00:16:40 -0800592 if (info->xmit_cnt < WAKEUP_CHARS)
593 tty_wakeup(info->tty);
594
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800595 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
596 return IRQ_HANDLED;
597} /* cy_tx_interrupt */
598
599static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800601 struct tty_struct *tty;
602 struct cyclades_port *info;
603 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
604 int channel;
605 char data;
606 int char_count;
607 int save_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800609 /* determine the channel and change to that context */
610 channel = (u_short) (base_addr[CyLICR] >> 2);
611 info = &cy_port[channel];
612 info->last_active = jiffies;
613 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800615 /* if there is nowhere to put the data, discard it */
616 if (info->tty == 0) {
617 while (char_count--) {
618 data = base_addr[CyRDR];
619 }
620 } else { /* there is an open port for this data */
621 tty = info->tty;
622 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800625 ++info->mon.int_count;
626 info->mon.char_count += char_count;
627 if (char_count > info->mon.char_max)
628 info->mon.char_max = char_count;
629 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630#endif
Alan Cox4165fe42010-02-17 13:07:13 +0000631 while (char_count--) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800632 data = base_addr[CyRDR];
633 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800635 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800637 }
638 tty_schedule_flip(tty);
639 }
640 /* end of service */
641 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
642 return IRQ_HANDLED;
643} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645/* This is called whenever a port becomes active;
646 interrupts are enabled and DTR & RTS are turned on.
647 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800648static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800650 unsigned long flags;
651 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
652 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800654 if (info->flags & ASYNC_INITIALIZED) {
655 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800657
658 if (!info->type) {
659 if (info->tty) {
660 set_bit(TTY_IO_ERROR, &info->tty->flags);
661 }
662 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800664 if (!info->xmit_buf) {
665 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
666 if (!info->xmit_buf) {
667 return -ENOMEM;
668 }
669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800671 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800673 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
675#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800676 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677#endif
678
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800679 local_irq_save(flags);
680 base_addr[CyCAR] = (u_char) channel;
681 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800683 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 base_addr[CyMSVR1] = CyRTS;
685/* CP('S');CP('1'); */
686 base_addr[CyMSVR2] = CyDTR;
687
688#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800689 printk("cyc: %d: raising DTR\n", __LINE__);
690 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
691 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692#endif
693
694 base_addr[CyIER] |= CyRxData;
695 info->flags |= ASYNC_INITIALIZED;
696
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800697 if (info->tty) {
698 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
700 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
701
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800702 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
704#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800705 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800707 return 0;
708} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800710void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800712 unsigned long flags;
713 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
714 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800716 channel = info->line;
717 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 base_addr[CyCAR] = channel;
719 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800720 local_irq_restore(flags);
721} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723/*
724 * This routine shuts down a serial port; interrupts are disabled,
725 * and DTR is dropped if the hangup on close termio flag is on.
726 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800727static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800729 unsigned long flags;
730 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
731 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800733 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800735 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800738 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800740#ifdef SERIAL_DEBUG_OPEN
741 printk("shutdown channel %d\n", channel);
742#endif
743
744 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
745 SENT BEFORE DROPPING THE LINE !!! (Perhaps
746 set some flag that is read when XMTY happens.)
747 Other choices are to delay some fixed interval
748 or schedule some later processing.
749 */
750 local_irq_save(flags);
751 if (info->xmit_buf) {
752 free_page((unsigned long)info->xmit_buf);
753 info->xmit_buf = NULL;
754 }
755
756 base_addr[CyCAR] = (u_char) channel;
757 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
758 base_addr[CyMSVR1] = 0;
759/* CP('C');CP('1'); */
760 base_addr[CyMSVR2] = 0;
761#ifdef SERIAL_DEBUG_DTR
762 printk("cyc: %d: dropping DTR\n", __LINE__);
763 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
764 base_addr[CyMSVR2]);
765#endif
766 }
767 write_cy_cmd(base_addr, CyDIS_RCVR);
768 /* it may be appropriate to clear _XMIT at
769 some later date (after testing)!!! */
770
771 if (info->tty) {
772 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800775 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800778 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800780} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782/*
783 * This routine finds or computes the various line characteristics.
784 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800785static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800787 unsigned long flags;
788 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
789 int channel;
790 unsigned cflag;
791 int i;
792 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800794 if (!info->tty || !info->tty->termios) {
795 return;
796 }
797 if (info->line == -1) {
798 return;
799 }
800 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800802 /* baud rate */
803 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804#ifdef CBAUDEX
805/* Starting with kernel 1.1.65, there is direct support for
806 higher baud rates. The following code supports those
807 changes. The conditional aspect allows this driver to be
808 used for earlier as well as later kernel versions. (The
809 mapping is slightly different from serial.c because there
810 is still the possibility of supporting 75 kbit/sec with
811 the Cyclades board.)
812 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800813 if (i & CBAUDEX) {
814 if (i == B57600)
815 i = 16;
816 else if (i == B115200)
817 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800819 else if (i == B78600)
820 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800822 else
823 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800826 if (i == 15) {
827 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
828 i += 1;
829 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
830 i += 3;
831 }
832 /* Don't ever change the speed of the console port. It will
833 * run at the speed specified in bootinfo, or at 19.2K */
834 /* Actually, it should run at whatever speed 166Bug was using */
835 /* Note info->timeout isn't used at present */
836 if (info != serial_console_info) {
837 info->tbpr = baud_bpr[i]; /* Tx BPR */
838 info->tco = baud_co[i]; /* Tx CO */
839 info->rbpr = baud_bpr[i]; /* Rx BPR */
840 info->rco = baud_co[i] >> 5; /* Rx CO */
841 if (baud_table[i] == 134) {
842 info->timeout =
843 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
844 /* get it right for 134.5 baud */
845 } else if (baud_table[i]) {
846 info->timeout =
847 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
848 2;
849 /* this needs to be propagated into the card info */
850 } else {
851 info->timeout = 0;
852 }
853 }
854 /* By tradition (is it a standard?) a baud rate of zero
855 implies the line should be/has been closed. A bit
856 later in this routine such a test is performed. */
857
858 /* byte size and parity */
859 info->cor7 = 0;
860 info->cor6 = 0;
861 info->cor5 = 0;
862 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
863 /* Following two lines added 101295, RGH. */
864 /* It is obviously wrong to access CyCORx, and not info->corx here,
865 * try and remember to fix it later! */
866 channel = info->line;
867 base_addr[CyCAR] = (u_char) channel;
868 if (C_CLOCAL(info->tty)) {
869 if (base_addr[CyIER] & CyMdmCh)
870 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
871 /* ignore 1->0 modem transitions */
872 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
873 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
874 /* ignore 0->1 modem transitions */
875 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
876 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
877 } else {
878 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
879 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
880 /* act on 1->0 modem transitions */
881 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
882 (CyDSR | CyCTS | CyDCD))
883 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
884 /* act on 0->1 modem transitions */
885 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
886 (CyDSR | CyCTS | CyDCD))
887 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
888 }
889 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
890 info->cor2 = CyETC;
891 switch (cflag & CSIZE) {
892 case CS5:
893 info->cor1 = Cy_5_BITS;
894 break;
895 case CS6:
896 info->cor1 = Cy_6_BITS;
897 break;
898 case CS7:
899 info->cor1 = Cy_7_BITS;
900 break;
901 case CS8:
902 info->cor1 = Cy_8_BITS;
903 break;
904 }
905 if (cflag & PARENB) {
906 if (cflag & PARODD) {
907 info->cor1 |= CyPARITY_O;
908 } else {
909 info->cor1 |= CyPARITY_E;
910 }
911 } else {
912 info->cor1 |= CyPARITY_NONE;
913 }
914
915 /* CTS flow control flag */
916#if 0
917 /* Don't complcate matters for now! RGH 141095 */
918 if (cflag & CRTSCTS) {
919 info->flags |= ASYNC_CTS_FLOW;
920 info->cor2 |= CyCtsAE;
921 } else {
922 info->flags &= ~ASYNC_CTS_FLOW;
923 info->cor2 &= ~CyCtsAE;
924 }
925#endif
926 if (cflag & CLOCAL)
927 info->flags &= ~ASYNC_CHECK_CD;
928 else
929 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 /***********************************************
932 The hardware option, CyRtsAO, presents RTS when
933 the chip has characters to send. Since most modems
934 use RTS as reverse (inbound) flow control, this
935 option is not used. If inbound flow control is
936 necessary, DTR can be programmed to provide the
937 appropriate signals for use with a non-standard
938 cable. Contact Marcio Saito for details.
939 ***********************************************/
940
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800941 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800943 local_irq_save(flags);
944 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 /* CyCMR set once only in mvme167_init_serial() */
947 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800948 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800950 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800952 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800955 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800957 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800959 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800961 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800963 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 /* set line characteristics according configuration */
966
967 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800968 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800970 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800972 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800974 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800976 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800978 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800980 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800982 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800984 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800986 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800988 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800991 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800993 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 /* 2ms default rx timeout */
996 ti = info->default_timeout ? info->default_timeout : 0x02;
997 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800998 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001000 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001003 if (i == 0) { /* baud rate is zero, turn off line */
1004 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1005 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001007 printk("cyc: %d: dropping DTR\n", __LINE__);
1008 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1009 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001011 } else {
1012 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1013 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001015 printk("cyc: %d: raising DTR\n", __LINE__);
1016 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1017 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018#endif
1019 }
1020
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001021 if (info->tty) {
1022 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 }
1024
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001025 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001027} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
Alan Coxa5b08c62008-04-30 00:54:05 -07001029static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
Alan Coxc9f19e92009-01-02 13:47:26 +00001031 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001032 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001035 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#endif
1037
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001038 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Coxa5b08c62008-04-30 00:54:05 -07001039 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001041 if (!info->xmit_buf)
Geert Uytterhoeven63a59fa2008-05-05 21:15:48 +02001042 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001044 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001046 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001047 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 }
1049
1050 info->xmit_buf[info->xmit_head++] = ch;
1051 info->xmit_head &= PAGE_SIZE - 1;
1052 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001053 local_irq_restore(flags);
Alan Coxa5b08c62008-04-30 00:54:05 -07001054 return 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001055} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001057static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
Alan Coxc9f19e92009-01-02 13:47:26 +00001059 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001060 unsigned long flags;
1061 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1062 int channel;
1063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001065 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066#endif
1067
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001068 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1069 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001071 if (info->xmit_cnt <= 0 || tty->stopped
1072 || tty->hw_stopped || !info->xmit_buf)
1073 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001075 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001077 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 base_addr[CyCAR] = channel;
1079 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001080 local_irq_restore(flags);
1081} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083/* This routine gets called when tty_write has put something into
1084 the write_queue. If the port is not already transmitting stuff,
1085 start it off by enabling interrupts. The interrupt service
1086 routine will then ensure that the characters are sent. If the
1087 port is already active, there is no need to kick it.
1088 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001089static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
Alan Coxc9f19e92009-01-02 13:47:26 +00001091 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001092 unsigned long flags;
1093 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001096 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097#endif
1098
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001099 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1100 return 0;
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001103 if (!info->xmit_buf) {
1104 return 0;
1105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001107 while (1) {
1108 local_irq_save(flags);
1109 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1110 SERIAL_XMIT_SIZE - info->xmit_head));
1111 if (c <= 0) {
1112 local_irq_restore(flags);
1113 break;
1114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001116 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1117 info->xmit_head =
1118 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1119 info->xmit_cnt += c;
1120 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001122 buf += c;
1123 count -= c;
1124 total += c;
1125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001127 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1128 start_xmit(info);
1129 }
1130 return total;
1131} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001133static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Alan Coxc9f19e92009-01-02 13:47:26 +00001135 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001136 int ret;
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001139 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140#endif
1141
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001142 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1143 return 0;
1144 ret = PAGE_SIZE - info->xmit_cnt - 1;
1145 if (ret < 0)
1146 ret = 0;
1147 return ret;
1148} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001150static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
Alan Coxc9f19e92009-01-02 13:47:26 +00001152 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001155 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156#endif
1157
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001158 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1159 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001161 return info->xmit_cnt;
1162} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001164static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
Alan Coxc9f19e92009-01-02 13:47:26 +00001166 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001167 unsigned long flags;
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001170 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171#endif
1172
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001173 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1174 return;
1175 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001177 local_irq_restore(flags);
1178 tty_wakeup(tty);
1179} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181/* This routine is called by the upper-layer tty layer to signal
1182 that incoming characters should be throttled or that the
1183 throttle should be released.
1184 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001185static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186{
Alan Coxc9f19e92009-01-02 13:47:26 +00001187 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001188 unsigned long flags;
1189 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1190 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001193 char buf[64];
1194
1195 printk("throttle %s: %d....\n", tty_name(tty, buf),
1196 tty->ldisc.chars_in_buffer(tty));
1197 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198#endif
1199
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001200 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1201 return;
1202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001204 if (I_IXOFF(tty)) {
1205 info->x_char = STOP_CHAR(tty);
1206 /* Should use the "Send Special Character" feature!!! */
1207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001209 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001211 local_irq_save(flags);
1212 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001214 local_irq_restore(flags);
1215} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001217static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218{
Alan Coxc9f19e92009-01-02 13:47:26 +00001219 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001220 unsigned long flags;
1221 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1222 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001225 char buf[64];
1226
1227 printk("throttle %s: %d....\n", tty_name(tty, buf),
1228 tty->ldisc.chars_in_buffer(tty));
1229 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230#endif
1231
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001232 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1233 return;
1234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001236 if (I_IXOFF(tty)) {
1237 info->x_char = START_CHAR(tty);
1238 /* Should use the "Send Special Character" feature!!! */
1239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001241 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001243 local_irq_save(flags);
1244 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001246 local_irq_restore(flags);
1247} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001250get_serial_info(struct cyclades_port *info,
1251 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001253 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001256 if (!retinfo)
1257 return -EFAULT;
1258 memset(&tmp, 0, sizeof(tmp));
1259 tmp.type = info->type;
1260 tmp.line = info->line;
1261 tmp.port = info->line;
1262 tmp.irq = 0;
1263 tmp.flags = info->flags;
1264 tmp.baud_base = 0; /*!!! */
1265 tmp.close_delay = info->close_delay;
1266 tmp.custom_divisor = 0; /*!!! */
1267 tmp.hub6 = 0; /*!!! */
1268 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1269} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001272set_serial_info(struct cyclades_port *info,
1273 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001275 struct serial_struct new_serial;
1276 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001279 if (!new_info)
1280 return -EFAULT;
1281 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1282 return -EFAULT;
1283 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001285 if (!capable(CAP_SYS_ADMIN)) {
1286 if ((new_serial.close_delay != info->close_delay) ||
1287 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1288 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1289 return -EPERM;
1290 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1291 (new_serial.flags & ASYNC_USR_MASK));
1292 goto check_and_exit;
1293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001295 /*
1296 * OK, past this point, all the error checking has been done.
1297 * At this point, we start making changes.....
1298 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001300 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1301 (new_serial.flags & ASYNC_FLAGS));
1302 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001305 if (info->flags & ASYNC_INITIALIZED) {
1306 config_setup(info);
1307 return 0;
1308 }
1309 return startup(info);
1310} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001312static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313{
Alan Coxc9f19e92009-01-02 13:47:26 +00001314 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001315 int channel;
1316 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1317 unsigned long flags;
1318 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001320 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001322 local_irq_save(flags);
1323 base_addr[CyCAR] = (u_char) channel;
1324 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1325 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001327 return ((status & CyRTS) ? TIOCM_RTS : 0)
1328 | ((status & CyDTR) ? TIOCM_DTR : 0)
1329 | ((status & CyDCD) ? TIOCM_CAR : 0)
1330 | ((status & CyDSR) ? TIOCM_DSR : 0)
1331 | ((status & CyCTS) ? TIOCM_CTS : 0);
1332} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334static int
1335cy_tiocmset(struct tty_struct *tty, struct file *file,
1336 unsigned int set, unsigned int clear)
1337{
Alan Coxc9f19e92009-01-02 13:47:26 +00001338 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001339 int channel;
1340 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1341 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001343 channel = info->line;
1344
1345 if (set & TIOCM_RTS) {
1346 local_irq_save(flags);
1347 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001349 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001351 if (set & TIOCM_DTR) {
1352 local_irq_save(flags);
1353 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001355 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001357 printk("cyc: %d: raising DTR\n", __LINE__);
1358 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1359 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001361 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 }
1363
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001364 if (clear & TIOCM_RTS) {
1365 local_irq_save(flags);
1366 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001368 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001370 if (clear & TIOCM_DTR) {
1371 local_irq_save(flags);
1372 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001374 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001376 printk("cyc: %d: dropping DTR\n", __LINE__);
1377 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1378 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001380 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
1382
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001383 return 0;
1384} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001386static void send_break(struct cyclades_port *info, int duration)
1387{ /* Let the transmit ISR take care of this (since it
1388 requires stuffing characters into the output stream).
1389 */
1390 info->x_break = duration;
1391 if (!info->xmit_cnt) {
1392 start_xmit(info);
1393 }
1394} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001397get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
1399
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001400 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1401 return -EFAULT;
1402 info->mon.int_count = 0;
1403 info->mon.char_count = 0;
1404 info->mon.char_max = 0;
1405 info->mon.char_last = 0;
1406 return 0;
1407}
1408
1409static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1410{
1411 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1412 unsigned long value;
1413 int channel;
1414
1415 if (get_user(value, arg))
1416 return -EFAULT;
1417
1418 channel = info->line;
1419 info->cor4 &= ~CyREC_FIFO;
1420 info->cor4 |= value & CyREC_FIFO;
1421 base_addr[CyCOR4] = info->cor4;
1422 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423}
1424
1425static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001426get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001428 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1429 int channel;
1430 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001432 channel = info->line;
1433
1434 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1435 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436}
1437
1438static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001439set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001441 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001443 if (get_user(value, arg))
1444 return -EFAULT;
1445
1446 info->default_threshold = value & 0x0f;
1447 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448}
1449
1450static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001451get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001453 return put_user(info->default_threshold, value);
1454}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001456static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1457{
1458 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1459 int channel;
1460 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001462 if (get_user(value, arg))
1463 return -EFAULT;
1464
1465 channel = info->line;
1466
1467 base_addr[CyRTPRL] = value & 0xff;
1468 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1469 return 0;
1470}
1471
1472static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1473{
1474 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1475 int channel;
1476 unsigned long tmp;
1477
1478 channel = info->line;
1479
1480 tmp = base_addr[CyRTPRL];
1481 return put_user(tmp, value);
1482}
1483
1484static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1485{
1486 info->default_timeout = value & 0xff;
1487 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488}
1489
1490static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001491get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001493 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494}
1495
1496static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001497cy_ioctl(struct tty_struct *tty, struct file *file,
1498 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Alan Coxc9f19e92009-01-02 13:47:26 +00001500 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001501 int ret_val = 0;
1502 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
1504#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001505 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506#endif
1507
Arnd Bergmannec79d602010-06-01 22:53:01 +02001508 tty_lock();
Alan Cox638157b2008-04-30 00:53:22 -07001509
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001510 switch (cmd) {
1511 case CYGETMON:
1512 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001514 case CYGETTHRESH:
1515 ret_val = get_threshold(info, argp);
1516 break;
1517 case CYSETTHRESH:
1518 ret_val = set_threshold(info, argp);
1519 break;
1520 case CYGETDEFTHRESH:
1521 ret_val = get_default_threshold(info, argp);
1522 break;
1523 case CYSETDEFTHRESH:
1524 ret_val = set_default_threshold(info, argp);
1525 break;
1526 case CYGETTIMEOUT:
1527 ret_val = get_timeout(info, argp);
1528 break;
1529 case CYSETTIMEOUT:
1530 ret_val = set_timeout(info, argp);
1531 break;
1532 case CYGETDEFTIMEOUT:
1533 ret_val = get_default_timeout(info, argp);
1534 break;
1535 case CYSETDEFTIMEOUT:
1536 ret_val = set_default_timeout(info, (unsigned long)arg);
1537 break;
1538 case TCSBRK: /* SVID version: non-zero arg --> no break */
1539 ret_val = tty_check_change(tty);
1540 if (ret_val)
1541 break;
1542 tty_wait_until_sent(tty, 0);
1543 if (!arg)
1544 send_break(info, HZ / 4); /* 1/4 second */
1545 break;
1546 case TCSBRKP: /* support for POSIX tcsendbreak() */
1547 ret_val = tty_check_change(tty);
1548 if (ret_val)
1549 break;
1550 tty_wait_until_sent(tty, 0);
1551 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1552 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001555 case TIOCGSERIAL:
1556 ret_val = get_serial_info(info, argp);
1557 break;
1558 case TIOCSSERIAL:
1559 ret_val = set_serial_info(info, argp);
1560 break;
1561 default:
1562 ret_val = -ENOIOCTLCMD;
1563 }
Arnd Bergmannec79d602010-06-01 22:53:01 +02001564 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001567 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568#endif
1569
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001570 return ret_val;
1571} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001573static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
Alan Coxc9f19e92009-01-02 13:47:26 +00001575 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
1577#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001578 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579#endif
1580
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001581 if (tty->termios->c_cflag == old_termios->c_cflag)
1582 return;
1583 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001585 if ((old_termios->c_cflag & CRTSCTS) &&
1586 !(tty->termios->c_cflag & CRTSCTS)) {
1587 tty->stopped = 0;
1588 cy_start(tty);
1589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001591 if (!(old_termios->c_cflag & CLOCAL) &&
1592 (tty->termios->c_cflag & CLOCAL))
1593 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001595} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001597static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598{
Alan Coxc9f19e92009-01-02 13:47:26 +00001599 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
1601/* CP('C'); */
1602#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001603 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604#endif
1605
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001606 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1607 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001609#ifdef SERIAL_DEBUG_OPEN
1610 printk("cy_close %s, count = %d\n", tty->name, info->count);
1611#endif
1612
1613 if ((tty->count == 1) && (info->count != 1)) {
1614 /*
1615 * Uh, oh. tty->count is 1, which means that the tty
1616 * structure will be freed. Info->count should always
1617 * be one in these conditions. If it's greater than
1618 * one, we've got real problems, since it means the
1619 * serial port won't be shutdown.
1620 */
1621 printk("cy_close: bad serial port count; tty->count is 1, "
1622 "info->count is %d\n", info->count);
1623 info->count = 1;
1624 }
1625#ifdef SERIAL_DEBUG_COUNT
1626 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1627 info->count - 1);
1628#endif
1629 if (--info->count < 0) {
1630 printk("cy_close: bad serial port count for ttys%d: %d\n",
1631 info->line, info->count);
1632#ifdef SERIAL_DEBUG_COUNT
1633 printk("cyc: %d: setting count to 0\n", __LINE__);
1634#endif
1635 info->count = 0;
1636 }
1637 if (info->count)
1638 return;
1639 info->flags |= ASYNC_CLOSING;
1640 if (info->flags & ASYNC_INITIALIZED)
1641 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1642 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -07001643 cy_flush_buffer(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001644 tty_ldisc_flush(tty);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001645 info->tty = NULL;
1646 if (info->blocked_open) {
1647 if (info->close_delay) {
1648 msleep_interruptible(jiffies_to_msecs
1649 (info->close_delay));
1650 }
1651 wake_up_interruptible(&info->open_wait);
1652 }
1653 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1654 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001657 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001659} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661/*
1662 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1663 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001664void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665{
Alan Coxc9f19e92009-01-02 13:47:26 +00001666 struct cyclades_port *info = tty->driver_data;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001669 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670#endif
1671
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001672 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1673 return;
1674
1675 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001677 info->event = 0;
1678 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001680 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001682 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001684 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1685 wake_up_interruptible(&info->open_wait);
1686} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688/*
1689 * ------------------------------------------------------------
1690 * cy_open() and friends
1691 * ------------------------------------------------------------
1692 */
1693
1694static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001695block_til_ready(struct tty_struct *tty, struct file *filp,
1696 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001698 DECLARE_WAITQUEUE(wait, current);
1699 unsigned long flags;
1700 int channel;
1701 int retval;
1702 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001704 /*
1705 * If the device is in the middle of being closed, then block
1706 * until it's done, and then try again.
1707 */
1708 if (info->flags & ASYNC_CLOSING) {
1709 interruptible_sleep_on(&info->close_wait);
1710 if (info->flags & ASYNC_HUP_NOTIFY) {
1711 return -EAGAIN;
1712 } else {
1713 return -ERESTARTSYS;
1714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001717 /*
1718 * If non-blocking mode is set, then make the check up front
1719 * and then exit.
1720 */
1721 if (filp->f_flags & O_NONBLOCK) {
1722 info->flags |= ASYNC_NORMAL_ACTIVE;
1723 return 0;
1724 }
1725
1726 /*
1727 * Block waiting for the carrier detect and the line to become
1728 * free (i.e., not in use by the callout). While we are in
1729 * this loop, info->count is dropped by one, so that
1730 * cy_close() knows when to free things. We restore it upon
1731 * exit, either normal or abnormal.
1732 */
1733 retval = 0;
1734 add_wait_queue(&info->open_wait, &wait);
1735#ifdef SERIAL_DEBUG_OPEN
1736 printk("block_til_ready before block: %s, count = %d\n",
1737 tty->name, info->count);
1738 /**/
1739#endif
1740 info->count--;
1741#ifdef SERIAL_DEBUG_COUNT
1742 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1743#endif
1744 info->blocked_open++;
1745
1746 channel = info->line;
1747
1748 while (1) {
1749 local_irq_save(flags);
1750 base_addr[CyCAR] = (u_char) channel;
1751 base_addr[CyMSVR1] = CyRTS;
1752/* CP('S');CP('4'); */
1753 base_addr[CyMSVR2] = CyDTR;
1754#ifdef SERIAL_DEBUG_DTR
1755 printk("cyc: %d: raising DTR\n", __LINE__);
1756 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1757 base_addr[CyMSVR2]);
1758#endif
1759 local_irq_restore(flags);
1760 set_current_state(TASK_INTERRUPTIBLE);
1761 if (tty_hung_up_p(filp)
1762 || !(info->flags & ASYNC_INITIALIZED)) {
1763 if (info->flags & ASYNC_HUP_NOTIFY) {
1764 retval = -EAGAIN;
1765 } else {
1766 retval = -ERESTARTSYS;
1767 }
1768 break;
1769 }
1770 local_irq_save(flags);
1771 base_addr[CyCAR] = (u_char) channel;
1772/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1773 if (!(info->flags & ASYNC_CLOSING)
1774 && (C_CLOCAL(tty)
1775 || (base_addr[CyMSVR1] & CyDCD))) {
1776 local_irq_restore(flags);
1777 break;
1778 }
1779 local_irq_restore(flags);
1780 if (signal_pending(current)) {
1781 retval = -ERESTARTSYS;
1782 break;
1783 }
1784#ifdef SERIAL_DEBUG_OPEN
1785 printk("block_til_ready blocking: %s, count = %d\n",
1786 tty->name, info->count);
1787 /**/
1788#endif
Arnd Bergmanne142a312010-06-01 22:53:10 +02001789 tty_unlock();
1790 schedule();
1791 tty_lock();
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001792 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001793 __set_current_state(TASK_RUNNING);
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001794 remove_wait_queue(&info->open_wait, &wait);
1795 if (!tty_hung_up_p(filp)) {
1796 info->count++;
1797#ifdef SERIAL_DEBUG_COUNT
1798 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1799 info->count);
1800#endif
1801 }
1802 info->blocked_open--;
1803#ifdef SERIAL_DEBUG_OPEN
1804 printk("block_til_ready after blocking: %s, count = %d\n",
1805 tty->name, info->count);
1806 /**/
1807#endif
1808 if (retval)
1809 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 info->flags |= ASYNC_NORMAL_ACTIVE;
1811 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001812} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
1814/*
1815 * This routine is called whenever a serial port is opened. It
1816 * performs the serial-specific initialization for the tty structure.
1817 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001818int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001820 struct cyclades_port *info;
1821 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
1823/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001824 line = tty->index;
1825 if ((line < 0) || (NR_PORTS <= line)) {
1826 return -ENODEV;
1827 }
1828 info = &cy_port[line];
1829 if (info->line < 0) {
1830 return -ENODEV;
1831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001833 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001835 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1836 return -ENODEV;
1837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001839 printk("cy_open %s, count = %d\n", tty->name, info->count);
1840 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001842 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001844 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001846 tty->driver_data = info;
1847 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001849 /*
1850 * Start up serial port
1851 */
1852 retval = startup(info);
1853 if (retval) {
1854 return retval;
1855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001857 retval = block_til_ready(tty, filp, info);
1858 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001860 printk("cy_open returning after block_til_ready with %d\n",
1861 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001863 return retval;
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001866 printk("cy_open done\n");
1867 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001869 return 0;
1870} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872/*
1873 * ---------------------------------------------------------------------
1874 * serial167_init() and friends
1875 *
1876 * serial167_init() is called at boot-time to initialize the serial driver.
1877 * ---------------------------------------------------------------------
1878 */
1879
1880/*
1881 * This routine prints out the appropriate serial driver version
1882 * number, and identifies which options were configured into this
1883 * driver.
1884 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001885static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001887 printk("MVME166/167 cd2401 driver\n");
1888} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890/* initialize chips on card -- return number of valid
1891 chips (which is number of ports/4) */
1892
1893/*
1894 * This initialises the hardware to a reasonable state. It should
1895 * probe the chip first so as to copy 166-Bug setup as a default for
1896 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1897 * as to limit the number of CyINIT_CHAN commands in normal running.
1898 *
1899 * ... I wonder what I should do if this fails ...
1900 */
1901
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001902void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001904 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 int ch;
1906 u_char spd;
1907 u_char rcor, rbpr, badspeed = 0;
1908 unsigned long flags;
1909
1910 local_irq_save(flags);
1911
1912 /*
1913 * First probe channel zero of the chip, to see what speed has
1914 * been selected.
1915 */
1916
1917 base_addr[CyCAR] = 0;
1918
1919 rcor = base_addr[CyRCOR] << 5;
1920 rbpr = base_addr[CyRBPR];
1921
1922 for (spd = 0; spd < sizeof(baud_bpr); spd++)
1923 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
1924 break;
1925 if (spd >= sizeof(baud_bpr)) {
1926 spd = 14; /* 19200 */
1927 badspeed = 1; /* Failed to identify speed */
1928 }
1929 initial_console_speed = spd;
1930
1931 /* OK, we have chosen a speed, now reset and reinitialise */
1932
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001933 my_udelay(20000L); /* Allow time for any active o/p to complete */
1934 if (base_addr[CyCCR] != 0x00) {
1935 local_irq_restore(flags);
1936 /* printk(" chip is never idle (CCR != 0)\n"); */
1937 return;
1938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001940 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
1941 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001943 if (base_addr[CyGFRCR] == 0x00) {
1944 local_irq_restore(flags);
1945 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
1946 return;
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949 /*
1950 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
1951 * tick
1952 */
1953
1954 base_addr[CyTPR] = 10;
1955
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001956 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
1957 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
1958 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
1960 /*
1961 * Attempt to set up all channels to something reasonable, and
1962 * bang out a INIT_CHAN command. We should then be able to limit
Uwe Kleine-König9ddc5b62010-01-20 17:02:24 +01001963 * the amount of fiddling we have to do in normal running.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 */
1965
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001966 for (ch = 3; ch >= 0; ch--) {
1967 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 base_addr[CyIER] = 0;
1969 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001970 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 base_addr[CyLIVR] = 0x5c;
1972 base_addr[CyTCOR] = baud_co[spd];
1973 base_addr[CyTBPR] = baud_bpr[spd];
1974 base_addr[CyRCOR] = baud_co[spd] >> 5;
1975 base_addr[CyRBPR] = baud_bpr[spd];
1976 base_addr[CySCHR1] = 'Q' & 0x1f;
1977 base_addr[CySCHR2] = 'X' & 0x1f;
1978 base_addr[CySCRL] = 0;
1979 base_addr[CySCRH] = 0;
1980 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
1981 base_addr[CyCOR2] = 0;
1982 base_addr[CyCOR3] = Cy_1_STOP;
1983 base_addr[CyCOR4] = baud_cor4[spd];
1984 base_addr[CyCOR5] = 0;
1985 base_addr[CyCOR6] = 0;
1986 base_addr[CyCOR7] = 0;
1987 base_addr[CyRTPRL] = 2;
1988 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001989 base_addr[CyMSVR1] = 0;
1990 base_addr[CyMSVR2] = 0;
1991 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 }
1993
1994 /*
1995 * Now do specials for channel zero....
1996 */
1997
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001998 base_addr[CyMSVR1] = CyRTS;
1999 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002001 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
2003 local_irq_restore(flags);
2004
2005 my_udelay(20000L); /* Let it all settle down */
2006
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002007 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002009 printk
2010 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2011 rcor >> 5, rbpr);
2012} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002014static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 .open = cy_open,
2016 .close = cy_close,
2017 .write = cy_write,
2018 .put_char = cy_put_char,
2019 .flush_chars = cy_flush_chars,
2020 .write_room = cy_write_room,
2021 .chars_in_buffer = cy_chars_in_buffer,
2022 .flush_buffer = cy_flush_buffer,
2023 .ioctl = cy_ioctl,
2024 .throttle = cy_throttle,
2025 .unthrottle = cy_unthrottle,
2026 .set_termios = cy_set_termios,
2027 .stop = cy_stop,
2028 .start = cy_start,
2029 .hangup = cy_hangup,
2030 .tiocmget = cy_tiocmget,
2031 .tiocmset = cy_tiocmset,
2032};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002033
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034/* The serial driver boot-time initialization code!
2035 Hardware I/O ports are mapped to character special devices on a
2036 first found, first allocated manner. That is, this code searches
2037 for Cyclom cards in the system. As each is found, it is probed
2038 to discover how many chips (and thus how many ports) are present.
2039 These ports are mapped to the tty ports 64 and upward in monotonic
2040 fashion. If an 8-port card is replaced with a 16-port card, the
2041 port mapping on a following card will shift.
2042
2043 This approach is different from what is used in the other serial
2044 device driver because the Cyclom is more properly a multiplexer,
2045 not just an aggregation of serial ports on one card.
2046
2047 If there are more cards with more ports than have been statically
2048 allocated above, a warning is printed and the extra ports are ignored.
2049 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002050static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002052 struct cyclades_port *info;
2053 int ret = 0;
2054 int good_ports = 0;
2055 int port_num = 0;
2056 int index;
2057 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002059 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060#endif
2061
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002062 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2063 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002065 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2066 if (!cy_serial_driver)
2067 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002070 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071#endif
2072
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002073 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002075 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2076 if (serial_console_cflag)
2077 DefSpeed = serial_console_cflag & 0017;
2078 else {
2079 DefSpeed = initial_console_speed;
2080 serial_console_info = &cy_port[0];
2081 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002083 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002086
2087 /* Initialize the tty_driver structure */
2088
2089 cy_serial_driver->owner = THIS_MODULE;
2090 cy_serial_driver->name = "ttyS";
2091 cy_serial_driver->major = TTY_MAJOR;
2092 cy_serial_driver->minor_start = 64;
2093 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2094 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2095 cy_serial_driver->init_termios = tty_std_termios;
2096 cy_serial_driver->init_termios.c_cflag =
2097 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2098 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2099 tty_set_operations(cy_serial_driver, &cy_ops);
2100
2101 ret = tty_register_driver(cy_serial_driver);
2102 if (ret) {
2103 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2104 put_tty_driver(cy_serial_driver);
2105 return ret;
2106 }
2107
2108 port_num = 0;
2109 info = cy_port;
2110 for (index = 0; index < 1; index++) {
2111
2112 good_ports = 4;
2113
2114 if (port_num < NR_PORTS) {
2115 while (good_ports-- && port_num < NR_PORTS) {
2116 /*** initialize port ***/
2117 info->magic = CYCLADES_MAGIC;
2118 info->type = PORT_CIRRUS;
2119 info->card = index;
2120 info->line = port_num;
2121 info->flags = STD_COM_FLAGS;
2122 info->tty = NULL;
2123 info->xmit_fifo_size = 12;
2124 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2125 info->cor2 = CyETC;
2126 info->cor3 = Cy_1_STOP;
2127 info->cor4 = 0x08; /* _very_ small receive threshold */
2128 info->cor5 = 0;
2129 info->cor6 = 0;
2130 info->cor7 = 0;
2131 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2132 info->tco = baud_co[DefSpeed]; /* Tx CO */
2133 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2134 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2135 info->close_delay = 0;
2136 info->x_char = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002137 info->count = 0;
2138#ifdef SERIAL_DEBUG_COUNT
2139 printk("cyc: %d: setting count to 0\n",
2140 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002142 info->blocked_open = 0;
2143 info->default_threshold = 0;
2144 info->default_timeout = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002145 init_waitqueue_head(&info->open_wait);
2146 init_waitqueue_head(&info->close_wait);
2147 /* info->session */
2148 /* info->pgrp */
2149/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2150 info->read_status_mask =
2151 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2152 CyFRAME | CyOVERRUN;
2153 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002155 printk("ttyS%d ", info->line);
2156 port_num++;
2157 info++;
2158 if (!(port_num & 7)) {
2159 printk("\n ");
2160 }
2161 }
2162 }
2163 printk("\n");
2164 }
2165 while (port_num < NR_PORTS) {
2166 info->line = -1;
2167 port_num++;
2168 info++;
2169 }
Christoph Egger0dbb5672010-05-17 17:25:54 +02002170
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002171 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2172 "cd2401_errors", cd2401_rxerr_interrupt);
2173 if (ret) {
2174 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2175 goto cleanup_serial_driver;
2176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002178 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2179 "cd2401_modem", cd2401_modem_interrupt);
2180 if (ret) {
2181 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2182 goto cleanup_irq_cd2401_errors;
2183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002185 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2186 "cd2401_txints", cd2401_tx_interrupt);
2187 if (ret) {
2188 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2189 goto cleanup_irq_cd2401_modem;
2190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002192 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2193 "cd2401_rxints", cd2401_rx_interrupt);
2194 if (ret) {
2195 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2196 goto cleanup_irq_cd2401_txints;
2197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002199 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002201 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2202 pcc2chip[PccSCCTICR] = 0x15;
2203 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002205 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2206
2207 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002209 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002211 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002213 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002215 if (tty_unregister_driver(cy_serial_driver))
2216 printk(KERN_ERR
2217 "Couldn't unregister MVME166/7 serial driver\n");
2218 put_tty_driver(cy_serial_driver);
2219 return ret;
2220} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222module_init(serial167_init);
2223
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002225static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002227 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2228 int channel;
2229 struct cyclades_port *info;
2230 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002232 info = &cy_port[line_num];
2233 channel = info->line;
2234 printk(" channel %d\n", channel);
2235 /**/ printk(" cy_port\n");
2236 printk(" card line flags = %d %d %x\n",
2237 info->card, info->line, info->flags);
2238 printk
2239 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2240 (long)info->tty, info->read_status_mask, info->timeout,
2241 info->xmit_fifo_size);
2242 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2243 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2244 info->cor6, info->cor7);
2245 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2246 info->rbpr, info->rco);
2247 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2248 info->event, info->count);
2249 printk(" x_char blocked_open = %x %x\n", info->x_char,
2250 info->blocked_open);
2251 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002253 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255/* Global Registers */
2256
2257 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2258 printk(" CyCAR %x\n", base_addr[CyCAR]);
2259 printk(" CyRISR %x\n", base_addr[CyRISR]);
2260 printk(" CyTISR %x\n", base_addr[CyTISR]);
2261 printk(" CyMISR %x\n", base_addr[CyMISR]);
2262 printk(" CyRIR %x\n", base_addr[CyRIR]);
2263 printk(" CyTIR %x\n", base_addr[CyTIR]);
2264 printk(" CyMIR %x\n", base_addr[CyMIR]);
2265 printk(" CyTPR %x\n", base_addr[CyTPR]);
2266
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002267 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
2269/* Virtual Registers */
2270
2271#if 0
2272 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2273 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2274 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2275 printk(" CyMISR %x\n", base_addr[CyMISR]);
2276#endif
2277
2278/* Channel Registers */
2279
2280 printk(" CyCCR %x\n", base_addr[CyCCR]);
2281 printk(" CyIER %x\n", base_addr[CyIER]);
2282 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2283 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2284 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2285 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2286 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2287#if 0
2288 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2289 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2290#endif
2291 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2292 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2293#if 0
2294 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2295 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2296 printk(" CySCRL %x\n", base_addr[CySCRL]);
2297 printk(" CySCRH %x\n", base_addr[CySCRH]);
2298 printk(" CyLNC %x\n", base_addr[CyLNC]);
2299 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2300 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2301#endif
2302 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2303 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2304 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2305 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2306 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2307 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2308 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2309 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2310
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002311 local_irq_restore(flags);
2312} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313#endif
2314
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315#if 0
2316/* Dummy routine in mvme16x/config.c for now */
2317
2318/* Serial console setup. Called from linux/init/main.c */
2319
2320void console_setup(char *str, int *ints)
2321{
2322 char *s;
2323 int baud, bits, parity;
2324 int cflag = 0;
2325
2326 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002327 if (ints[0] > 3 || ints[1] > 3)
2328 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
2330 /* Get baud, bits and parity */
2331 baud = 2400;
2332 bits = 8;
2333 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002334 if (ints[2])
2335 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 if ((s = strchr(str, ','))) {
2337 do {
2338 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002339 } while (*s >= '0' && *s <= '9');
2340 if (*s)
2341 parity = *s++;
2342 if (*s)
2343 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 }
2345
2346 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002347 switch (baud) {
2348 case 1200:
2349 cflag |= B1200;
2350 break;
2351 case 9600:
2352 cflag |= B9600;
2353 break;
2354 case 19200:
2355 cflag |= B19200;
2356 break;
2357 case 38400:
2358 cflag |= B38400;
2359 break;
2360 case 2400:
2361 default:
2362 cflag |= B2400;
2363 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002365 switch (bits) {
2366 case 7:
2367 cflag |= CS7;
2368 break;
2369 default:
2370 case 8:
2371 cflag |= CS8;
2372 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002374 switch (parity) {
2375 case 'o':
2376 case 'O':
2377 cflag |= PARODD;
2378 break;
2379 case 'e':
2380 case 'E':
2381 cflag |= PARENB;
2382 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 }
2384
2385 serial_console_info = &cy_port[ints[1]];
2386 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002387 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388}
2389#endif
2390
2391/*
2392 * The following is probably out of date for 2.1.x serial console stuff.
2393 *
2394 * The console is registered early on from arch/m68k/kernel/setup.c, and
2395 * it therefore relies on the chip being setup correctly by 166-Bug. This
2396 * seems reasonable, as the serial port has been used to invoke the system
2397 * boot. It also means that this function must not rely on any data
2398 * initialisation performed by serial167_init() etc.
2399 *
2400 * Of course, once the console has been registered, we had better ensure
2401 * that serial167_init() doesn't leave the chip non-functional.
2402 *
2403 * The console must be locked when we get here.
2404 */
2405
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002406void serial167_console_write(struct console *co, const char *str,
2407 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002409 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 unsigned long flags;
2411 volatile u_char sink;
2412 u_char ier;
2413 int port;
2414 u_char do_lf = 0;
2415 int i = 0;
2416
2417 local_irq_save(flags);
2418
2419 /* Ensure transmitter is enabled! */
2420
2421 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002422 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 while (base_addr[CyCCR])
2424 ;
2425 base_addr[CyCCR] = CyENB_XMTR;
2426
2427 ier = base_addr[CyIER];
2428 base_addr[CyIER] = CyTxMpty;
2429
2430 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002431 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 /* We have a Tx int. Acknowledge it */
2433 sink = pcc2chip[PccTPIACKR];
2434 if ((base_addr[CyLICR] >> 2) == port) {
2435 if (i == count) {
2436 /* Last char of string is now output */
2437 base_addr[CyTEOIR] = CyNOTRANS;
2438 break;
2439 }
2440 if (do_lf) {
2441 base_addr[CyTDR] = '\n';
2442 str++;
2443 i++;
2444 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002445 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 base_addr[CyTDR] = '\r';
2447 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002448 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 base_addr[CyTDR] = *str++;
2450 i++;
2451 }
2452 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002453 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 base_addr[CyTEOIR] = CyNOTRANS;
2455 }
2456 }
2457
2458 base_addr[CyIER] = ier;
2459
2460 local_irq_restore(flags);
2461}
2462
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002463static struct tty_driver *serial167_console_device(struct console *c,
2464 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465{
2466 *index = c->index;
2467 return cy_serial_driver;
2468}
2469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002471 .name = "ttyS",
2472 .write = serial167_console_write,
2473 .device = serial167_console_device,
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002474 .flags = CON_PRINTBUFFER,
2475 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476};
2477
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478static int __init serial167_console_init(void)
2479{
2480 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002481 vme_brdtype == VME_TYPE_MVME167 ||
2482 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 mvme167_serial_console_setup(0);
2484 register_console(&sercons);
2485 }
2486 return 0;
2487}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002488
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489console_initcall(serial167_console_init);
2490
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491MODULE_LICENSE("GPL");