blob: 5fd314adc1f28d864805bea180d2f87a77d06741 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/char/serial167.c
3 *
4 * Driver for MVME166/7 board serial ports, which are via a CD2401.
5 * Based very much on cyclades.c.
6 *
7 * MVME166/7 work by Richard Hirst [richard@sleepie.demon.co.uk]
8 *
9 * ==============================================================
10 *
11 * static char rcsid[] =
12 * "$Revision: 1.36.1.4 $$Date: 1995/03/29 06:14:14 $";
13 *
14 * linux/kernel/cyclades.c
15 *
16 * Maintained by Marcio Saito (cyclades@netcom.com) and
17 * Randolph Bentson (bentson@grieg.seaslug.org)
18 *
19 * Much of the design and some of the code came from serial.c
20 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
21 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
22 * and then fixed as suggested by Michael K. Johnson 12/12/92.
23 *
24 * This version does not support shared irq's.
25 *
26 * $Log: cyclades.c,v $
27 * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
28 * disambiguate between Cyclom-16Y and Cyclom-32Ye;
29 *
30 * Changes:
31 *
32 * 200 lines of changes record removed - RGH 11-10-95, starting work on
33 * converting this to drive serial ports on mvme166 (cd2401).
34 *
35 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/08/25
36 * - get rid of verify_area
37 * - use get_user to access memory from userspace in set_threshold,
38 * set_default_threshold and set_timeout
39 * - don't use the panic function in serial167_init
40 * - do resource release on failure on serial167_init
41 * - include missing restore_flags in mvme167_serial_console_setup
42 *
43 * Kars de Jong <jongk@linux-m68k.org> - 2004/09/06
44 * - replace bottom half handler with task queue handler
45 */
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/errno.h>
48#include <linux/signal.h>
49#include <linux/sched.h>
50#include <linux/timer.h>
51#include <linux/tty.h>
52#include <linux/interrupt.h>
53#include <linux/serial.h>
54#include <linux/serialP.h>
55#include <linux/string.h>
56#include <linux/fcntl.h>
57#include <linux/ptrace.h>
58#include <linux/serial167.h>
59#include <linux/delay.h>
60#include <linux/major.h>
61#include <linux/mm.h>
62#include <linux/console.h>
63#include <linux/module.h>
64#include <linux/bitops.h>
Geert Uytterhoeven81e859a2006-10-09 22:27:42 +020065#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include <asm/system.h>
68#include <asm/io.h>
69#include <asm/mvme16xhw.h>
70#include <asm/bootinfo.h>
71#include <asm/setup.h>
72
73#include <linux/types.h>
74#include <linux/kernel.h>
75
76#include <asm/uaccess.h>
77#include <linux/init.h>
78
79#define SERIAL_PARANOIA_CHECK
80#undef SERIAL_DEBUG_OPEN
81#undef SERIAL_DEBUG_THROTTLE
82#undef SERIAL_DEBUG_OTHER
83#undef SERIAL_DEBUG_IO
84#undef SERIAL_DEBUG_COUNT
85#undef SERIAL_DEBUG_DTR
86#undef CYCLOM_16Y_HACK
87#define CYCLOM_ENABLE_MONITORING
88
89#define WAKEUP_CHARS 256
90
91#define STD_COM_FLAGS (0)
92
93#define SERIAL_TYPE_NORMAL 1
94
95static 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 *);
175extern void console_print(const char *);
176#ifdef CYCLOM_SHOW_STATUS
177static void show_status(int);
178#endif
179
180#ifdef CONFIG_REMOTE_DEBUG
181static void debug_setup(void);
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800182void queueDebugChar(int c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183int getDebugChar(void);
184
185#define DEBUG_PORT 1
186#define DEBUG_LEN 256
187
188typedef struct {
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800189 int in;
190 int out;
191 unsigned char buf[DEBUG_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192} debugq;
193
194debugq debugiq;
195#endif
196
197/*
198 * I have my own version of udelay(), as it is needed when initialising
199 * the chip, before the delay loop has been calibrated. Should probably
200 * reference one of the vmechip2 or pccchip2 counter for an accurate
201 * delay, but this wild guess will do for now.
202 */
203
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800204void my_udelay(long us)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
206 u_char x;
207 volatile u_char *p = &x;
208 int i;
209
210 while (us--)
211 for (i = 100; i; i--)
212 x |= *p;
213}
214
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800215static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
216 const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800219 if (!info) {
220 printk("Warning: null cyclades_port for (%s) in %s\n", name,
221 routine);
222 return 1;
223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800225 if ((long)info < (long)(&cy_port[0])
226 || (long)(&cy_port[NR_PORTS]) < (long)info) {
227 printk("Warning: cyclades_port out of range for (%s) in %s\n",
228 name, routine);
229 return 1;
230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800232 if (info->magic != CYCLADES_MAGIC) {
233 printk("Warning: bad magic number for serial struct (%s) in "
234 "%s\n", name, routine);
235 return 1;
236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237#endif
238 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800239} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
241#if 0
242/* The following diagnostic routines allow the driver to spew
243 information on the screen, even (especially!) during interrupts.
244 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800245void SP(char *data)
246{
247 unsigned long flags;
248 local_irq_save(flags);
249 console_print(data);
250 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800253char scrn[2];
254void CP(char data)
255{
256 unsigned long flags;
257 local_irq_save(flags);
258 scrn[0] = data;
259 console_print(scrn);
260 local_irq_restore(flags);
261} /* CP */
262
263void CP1(int data)
264{
265 (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
266} /* CP1 */
267void CP2(int data)
268{
269 CP1((data >> 4) & 0x0f);
270 CP1(data & 0x0f);
271} /* CP2 */
272void CP4(int data)
273{
274 CP2((data >> 8) & 0xff);
275 CP2(data & 0xff);
276} /* CP4 */
277void CP8(long data)
278{
279 CP4((data >> 16) & 0xffff);
280 CP4(data & 0xffff);
281} /* CP8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282#endif
283
284/* This routine waits up to 1000 micro-seconds for the previous
285 command to the Cirrus chip to complete and then issues the
286 new command. An error is returned if the previous command
287 didn't finish within the time limit.
288 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800289u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800291 unsigned long flags;
292 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800294 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 /* Check to see that the previous command has completed */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800296 for (i = 0; i < 100; i++) {
297 if (base_addr[CyCCR] == 0) {
298 break;
299 }
300 my_udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302 /* if the CCR never cleared, the previous command
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800303 didn't finish within the "reasonable time" */
304 if (i == 10) {
305 local_irq_restore(flags);
306 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 }
308
309 /* Issue the new command */
310 base_addr[CyCCR] = cmd;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800311 local_irq_restore(flags);
312 return (0);
313} /* write_cy_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315/* cy_start and cy_stop provide software output flow control as a
316 function of XON/XOFF, software CTS, and other such stuff. */
317
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800318static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800320 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
321 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
322 int channel;
323 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800326 printk("cy_stop %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327#endif
328
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800329 if (serial_paranoia_check(info, tty->name, "cy_stop"))
330 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800332 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800334 local_irq_save(flags);
335 base_addr[CyCAR] = (u_char) (channel); /* index channel */
336 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
337 local_irq_restore(flags);
338} /* cy_stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800340static void cy_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800342 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
343 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
344 int channel;
345 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800348 printk("cy_start %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349#endif
350
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800351 if (serial_paranoia_check(info, tty->name, "cy_start"))
352 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800354 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800356 local_irq_save(flags);
357 base_addr[CyCAR] = (u_char) (channel);
358 base_addr[CyIER] |= CyTxMpty;
359 local_irq_restore(flags);
360} /* cy_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362/*
363 * This routine is used by the interrupt handler to schedule
364 * processing in the software interrupt portion of the driver
365 * (also known as the "bottom half"). This can be called any
366 * number of times for any channel without harm.
367 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800368static inline void cy_sched_event(struct cyclades_port *info, int event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800370 info->event |= 1 << event; /* remember what kind of event and who */
371 schedule_work(&info->tqueue);
372} /* cy_sched_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374/* The real interrupt service routines are called
375 whenever the card wants its hand held--chars
376 received, out buffer empty, modem change, etc.
377 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800378static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800380 struct tty_struct *tty;
381 struct cyclades_port *info;
382 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
383 unsigned char err, rfoc;
384 int channel;
385 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800387 /* determine the channel and change to that context */
388 channel = (u_short) (base_addr[CyLICR] >> 2);
389 info = &cy_port[channel];
390 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800392 if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
393 /* This is a receive timeout interrupt, ignore it */
394 base_addr[CyREOIR] = CyNOTRANS;
395 return IRQ_HANDLED;
396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800398 /* Read a byte of data if there is any - assume the error
399 * is associated with this character */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800401 if ((rfoc = base_addr[CyRFOC]) != 0)
402 data = base_addr[CyRDR];
403 else
404 data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800406 /* if there is nowhere to put the data, discard it */
407 if (info->tty == 0) {
408 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
409 return IRQ_HANDLED;
410 } else { /* there is an open port for this data */
411 tty = info->tty;
412 if (err & info->ignore_status_mask) {
413 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
414 return IRQ_HANDLED;
415 }
416 if (tty_buffer_request_room(tty, 1) != 0) {
417 if (err & info->read_status_mask) {
418 if (err & CyBREAK) {
419 tty_insert_flip_char(tty, data,
420 TTY_BREAK);
421 if (info->flags & ASYNC_SAK) {
422 do_SAK(tty);
423 }
424 } else if (err & CyFRAME) {
425 tty_insert_flip_char(tty, data,
426 TTY_FRAME);
427 } else if (err & CyPARITY) {
428 tty_insert_flip_char(tty, data,
429 TTY_PARITY);
430 } else if (err & CyOVERRUN) {
431 tty_insert_flip_char(tty, 0,
432 TTY_OVERRUN);
433 /*
434 If the flip buffer itself is
435 overflowing, we still loose
436 the next incoming character.
437 */
438 if (tty_buffer_request_room(tty, 1) !=
439 0) {
440 tty_insert_flip_char(tty, data,
441 TTY_FRAME);
442 }
443 /* These two conditions may imply */
444 /* a normal read should be done. */
445 /* else if(data & CyTIMEOUT) */
446 /* else if(data & CySPECHAR) */
447 } else {
448 tty_insert_flip_char(tty, 0,
449 TTY_NORMAL);
450 }
451 } else {
452 tty_insert_flip_char(tty, data, TTY_NORMAL);
453 }
454 } else {
455 /* there was a software buffer overrun
456 and nothing could be done about it!!! */
457 }
458 }
459 tty_schedule_flip(tty);
460 /* end of service */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
462 return IRQ_HANDLED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800463} /* cy_rxerr_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800465static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800467 struct cyclades_port *info;
468 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
469 int channel;
470 int mdm_change;
471 int mdm_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800473 /* determine the channel and change to that context */
474 channel = (u_short) (base_addr[CyLICR] >> 2);
475 info = &cy_port[channel];
476 info->last_active = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800478 mdm_change = base_addr[CyMISR];
479 mdm_status = base_addr[CyMSVR1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800481 if (info->tty == 0) { /* nowhere to put the data, ignore it */
482 ;
483 } else {
484 if ((mdm_change & CyDCD)
485 && (info->flags & ASYNC_CHECK_CD)) {
486 if (mdm_status & CyDCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487/* CP('!'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800488 cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
489 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490/* CP('@'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800491 cy_sched_event(info, Cy_EVENT_HANGUP);
492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800494 if ((mdm_change & CyCTS)
495 && (info->flags & ASYNC_CTS_FLOW)) {
496 if (info->tty->stopped) {
497 if (mdm_status & CyCTS) {
498 /* !!! cy_start isn't used because... */
499 info->tty->stopped = 0;
500 base_addr[CyIER] |= CyTxMpty;
501 cy_sched_event(info,
502 Cy_EVENT_WRITE_WAKEUP);
503 }
504 } else {
505 if (!(mdm_status & CyCTS)) {
506 /* !!! cy_stop isn't used because... */
507 info->tty->stopped = 1;
508 base_addr[CyIER] &=
509 ~(CyTxMpty | CyTxRdy);
510 }
511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800513 if (mdm_status & CyDSR) {
514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800516 base_addr[CyMEOIR] = 0;
517 return IRQ_HANDLED;
518} /* cy_modem_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800520static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800522 struct cyclades_port *info;
523 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
524 int channel;
525 int char_count, saved_cnt;
526 int outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800528 /* determine the channel and change to that context */
529 channel = (u_short) (base_addr[CyLICR] >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800532 if (channel == DEBUG_PORT) {
533 panic("TxInt on debug port!!!");
534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535#endif
536
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800537 info = &cy_port[channel];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800539 /* validate the port number (as configured and open) */
540 if ((channel < 0) || (NR_PORTS <= channel)) {
541 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
542 base_addr[CyTEOIR] = CyNOTRANS;
543 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800545 info->last_active = jiffies;
546 if (info->tty == 0) {
547 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
548 if (info->xmit_cnt < WAKEUP_CHARS) {
549 cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
550 }
551 base_addr[CyTEOIR] = CyNOTRANS;
552 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800554
555 /* load the on-chip space available for outbound data */
556 saved_cnt = char_count = base_addr[CyTFTC];
557
558 if (info->x_char) { /* send special char */
559 outch = info->x_char;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 base_addr[CyTDR] = outch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 char_count--;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800562 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800565 if (info->x_break) {
566 /* The Cirrus chip requires the "Embedded Transmit
567 Commands" of start break, delay, and end break
568 sequences to be sent. The duration of the
569 break is given in TICs, which runs at HZ
570 (typically 100) and the PPR runs at 200 Hz,
571 so the delay is duration * 200/HZ, and thus a
572 break can run from 1/100 sec to about 5/4 sec.
573 Need to check these values - RGH 141095.
574 */
575 base_addr[CyTDR] = 0; /* start break */
576 base_addr[CyTDR] = 0x81;
577 base_addr[CyTDR] = 0; /* delay a bit */
578 base_addr[CyTDR] = 0x82;
579 base_addr[CyTDR] = info->x_break * 200 / HZ;
580 base_addr[CyTDR] = 0; /* terminate break */
581 base_addr[CyTDR] = 0x83;
582 char_count -= 7;
583 info->x_break = 0;
584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800586 while (char_count > 0) {
587 if (!info->xmit_cnt) {
588 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
589 break;
590 }
591 if (info->xmit_buf == 0) {
592 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
593 break;
594 }
595 if (info->tty->stopped || info->tty->hw_stopped) {
596 base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
597 break;
598 }
599 /* Because the Embedded Transmit Commands have been
600 enabled, we must check to see if the escape
601 character, NULL, is being sent. If it is, we
602 must ensure that there is room for it to be
603 doubled in the output stream. Therefore we
604 no longer advance the pointer when the character
605 is fetched, but rather wait until after the check
606 for a NULL output character. (This is necessary
607 because there may not be room for the two chars
608 needed to send a NULL.
609 */
610 outch = info->xmit_buf[info->xmit_tail];
611 if (outch) {
612 info->xmit_cnt--;
613 info->xmit_tail = (info->xmit_tail + 1)
614 & (PAGE_SIZE - 1);
615 base_addr[CyTDR] = outch;
616 char_count--;
617 } else {
618 if (char_count > 1) {
619 info->xmit_cnt--;
620 info->xmit_tail = (info->xmit_tail + 1)
621 & (PAGE_SIZE - 1);
622 base_addr[CyTDR] = outch;
623 base_addr[CyTDR] = 0;
624 char_count--;
625 char_count--;
626 } else {
627 break;
628 }
629 }
630 }
631
632 if (info->xmit_cnt < WAKEUP_CHARS) {
633 cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
634 }
635 base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
636 return IRQ_HANDLED;
637} /* cy_tx_interrupt */
638
639static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800641 struct tty_struct *tty;
642 struct cyclades_port *info;
643 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
644 int channel;
645 char data;
646 int char_count;
647 int save_cnt;
648 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800650 /* determine the channel and change to that context */
651 channel = (u_short) (base_addr[CyLICR] >> 2);
652 info = &cy_port[channel];
653 info->last_active = jiffies;
654 save_cnt = char_count = base_addr[CyRFOC];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800657 if (channel == DEBUG_PORT) {
658 while (char_count--) {
659 data = base_addr[CyRDR];
660 queueDebugChar(data);
661 }
662 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800664 /* if there is nowhere to put the data, discard it */
665 if (info->tty == 0) {
666 while (char_count--) {
667 data = base_addr[CyRDR];
668 }
669 } else { /* there is an open port for this data */
670 tty = info->tty;
671 /* load # characters available from the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
673#ifdef CYCLOM_ENABLE_MONITORING
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800674 ++info->mon.int_count;
675 info->mon.char_count += char_count;
676 if (char_count > info->mon.char_max)
677 info->mon.char_max = char_count;
678 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800680 len = tty_buffer_request_room(tty, char_count);
681 while (len--) {
682 data = base_addr[CyRDR];
683 tty_insert_flip_char(tty, data, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684#ifdef CYCLOM_16Y_HACK
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800685 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800687 }
688 tty_schedule_flip(tty);
689 }
690 /* end of service */
691 base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
692 return IRQ_HANDLED;
693} /* cy_rx_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695/*
696 * This routine is used to handle the "bottom half" processing for the
697 * serial driver, known also the "software interrupt" processing.
698 * This processing is done at the kernel interrupt level, after the
699 * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
700 * is where time-consuming activities which can not be done in the
701 * interrupt driver proper are done; the interrupt driver schedules
702 * them using cy_sched_event(), and they get done here.
703 *
704 * This is done through one level of indirection--the task queue.
705 * When a hardware interrupt service routine wants service by the
706 * driver's bottom half, it enqueues the appropriate tq_struct (one
707 * per port) to the keventd work queue and sets a request flag
708 * that the work queue be processed.
709 *
710 * Although this may seem unwieldy, it gives the system a way to
711 * pass an argument (in this case the pointer to the cyclades_port
712 * structure) to the bottom half of the driver. Previous kernels
713 * had to poll every port to see if that port needed servicing.
714 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800715static void do_softint(struct work_struct *ugly_api)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800717 struct cyclades_port *info =
718 container_of(ugly_api, struct cyclades_port, tqueue);
719 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800721 tty = info->tty;
722 if (!tty)
723 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800725 if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
726 tty_hangup(info->tty);
727 wake_up_interruptible(&info->open_wait);
728 info->flags &= ~ASYNC_NORMAL_ACTIVE;
729 }
730 if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
731 wake_up_interruptible(&info->open_wait);
732 }
733 if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
734 tty_wakeup(tty);
735 }
736} /* do_softint */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738/* This is called whenever a port becomes active;
739 interrupts are enabled and DTR & RTS are turned on.
740 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800741static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800743 unsigned long flags;
744 volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
745 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800747 if (info->flags & ASYNC_INITIALIZED) {
748 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800750
751 if (!info->type) {
752 if (info->tty) {
753 set_bit(TTY_IO_ERROR, &info->tty->flags);
754 }
755 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800757 if (!info->xmit_buf) {
758 info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
759 if (!info->xmit_buf) {
760 return -ENOMEM;
761 }
762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800764 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800766 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800769 printk("startup channel %d\n", channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770#endif
771
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800772 local_irq_save(flags);
773 base_addr[CyCAR] = (u_char) channel;
774 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800776 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 base_addr[CyMSVR1] = CyRTS;
778/* CP('S');CP('1'); */
779 base_addr[CyMSVR2] = CyDTR;
780
781#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800782 printk("cyc: %d: raising DTR\n", __LINE__);
783 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
784 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785#endif
786
787 base_addr[CyIER] |= CyRxData;
788 info->flags |= ASYNC_INITIALIZED;
789
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800790 if (info->tty) {
791 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
793 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
794
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800795 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800798 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800800 return 0;
801} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800803void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800805 unsigned long flags;
806 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
807 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800809 channel = info->line;
810 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 base_addr[CyCAR] = channel;
812 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800813 local_irq_restore(flags);
814} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816/*
817 * This routine shuts down a serial port; interrupts are disabled,
818 * and DTR is dropped if the hangup on close termio flag is on.
819 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800820static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800822 unsigned long flags;
823 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
824 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800826 if (!(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827/* CP('$'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800828 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
830
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800831 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800833#ifdef SERIAL_DEBUG_OPEN
834 printk("shutdown channel %d\n", channel);
835#endif
836
837 /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
838 SENT BEFORE DROPPING THE LINE !!! (Perhaps
839 set some flag that is read when XMTY happens.)
840 Other choices are to delay some fixed interval
841 or schedule some later processing.
842 */
843 local_irq_save(flags);
844 if (info->xmit_buf) {
845 free_page((unsigned long)info->xmit_buf);
846 info->xmit_buf = NULL;
847 }
848
849 base_addr[CyCAR] = (u_char) channel;
850 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
851 base_addr[CyMSVR1] = 0;
852/* CP('C');CP('1'); */
853 base_addr[CyMSVR2] = 0;
854#ifdef SERIAL_DEBUG_DTR
855 printk("cyc: %d: dropping DTR\n", __LINE__);
856 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
857 base_addr[CyMSVR2]);
858#endif
859 }
860 write_cy_cmd(base_addr, CyDIS_RCVR);
861 /* it may be appropriate to clear _XMIT at
862 some later date (after testing)!!! */
863
864 if (info->tty) {
865 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800868 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800871 printk(" done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800873} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875/*
876 * This routine finds or computes the various line characteristics.
877 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800878static void config_setup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800880 unsigned long flags;
881 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
882 int channel;
883 unsigned cflag;
884 int i;
885 unsigned char ti, need_init_chan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800887 if (!info->tty || !info->tty->termios) {
888 return;
889 }
890 if (info->line == -1) {
891 return;
892 }
893 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800895 /* baud rate */
896 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897#ifdef CBAUDEX
898/* Starting with kernel 1.1.65, there is direct support for
899 higher baud rates. The following code supports those
900 changes. The conditional aspect allows this driver to be
901 used for earlier as well as later kernel versions. (The
902 mapping is slightly different from serial.c because there
903 is still the possibility of supporting 75 kbit/sec with
904 the Cyclades board.)
905 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800906 if (i & CBAUDEX) {
907 if (i == B57600)
908 i = 16;
909 else if (i == B115200)
910 i = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911#ifdef B78600
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800912 else if (i == B78600)
913 i = 17;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800915 else
916 info->tty->termios->c_cflag &= ~CBAUDEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -0800919 if (i == 15) {
920 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
921 i += 1;
922 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
923 i += 3;
924 }
925 /* Don't ever change the speed of the console port. It will
926 * run at the speed specified in bootinfo, or at 19.2K */
927 /* Actually, it should run at whatever speed 166Bug was using */
928 /* Note info->timeout isn't used at present */
929 if (info != serial_console_info) {
930 info->tbpr = baud_bpr[i]; /* Tx BPR */
931 info->tco = baud_co[i]; /* Tx CO */
932 info->rbpr = baud_bpr[i]; /* Rx BPR */
933 info->rco = baud_co[i] >> 5; /* Rx CO */
934 if (baud_table[i] == 134) {
935 info->timeout =
936 (info->xmit_fifo_size * HZ * 30 / 269) + 2;
937 /* get it right for 134.5 baud */
938 } else if (baud_table[i]) {
939 info->timeout =
940 (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
941 2;
942 /* this needs to be propagated into the card info */
943 } else {
944 info->timeout = 0;
945 }
946 }
947 /* By tradition (is it a standard?) a baud rate of zero
948 implies the line should be/has been closed. A bit
949 later in this routine such a test is performed. */
950
951 /* byte size and parity */
952 info->cor7 = 0;
953 info->cor6 = 0;
954 info->cor5 = 0;
955 info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
956 /* Following two lines added 101295, RGH. */
957 /* It is obviously wrong to access CyCORx, and not info->corx here,
958 * try and remember to fix it later! */
959 channel = info->line;
960 base_addr[CyCAR] = (u_char) channel;
961 if (C_CLOCAL(info->tty)) {
962 if (base_addr[CyIER] & CyMdmCh)
963 base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
964 /* ignore 1->0 modem transitions */
965 if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
966 base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
967 /* ignore 0->1 modem transitions */
968 if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
969 base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
970 } else {
971 if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
972 base_addr[CyIER] |= CyMdmCh; /* with modem intr */
973 /* act on 1->0 modem transitions */
974 if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
975 (CyDSR | CyCTS | CyDCD))
976 base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
977 /* act on 0->1 modem transitions */
978 if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
979 (CyDSR | CyCTS | CyDCD))
980 base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
981 }
982 info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
983 info->cor2 = CyETC;
984 switch (cflag & CSIZE) {
985 case CS5:
986 info->cor1 = Cy_5_BITS;
987 break;
988 case CS6:
989 info->cor1 = Cy_6_BITS;
990 break;
991 case CS7:
992 info->cor1 = Cy_7_BITS;
993 break;
994 case CS8:
995 info->cor1 = Cy_8_BITS;
996 break;
997 }
998 if (cflag & PARENB) {
999 if (cflag & PARODD) {
1000 info->cor1 |= CyPARITY_O;
1001 } else {
1002 info->cor1 |= CyPARITY_E;
1003 }
1004 } else {
1005 info->cor1 |= CyPARITY_NONE;
1006 }
1007
1008 /* CTS flow control flag */
1009#if 0
1010 /* Don't complcate matters for now! RGH 141095 */
1011 if (cflag & CRTSCTS) {
1012 info->flags |= ASYNC_CTS_FLOW;
1013 info->cor2 |= CyCtsAE;
1014 } else {
1015 info->flags &= ~ASYNC_CTS_FLOW;
1016 info->cor2 &= ~CyCtsAE;
1017 }
1018#endif
1019 if (cflag & CLOCAL)
1020 info->flags &= ~ASYNC_CHECK_CD;
1021 else
1022 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 /***********************************************
1025 The hardware option, CyRtsAO, presents RTS when
1026 the chip has characters to send. Since most modems
1027 use RTS as reverse (inbound) flow control, this
1028 option is not used. If inbound flow control is
1029 necessary, DTR can be programmed to provide the
1030 appropriate signals for use with a non-standard
1031 cable. Contact Marcio Saito for details.
1032 ***********************************************/
1033
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001034 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001036 local_irq_save(flags);
1037 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 /* CyCMR set once only in mvme167_init_serial() */
1040 if (base_addr[CyLICR] != channel << 2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001041 base_addr[CyLICR] = channel << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 if (base_addr[CyLIVR] != 0x5c)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001043 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001045 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001048 need_init_chan = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 if (base_addr[CyTCOR] != info->tco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001050 base_addr[CyTCOR] = info->tco;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 if (base_addr[CyTBPR] != info->tbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001052 base_addr[CyTBPR] = info->tbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (base_addr[CyRCOR] != info->rco)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001054 base_addr[CyRCOR] = info->rco;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 if (base_addr[CyRBPR] != info->rbpr)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001056 base_addr[CyRBPR] = info->rbpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 /* set line characteristics according configuration */
1059
1060 if (base_addr[CySCHR1] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001061 base_addr[CySCHR1] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001063 base_addr[CySCHR2] = STOP_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 if (base_addr[CySCRL] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001065 base_addr[CySCRL] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 if (base_addr[CySCRH] != START_CHAR(info->tty))
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001067 base_addr[CySCRH] = START_CHAR(info->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (base_addr[CyCOR1] != info->cor1)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001069 base_addr[CyCOR1] = info->cor1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (base_addr[CyCOR2] != info->cor2)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001071 base_addr[CyCOR2] = info->cor2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 if (base_addr[CyCOR3] != info->cor3)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001073 base_addr[CyCOR3] = info->cor3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 if (base_addr[CyCOR4] != info->cor4)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001075 base_addr[CyCOR4] = info->cor4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 if (base_addr[CyCOR5] != info->cor5)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001077 base_addr[CyCOR5] = info->cor5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 if (base_addr[CyCOR6] != info->cor6)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001079 base_addr[CyCOR6] = info->cor6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (base_addr[CyCOR7] != info->cor7)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001081 base_addr[CyCOR7] = info->cor7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 if (need_init_chan)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001084 write_cy_cmd(base_addr, CyINIT_CHAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001086 base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088 /* 2ms default rx timeout */
1089 ti = info->default_timeout ? info->default_timeout : 0x02;
1090 if (base_addr[CyRTPRL] != ti)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001091 base_addr[CyRTPRL] = ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 if (base_addr[CyRTPRH] != 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001093 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 /* Set up RTS here also ????? RGH 141095 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001096 if (i == 0) { /* baud rate is zero, turn off line */
1097 if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
1098 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001100 printk("cyc: %d: dropping DTR\n", __LINE__);
1101 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1102 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001104 } else {
1105 if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
1106 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001108 printk("cyc: %d: raising DTR\n", __LINE__);
1109 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1110 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111#endif
1112 }
1113
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001114 if (info->tty) {
1115 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
1117
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001118 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001120} /* config_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001122static void cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001124 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1125 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001128 printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129#endif
1130
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001131 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1132 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001134 if (!info->xmit_buf)
1135 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001137 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 if (info->xmit_cnt >= PAGE_SIZE - 1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001139 local_irq_restore(flags);
1140 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 }
1142
1143 info->xmit_buf[info->xmit_head++] = ch;
1144 info->xmit_head &= PAGE_SIZE - 1;
1145 info->xmit_cnt++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001146 local_irq_restore(flags);
1147} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001149static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001151 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1152 unsigned long flags;
1153 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1154 int channel;
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001157 printk("cy_flush_chars %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158#endif
1159
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001160 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1161 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001163 if (info->xmit_cnt <= 0 || tty->stopped
1164 || tty->hw_stopped || !info->xmit_buf)
1165 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001167 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001169 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 base_addr[CyCAR] = channel;
1171 base_addr[CyIER] |= CyTxMpty;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001172 local_irq_restore(flags);
1173} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175/* This routine gets called when tty_write has put something into
1176 the write_queue. If the port is not already transmitting stuff,
1177 start it off by enabling interrupts. The interrupt service
1178 routine will then ensure that the characters are sent. If the
1179 port is already active, there is no need to kick it.
1180 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001181static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001183 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1184 unsigned long flags;
1185 int c, total = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
1187#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001188 printk("cy_write %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189#endif
1190
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001191 if (serial_paranoia_check(info, tty->name, "cy_write")) {
1192 return 0;
1193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001195 if (!info->xmit_buf) {
1196 return 0;
1197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001199 while (1) {
1200 local_irq_save(flags);
1201 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1202 SERIAL_XMIT_SIZE - info->xmit_head));
1203 if (c <= 0) {
1204 local_irq_restore(flags);
1205 break;
1206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001208 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1209 info->xmit_head =
1210 (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1211 info->xmit_cnt += c;
1212 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001214 buf += c;
1215 count -= c;
1216 total += c;
1217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001219 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
1220 start_xmit(info);
1221 }
1222 return total;
1223} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001225static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001227 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1228 int ret;
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001231 printk("cy_write_room %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232#endif
1233
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001234 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1235 return 0;
1236 ret = PAGE_SIZE - info->xmit_cnt - 1;
1237 if (ret < 0)
1238 ret = 0;
1239 return ret;
1240} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001242static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001244 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001247 printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248#endif
1249
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001250 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1251 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001253 return info->xmit_cnt;
1254} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001256static void cy_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001258 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1259 unsigned long flags;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261#ifdef SERIAL_DEBUG_IO
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001262 printk("cy_flush_buffer %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263#endif
1264
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001265 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1266 return;
1267 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001269 local_irq_restore(flags);
1270 tty_wakeup(tty);
1271} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273/* This routine is called by the upper-layer tty layer to signal
1274 that incoming characters should be throttled or that the
1275 throttle should be released.
1276 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001277static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001279 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1280 unsigned long flags;
1281 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1282 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001285 char buf[64];
1286
1287 printk("throttle %s: %d....\n", tty_name(tty, buf),
1288 tty->ldisc.chars_in_buffer(tty));
1289 printk("cy_throttle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290#endif
1291
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001292 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1293 return;
1294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001296 if (I_IXOFF(tty)) {
1297 info->x_char = STOP_CHAR(tty);
1298 /* Should use the "Send Special Character" feature!!! */
1299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001301 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001303 local_irq_save(flags);
1304 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001306 local_irq_restore(flags);
1307} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001309static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001311 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1312 unsigned long flags;
1313 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1314 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
1316#ifdef SERIAL_DEBUG_THROTTLE
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001317 char buf[64];
1318
1319 printk("throttle %s: %d....\n", tty_name(tty, buf),
1320 tty->ldisc.chars_in_buffer(tty));
1321 printk("cy_unthrottle %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322#endif
1323
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001324 if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
1325 return;
1326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001328 if (I_IXOFF(tty)) {
1329 info->x_char = START_CHAR(tty);
1330 /* Should use the "Send Special Character" feature!!! */
1331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001333 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001335 local_irq_save(flags);
1336 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001338 local_irq_restore(flags);
1339} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
1341static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001342get_serial_info(struct cyclades_port *info,
1343 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001345 struct serial_struct tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347/* CP('g'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001348 if (!retinfo)
1349 return -EFAULT;
1350 memset(&tmp, 0, sizeof(tmp));
1351 tmp.type = info->type;
1352 tmp.line = info->line;
1353 tmp.port = info->line;
1354 tmp.irq = 0;
1355 tmp.flags = info->flags;
1356 tmp.baud_base = 0; /*!!! */
1357 tmp.close_delay = info->close_delay;
1358 tmp.custom_divisor = 0; /*!!! */
1359 tmp.hub6 = 0; /*!!! */
1360 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1361} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001364set_serial_info(struct cyclades_port *info,
1365 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001367 struct serial_struct new_serial;
1368 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370/* CP('s'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001371 if (!new_info)
1372 return -EFAULT;
1373 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1374 return -EFAULT;
1375 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001377 if (!capable(CAP_SYS_ADMIN)) {
1378 if ((new_serial.close_delay != info->close_delay) ||
1379 ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
1380 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
1381 return -EPERM;
1382 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
1383 (new_serial.flags & ASYNC_USR_MASK));
1384 goto check_and_exit;
1385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001387 /*
1388 * OK, past this point, all the error checking has been done.
1389 * At this point, we start making changes.....
1390 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001392 info->flags = ((info->flags & ~ASYNC_FLAGS) |
1393 (new_serial.flags & ASYNC_FLAGS));
1394 info->close_delay = new_serial.close_delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396check_and_exit:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001397 if (info->flags & ASYNC_INITIALIZED) {
1398 config_setup(info);
1399 return 0;
1400 }
1401 return startup(info);
1402} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001404static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001406 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1407 int channel;
1408 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1409 unsigned long flags;
1410 unsigned char status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001412 channel = info->line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001414 local_irq_save(flags);
1415 base_addr[CyCAR] = (u_char) channel;
1416 status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
1417 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001419 return ((status & CyRTS) ? TIOCM_RTS : 0)
1420 | ((status & CyDTR) ? TIOCM_DTR : 0)
1421 | ((status & CyDCD) ? TIOCM_CAR : 0)
1422 | ((status & CyDSR) ? TIOCM_DSR : 0)
1423 | ((status & CyCTS) ? TIOCM_CTS : 0);
1424} /* cy_tiocmget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426static int
1427cy_tiocmset(struct tty_struct *tty, struct file *file,
1428 unsigned int set, unsigned int clear)
1429{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001430 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1431 int channel;
1432 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1433 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001435 channel = info->line;
1436
1437 if (set & TIOCM_RTS) {
1438 local_irq_save(flags);
1439 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 base_addr[CyMSVR1] = CyRTS;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001441 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001443 if (set & TIOCM_DTR) {
1444 local_irq_save(flags);
1445 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446/* CP('S');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001447 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001449 printk("cyc: %d: raising DTR\n", __LINE__);
1450 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1451 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001453 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
1455
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001456 if (clear & TIOCM_RTS) {
1457 local_irq_save(flags);
1458 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 base_addr[CyMSVR1] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001460 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001462 if (clear & TIOCM_DTR) {
1463 local_irq_save(flags);
1464 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465/* CP('C');CP('2'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001466 base_addr[CyMSVR2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467#ifdef SERIAL_DEBUG_DTR
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001468 printk("cyc: %d: dropping DTR\n", __LINE__);
1469 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1470 base_addr[CyMSVR2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001472 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
1474
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001475 return 0;
1476} /* set_modem_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001478static void send_break(struct cyclades_port *info, int duration)
1479{ /* Let the transmit ISR take care of this (since it
1480 requires stuffing characters into the output stream).
1481 */
1482 info->x_break = duration;
1483 if (!info->xmit_cnt) {
1484 start_xmit(info);
1485 }
1486} /* send_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001489get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490{
1491
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001492 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
1493 return -EFAULT;
1494 info->mon.int_count = 0;
1495 info->mon.char_count = 0;
1496 info->mon.char_max = 0;
1497 info->mon.char_last = 0;
1498 return 0;
1499}
1500
1501static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
1502{
1503 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1504 unsigned long value;
1505 int channel;
1506
1507 if (get_user(value, arg))
1508 return -EFAULT;
1509
1510 channel = info->line;
1511 info->cor4 &= ~CyREC_FIFO;
1512 info->cor4 |= value & CyREC_FIFO;
1513 base_addr[CyCOR4] = info->cor4;
1514 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515}
1516
1517static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001518get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001520 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1521 int channel;
1522 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001524 channel = info->line;
1525
1526 tmp = base_addr[CyCOR4] & CyREC_FIFO;
1527 return put_user(tmp, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528}
1529
1530static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001531set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001533 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001535 if (get_user(value, arg))
1536 return -EFAULT;
1537
1538 info->default_threshold = value & 0x0f;
1539 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540}
1541
1542static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001543get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001545 return put_user(info->default_threshold, value);
1546}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001548static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
1549{
1550 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1551 int channel;
1552 unsigned long value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001554 if (get_user(value, arg))
1555 return -EFAULT;
1556
1557 channel = info->line;
1558
1559 base_addr[CyRTPRL] = value & 0xff;
1560 base_addr[CyRTPRH] = (value >> 8) & 0xff;
1561 return 0;
1562}
1563
1564static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
1565{
1566 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
1567 int channel;
1568 unsigned long tmp;
1569
1570 channel = info->line;
1571
1572 tmp = base_addr[CyRTPRL];
1573 return put_user(tmp, value);
1574}
1575
1576static int set_default_timeout(struct cyclades_port *info, unsigned long value)
1577{
1578 info->default_timeout = value & 0xff;
1579 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580}
1581
1582static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001583get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001585 return put_user(info->default_timeout, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586}
1587
1588static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001589cy_ioctl(struct tty_struct *tty, struct file *file,
1590 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001592 unsigned long val;
1593 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1594 int ret_val = 0;
1595 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001598 printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599#endif
1600
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001601 switch (cmd) {
1602 case CYGETMON:
1603 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001605 case CYGETTHRESH:
1606 ret_val = get_threshold(info, argp);
1607 break;
1608 case CYSETTHRESH:
1609 ret_val = set_threshold(info, argp);
1610 break;
1611 case CYGETDEFTHRESH:
1612 ret_val = get_default_threshold(info, argp);
1613 break;
1614 case CYSETDEFTHRESH:
1615 ret_val = set_default_threshold(info, argp);
1616 break;
1617 case CYGETTIMEOUT:
1618 ret_val = get_timeout(info, argp);
1619 break;
1620 case CYSETTIMEOUT:
1621 ret_val = set_timeout(info, argp);
1622 break;
1623 case CYGETDEFTIMEOUT:
1624 ret_val = get_default_timeout(info, argp);
1625 break;
1626 case CYSETDEFTIMEOUT:
1627 ret_val = set_default_timeout(info, (unsigned long)arg);
1628 break;
1629 case TCSBRK: /* SVID version: non-zero arg --> no break */
1630 ret_val = tty_check_change(tty);
1631 if (ret_val)
1632 break;
1633 tty_wait_until_sent(tty, 0);
1634 if (!arg)
1635 send_break(info, HZ / 4); /* 1/4 second */
1636 break;
1637 case TCSBRKP: /* support for POSIX tcsendbreak() */
1638 ret_val = tty_check_change(tty);
1639 if (ret_val)
1640 break;
1641 tty_wait_until_sent(tty, 0);
1642 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
1643 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
1645/* The following commands are incompletely implemented!!! */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001646 case TIOCGSOFTCAR:
1647 ret_val =
1648 put_user(C_CLOCAL(tty) ? 1 : 0,
1649 (unsigned long __user *)argp);
1650 break;
1651 case TIOCSSOFTCAR:
1652 ret_val = get_user(val, (unsigned long __user *)argp);
1653 if (ret_val)
1654 break;
1655 tty->termios->c_cflag =
1656 ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
1657 break;
1658 case TIOCGSERIAL:
1659 ret_val = get_serial_info(info, argp);
1660 break;
1661 case TIOCSSERIAL:
1662 ret_val = set_serial_info(info, argp);
1663 break;
1664 default:
1665 ret_val = -ENOIOCTLCMD;
1666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001669 printk("cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670#endif
1671
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001672 return ret_val;
1673} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001675static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001677 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001680 printk("cy_set_termios %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681#endif
1682
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001683 if (tty->termios->c_cflag == old_termios->c_cflag)
1684 return;
1685 config_setup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001687 if ((old_termios->c_cflag & CRTSCTS) &&
1688 !(tty->termios->c_cflag & CRTSCTS)) {
1689 tty->stopped = 0;
1690 cy_start(tty);
1691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692#ifdef tytso_patch_94Nov25_1726
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001693 if (!(old_termios->c_cflag & CLOCAL) &&
1694 (tty->termios->c_cflag & CLOCAL))
1695 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001697} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001699static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001701 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703/* CP('C'); */
1704#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001705 printk("cy_close %s\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706#endif
1707
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001708 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
1709 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001711#ifdef SERIAL_DEBUG_OPEN
1712 printk("cy_close %s, count = %d\n", tty->name, info->count);
1713#endif
1714
1715 if ((tty->count == 1) && (info->count != 1)) {
1716 /*
1717 * Uh, oh. tty->count is 1, which means that the tty
1718 * structure will be freed. Info->count should always
1719 * be one in these conditions. If it's greater than
1720 * one, we've got real problems, since it means the
1721 * serial port won't be shutdown.
1722 */
1723 printk("cy_close: bad serial port count; tty->count is 1, "
1724 "info->count is %d\n", info->count);
1725 info->count = 1;
1726 }
1727#ifdef SERIAL_DEBUG_COUNT
1728 printk("cyc: %d: decrementing count to %d\n", __LINE__,
1729 info->count - 1);
1730#endif
1731 if (--info->count < 0) {
1732 printk("cy_close: bad serial port count for ttys%d: %d\n",
1733 info->line, info->count);
1734#ifdef SERIAL_DEBUG_COUNT
1735 printk("cyc: %d: setting count to 0\n", __LINE__);
1736#endif
1737 info->count = 0;
1738 }
1739 if (info->count)
1740 return;
1741 info->flags |= ASYNC_CLOSING;
1742 if (info->flags & ASYNC_INITIALIZED)
1743 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1744 shutdown(info);
1745 if (tty->driver->flush_buffer)
1746 tty->driver->flush_buffer(tty);
1747 tty_ldisc_flush(tty);
1748 info->event = 0;
1749 info->tty = NULL;
1750 if (info->blocked_open) {
1751 if (info->close_delay) {
1752 msleep_interruptible(jiffies_to_msecs
1753 (info->close_delay));
1754 }
1755 wake_up_interruptible(&info->open_wait);
1756 }
1757 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1758 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001761 printk("cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001763} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
1765/*
1766 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
1767 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001768void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001770 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001773 printk("cy_hangup %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774#endif
1775
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001776 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
1777 return;
1778
1779 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001781 info->event = 0;
1782 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001784 printk("cyc: %d: setting count to 0\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001786 info->tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001788 info->flags &= ~ASYNC_NORMAL_ACTIVE;
1789 wake_up_interruptible(&info->open_wait);
1790} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
1792/*
1793 * ------------------------------------------------------------
1794 * cy_open() and friends
1795 * ------------------------------------------------------------
1796 */
1797
1798static int
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001799block_til_ready(struct tty_struct *tty, struct file *filp,
1800 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001802 DECLARE_WAITQUEUE(wait, current);
1803 unsigned long flags;
1804 int channel;
1805 int retval;
1806 volatile u_char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001808 /*
1809 * If the device is in the middle of being closed, then block
1810 * until it's done, and then try again.
1811 */
1812 if (info->flags & ASYNC_CLOSING) {
1813 interruptible_sleep_on(&info->close_wait);
1814 if (info->flags & ASYNC_HUP_NOTIFY) {
1815 return -EAGAIN;
1816 } else {
1817 return -ERESTARTSYS;
1818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001821 /*
1822 * If non-blocking mode is set, then make the check up front
1823 * and then exit.
1824 */
1825 if (filp->f_flags & O_NONBLOCK) {
1826 info->flags |= ASYNC_NORMAL_ACTIVE;
1827 return 0;
1828 }
1829
1830 /*
1831 * Block waiting for the carrier detect and the line to become
1832 * free (i.e., not in use by the callout). While we are in
1833 * this loop, info->count is dropped by one, so that
1834 * cy_close() knows when to free things. We restore it upon
1835 * exit, either normal or abnormal.
1836 */
1837 retval = 0;
1838 add_wait_queue(&info->open_wait, &wait);
1839#ifdef SERIAL_DEBUG_OPEN
1840 printk("block_til_ready before block: %s, count = %d\n",
1841 tty->name, info->count);
1842 /**/
1843#endif
1844 info->count--;
1845#ifdef SERIAL_DEBUG_COUNT
1846 printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
1847#endif
1848 info->blocked_open++;
1849
1850 channel = info->line;
1851
1852 while (1) {
1853 local_irq_save(flags);
1854 base_addr[CyCAR] = (u_char) channel;
1855 base_addr[CyMSVR1] = CyRTS;
1856/* CP('S');CP('4'); */
1857 base_addr[CyMSVR2] = CyDTR;
1858#ifdef SERIAL_DEBUG_DTR
1859 printk("cyc: %d: raising DTR\n", __LINE__);
1860 printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
1861 base_addr[CyMSVR2]);
1862#endif
1863 local_irq_restore(flags);
1864 set_current_state(TASK_INTERRUPTIBLE);
1865 if (tty_hung_up_p(filp)
1866 || !(info->flags & ASYNC_INITIALIZED)) {
1867 if (info->flags & ASYNC_HUP_NOTIFY) {
1868 retval = -EAGAIN;
1869 } else {
1870 retval = -ERESTARTSYS;
1871 }
1872 break;
1873 }
1874 local_irq_save(flags);
1875 base_addr[CyCAR] = (u_char) channel;
1876/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
1877 if (!(info->flags & ASYNC_CLOSING)
1878 && (C_CLOCAL(tty)
1879 || (base_addr[CyMSVR1] & CyDCD))) {
1880 local_irq_restore(flags);
1881 break;
1882 }
1883 local_irq_restore(flags);
1884 if (signal_pending(current)) {
1885 retval = -ERESTARTSYS;
1886 break;
1887 }
1888#ifdef SERIAL_DEBUG_OPEN
1889 printk("block_til_ready blocking: %s, count = %d\n",
1890 tty->name, info->count);
1891 /**/
1892#endif
1893 schedule();
1894 }
1895 current->state = TASK_RUNNING;
1896 remove_wait_queue(&info->open_wait, &wait);
1897 if (!tty_hung_up_p(filp)) {
1898 info->count++;
1899#ifdef SERIAL_DEBUG_COUNT
1900 printk("cyc: %d: incrementing count to %d\n", __LINE__,
1901 info->count);
1902#endif
1903 }
1904 info->blocked_open--;
1905#ifdef SERIAL_DEBUG_OPEN
1906 printk("block_til_ready after blocking: %s, count = %d\n",
1907 tty->name, info->count);
1908 /**/
1909#endif
1910 if (retval)
1911 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 info->flags |= ASYNC_NORMAL_ACTIVE;
1913 return 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001914} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916/*
1917 * This routine is called whenever a serial port is opened. It
1918 * performs the serial-specific initialization for the tty structure.
1919 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001920int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001922 struct cyclades_port *info;
1923 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925/* CP('O'); */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001926 line = tty->index;
1927 if ((line < 0) || (NR_PORTS <= line)) {
1928 return -ENODEV;
1929 }
1930 info = &cy_port[line];
1931 if (info->line < 0) {
1932 return -ENODEV;
1933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934#ifdef SERIAL_DEBUG_OTHER
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001935 printk("cy_open %s\n", tty->name); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001937 if (serial_paranoia_check(info, tty->name, "cy_open")) {
1938 return -ENODEV;
1939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001941 printk("cy_open %s, count = %d\n", tty->name, info->count);
1942 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001944 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945#ifdef SERIAL_DEBUG_COUNT
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001946 printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001948 tty->driver_data = info;
1949 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001951 /*
1952 * Start up serial port
1953 */
1954 retval = startup(info);
1955 if (retval) {
1956 return retval;
1957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001959 retval = block_til_ready(tty, filp, info);
1960 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001962 printk("cy_open returning after block_til_ready with %d\n",
1963 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001965 return retval;
1966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967#ifdef SERIAL_DEBUG_OPEN
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001968 printk("cy_open done\n");
1969 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001971 return 0;
1972} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974/*
1975 * ---------------------------------------------------------------------
1976 * serial167_init() and friends
1977 *
1978 * serial167_init() is called at boot-time to initialize the serial driver.
1979 * ---------------------------------------------------------------------
1980 */
1981
1982/*
1983 * This routine prints out the appropriate serial driver version
1984 * number, and identifies which options were configured into this
1985 * driver.
1986 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001987static void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08001989 printk("MVME166/167 cd2401 driver\n");
1990} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
1992/* initialize chips on card -- return number of valid
1993 chips (which is number of ports/4) */
1994
1995/*
1996 * This initialises the hardware to a reasonable state. It should
1997 * probe the chip first so as to copy 166-Bug setup as a default for
1998 * port 0. It initialises CMR to CyASYNC; that is never done again, so
1999 * as to limit the number of CyINIT_CHAN commands in normal running.
2000 *
2001 * ... I wonder what I should do if this fails ...
2002 */
2003
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002004void mvme167_serial_console_setup(int cflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002006 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 int ch;
2008 u_char spd;
2009 u_char rcor, rbpr, badspeed = 0;
2010 unsigned long flags;
2011
2012 local_irq_save(flags);
2013
2014 /*
2015 * First probe channel zero of the chip, to see what speed has
2016 * been selected.
2017 */
2018
2019 base_addr[CyCAR] = 0;
2020
2021 rcor = base_addr[CyRCOR] << 5;
2022 rbpr = base_addr[CyRBPR];
2023
2024 for (spd = 0; spd < sizeof(baud_bpr); spd++)
2025 if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])
2026 break;
2027 if (spd >= sizeof(baud_bpr)) {
2028 spd = 14; /* 19200 */
2029 badspeed = 1; /* Failed to identify speed */
2030 }
2031 initial_console_speed = spd;
2032
2033 /* OK, we have chosen a speed, now reset and reinitialise */
2034
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002035 my_udelay(20000L); /* Allow time for any active o/p to complete */
2036 if (base_addr[CyCCR] != 0x00) {
2037 local_irq_restore(flags);
2038 /* printk(" chip is never idle (CCR != 0)\n"); */
2039 return;
2040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002042 base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
2043 my_udelay(1000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002045 if (base_addr[CyGFRCR] == 0x00) {
2046 local_irq_restore(flags);
2047 /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
2048 return;
2049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
2051 /*
2052 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
2053 * tick
2054 */
2055
2056 base_addr[CyTPR] = 10;
2057
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002058 base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
2059 base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
2060 base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061
2062 /*
2063 * Attempt to set up all channels to something reasonable, and
2064 * bang out a INIT_CHAN command. We should then be able to limit
2065 * the ammount of fiddling we have to do in normal running.
2066 */
2067
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002068 for (ch = 3; ch >= 0; ch--) {
2069 base_addr[CyCAR] = (u_char) ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 base_addr[CyIER] = 0;
2071 base_addr[CyCMR] = CyASYNC;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002072 base_addr[CyLICR] = (u_char) ch << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 base_addr[CyLIVR] = 0x5c;
2074 base_addr[CyTCOR] = baud_co[spd];
2075 base_addr[CyTBPR] = baud_bpr[spd];
2076 base_addr[CyRCOR] = baud_co[spd] >> 5;
2077 base_addr[CyRBPR] = baud_bpr[spd];
2078 base_addr[CySCHR1] = 'Q' & 0x1f;
2079 base_addr[CySCHR2] = 'X' & 0x1f;
2080 base_addr[CySCRL] = 0;
2081 base_addr[CySCRH] = 0;
2082 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2083 base_addr[CyCOR2] = 0;
2084 base_addr[CyCOR3] = Cy_1_STOP;
2085 base_addr[CyCOR4] = baud_cor4[spd];
2086 base_addr[CyCOR5] = 0;
2087 base_addr[CyCOR6] = 0;
2088 base_addr[CyCOR7] = 0;
2089 base_addr[CyRTPRL] = 2;
2090 base_addr[CyRTPRH] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002091 base_addr[CyMSVR1] = 0;
2092 base_addr[CyMSVR2] = 0;
2093 write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 }
2095
2096 /*
2097 * Now do specials for channel zero....
2098 */
2099
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002100 base_addr[CyMSVR1] = CyRTS;
2101 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 base_addr[CyIER] = CyRxData;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002103 write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
2105 local_irq_restore(flags);
2106
2107 my_udelay(20000L); /* Let it all settle down */
2108
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002109 printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 if (badspeed)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002111 printk
2112 (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
2113 rcor >> 5, rbpr);
2114} /* serial_console_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002116static const struct tty_operations cy_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 .open = cy_open,
2118 .close = cy_close,
2119 .write = cy_write,
2120 .put_char = cy_put_char,
2121 .flush_chars = cy_flush_chars,
2122 .write_room = cy_write_room,
2123 .chars_in_buffer = cy_chars_in_buffer,
2124 .flush_buffer = cy_flush_buffer,
2125 .ioctl = cy_ioctl,
2126 .throttle = cy_throttle,
2127 .unthrottle = cy_unthrottle,
2128 .set_termios = cy_set_termios,
2129 .stop = cy_stop,
2130 .start = cy_start,
2131 .hangup = cy_hangup,
2132 .tiocmget = cy_tiocmget,
2133 .tiocmset = cy_tiocmset,
2134};
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136/* The serial driver boot-time initialization code!
2137 Hardware I/O ports are mapped to character special devices on a
2138 first found, first allocated manner. That is, this code searches
2139 for Cyclom cards in the system. As each is found, it is probed
2140 to discover how many chips (and thus how many ports) are present.
2141 These ports are mapped to the tty ports 64 and upward in monotonic
2142 fashion. If an 8-port card is replaced with a 16-port card, the
2143 port mapping on a following card will shift.
2144
2145 This approach is different from what is used in the other serial
2146 device driver because the Cyclom is more properly a multiplexer,
2147 not just an aggregation of serial ports on one card.
2148
2149 If there are more cards with more ports than have been statically
2150 allocated above, a warning is printed and the extra ports are ignored.
2151 */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002152static int __init serial167_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002154 struct cyclades_port *info;
2155 int ret = 0;
2156 int good_ports = 0;
2157 int port_num = 0;
2158 int index;
2159 int DefSpeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160#ifdef notyet
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002161 struct sigaction sa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162#endif
2163
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002164 if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
2165 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002167 cy_serial_driver = alloc_tty_driver(NR_PORTS);
2168 if (!cy_serial_driver)
2169 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
2171#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002172 scrn[1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173#endif
2174
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002175 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002177 /* Has "console=0,9600n8" been used in bootinfo to change speed? */
2178 if (serial_console_cflag)
2179 DefSpeed = serial_console_cflag & 0017;
2180 else {
2181 DefSpeed = initial_console_speed;
2182 serial_console_info = &cy_port[0];
2183 serial_console_cflag = DefSpeed | CS8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184#if 0
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002185 serial_console = 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002188
2189 /* Initialize the tty_driver structure */
2190
2191 cy_serial_driver->owner = THIS_MODULE;
2192 cy_serial_driver->name = "ttyS";
2193 cy_serial_driver->major = TTY_MAJOR;
2194 cy_serial_driver->minor_start = 64;
2195 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2196 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
2197 cy_serial_driver->init_termios = tty_std_termios;
2198 cy_serial_driver->init_termios.c_cflag =
2199 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2200 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
2201 tty_set_operations(cy_serial_driver, &cy_ops);
2202
2203 ret = tty_register_driver(cy_serial_driver);
2204 if (ret) {
2205 printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
2206 put_tty_driver(cy_serial_driver);
2207 return ret;
2208 }
2209
2210 port_num = 0;
2211 info = cy_port;
2212 for (index = 0; index < 1; index++) {
2213
2214 good_ports = 4;
2215
2216 if (port_num < NR_PORTS) {
2217 while (good_ports-- && port_num < NR_PORTS) {
2218 /*** initialize port ***/
2219 info->magic = CYCLADES_MAGIC;
2220 info->type = PORT_CIRRUS;
2221 info->card = index;
2222 info->line = port_num;
2223 info->flags = STD_COM_FLAGS;
2224 info->tty = NULL;
2225 info->xmit_fifo_size = 12;
2226 info->cor1 = CyPARITY_NONE | Cy_8_BITS;
2227 info->cor2 = CyETC;
2228 info->cor3 = Cy_1_STOP;
2229 info->cor4 = 0x08; /* _very_ small receive threshold */
2230 info->cor5 = 0;
2231 info->cor6 = 0;
2232 info->cor7 = 0;
2233 info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
2234 info->tco = baud_co[DefSpeed]; /* Tx CO */
2235 info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
2236 info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
2237 info->close_delay = 0;
2238 info->x_char = 0;
2239 info->event = 0;
2240 info->count = 0;
2241#ifdef SERIAL_DEBUG_COUNT
2242 printk("cyc: %d: setting count to 0\n",
2243 __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244#endif
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002245 info->blocked_open = 0;
2246 info->default_threshold = 0;
2247 info->default_timeout = 0;
2248 INIT_WORK(&info->tqueue, do_softint);
2249 init_waitqueue_head(&info->open_wait);
2250 init_waitqueue_head(&info->close_wait);
2251 /* info->session */
2252 /* info->pgrp */
2253/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
2254 info->read_status_mask =
2255 CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
2256 CyFRAME | CyOVERRUN;
2257 /* info->timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002259 printk("ttyS%d ", info->line);
2260 port_num++;
2261 info++;
2262 if (!(port_num & 7)) {
2263 printk("\n ");
2264 }
2265 }
2266 }
2267 printk("\n");
2268 }
2269 while (port_num < NR_PORTS) {
2270 info->line = -1;
2271 port_num++;
2272 info++;
2273 }
2274#ifdef CONFIG_REMOTE_DEBUG
2275 debug_setup();
2276#endif
2277 ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
2278 "cd2401_errors", cd2401_rxerr_interrupt);
2279 if (ret) {
2280 printk(KERN_ERR "Could't get cd2401_errors IRQ");
2281 goto cleanup_serial_driver;
2282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002284 ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
2285 "cd2401_modem", cd2401_modem_interrupt);
2286 if (ret) {
2287 printk(KERN_ERR "Could't get cd2401_modem IRQ");
2288 goto cleanup_irq_cd2401_errors;
2289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002291 ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
2292 "cd2401_txints", cd2401_tx_interrupt);
2293 if (ret) {
2294 printk(KERN_ERR "Could't get cd2401_txints IRQ");
2295 goto cleanup_irq_cd2401_modem;
2296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002298 ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
2299 "cd2401_rxints", cd2401_rx_interrupt);
2300 if (ret) {
2301 printk(KERN_ERR "Could't get cd2401_rxints IRQ");
2302 goto cleanup_irq_cd2401_txints;
2303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002305 /* Now we have registered the interrupt handlers, allow the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002307 pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
2308 pcc2chip[PccSCCTICR] = 0x15;
2309 pcc2chip[PccSCCRICR] = 0x15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002311 pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
2312
2313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314cleanup_irq_cd2401_txints:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002315 free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316cleanup_irq_cd2401_modem:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002317 free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318cleanup_irq_cd2401_errors:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002319 free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320cleanup_serial_driver:
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002321 if (tty_unregister_driver(cy_serial_driver))
2322 printk(KERN_ERR
2323 "Couldn't unregister MVME166/7 serial driver\n");
2324 put_tty_driver(cy_serial_driver);
2325 return ret;
2326} /* serial167_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
2328module_init(serial167_init);
2329
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330#ifdef CYCLOM_SHOW_STATUS
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002331static void show_status(int line_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002333 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2334 int channel;
2335 struct cyclades_port *info;
2336 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002338 info = &cy_port[line_num];
2339 channel = info->line;
2340 printk(" channel %d\n", channel);
2341 /**/ printk(" cy_port\n");
2342 printk(" card line flags = %d %d %x\n",
2343 info->card, info->line, info->flags);
2344 printk
2345 (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
2346 (long)info->tty, info->read_status_mask, info->timeout,
2347 info->xmit_fifo_size);
2348 printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
2349 info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
2350 info->cor6, info->cor7);
2351 printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
2352 info->rbpr, info->rco);
2353 printk(" close_delay event count = %d %d %d\n", info->close_delay,
2354 info->event, info->count);
2355 printk(" x_char blocked_open = %x %x\n", info->x_char,
2356 info->blocked_open);
2357 printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002359 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361/* Global Registers */
2362
2363 printk(" CyGFRCR %x\n", base_addr[CyGFRCR]);
2364 printk(" CyCAR %x\n", base_addr[CyCAR]);
2365 printk(" CyRISR %x\n", base_addr[CyRISR]);
2366 printk(" CyTISR %x\n", base_addr[CyTISR]);
2367 printk(" CyMISR %x\n", base_addr[CyMISR]);
2368 printk(" CyRIR %x\n", base_addr[CyRIR]);
2369 printk(" CyTIR %x\n", base_addr[CyTIR]);
2370 printk(" CyMIR %x\n", base_addr[CyMIR]);
2371 printk(" CyTPR %x\n", base_addr[CyTPR]);
2372
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002373 base_addr[CyCAR] = (u_char) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375/* Virtual Registers */
2376
2377#if 0
2378 printk(" CyRIVR %x\n", base_addr[CyRIVR]);
2379 printk(" CyTIVR %x\n", base_addr[CyTIVR]);
2380 printk(" CyMIVR %x\n", base_addr[CyMIVR]);
2381 printk(" CyMISR %x\n", base_addr[CyMISR]);
2382#endif
2383
2384/* Channel Registers */
2385
2386 printk(" CyCCR %x\n", base_addr[CyCCR]);
2387 printk(" CyIER %x\n", base_addr[CyIER]);
2388 printk(" CyCOR1 %x\n", base_addr[CyCOR1]);
2389 printk(" CyCOR2 %x\n", base_addr[CyCOR2]);
2390 printk(" CyCOR3 %x\n", base_addr[CyCOR3]);
2391 printk(" CyCOR4 %x\n", base_addr[CyCOR4]);
2392 printk(" CyCOR5 %x\n", base_addr[CyCOR5]);
2393#if 0
2394 printk(" CyCCSR %x\n", base_addr[CyCCSR]);
2395 printk(" CyRDCR %x\n", base_addr[CyRDCR]);
2396#endif
2397 printk(" CySCHR1 %x\n", base_addr[CySCHR1]);
2398 printk(" CySCHR2 %x\n", base_addr[CySCHR2]);
2399#if 0
2400 printk(" CySCHR3 %x\n", base_addr[CySCHR3]);
2401 printk(" CySCHR4 %x\n", base_addr[CySCHR4]);
2402 printk(" CySCRL %x\n", base_addr[CySCRL]);
2403 printk(" CySCRH %x\n", base_addr[CySCRH]);
2404 printk(" CyLNC %x\n", base_addr[CyLNC]);
2405 printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]);
2406 printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]);
2407#endif
2408 printk(" CyRTPRL %x\n", base_addr[CyRTPRL]);
2409 printk(" CyRTPRH %x\n", base_addr[CyRTPRH]);
2410 printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]);
2411 printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]);
2412 printk(" CyRBPR %x\n", base_addr[CyRBPR]);
2413 printk(" CyRCOR %x\n", base_addr[CyRCOR]);
2414 printk(" CyTBPR %x\n", base_addr[CyTBPR]);
2415 printk(" CyTCOR %x\n", base_addr[CyTCOR]);
2416
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002417 local_irq_restore(flags);
2418} /* show_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419#endif
2420
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421#if 0
2422/* Dummy routine in mvme16x/config.c for now */
2423
2424/* Serial console setup. Called from linux/init/main.c */
2425
2426void console_setup(char *str, int *ints)
2427{
2428 char *s;
2429 int baud, bits, parity;
2430 int cflag = 0;
2431
2432 /* Sanity check. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002433 if (ints[0] > 3 || ints[1] > 3)
2434 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
2436 /* Get baud, bits and parity */
2437 baud = 2400;
2438 bits = 8;
2439 parity = 'n';
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002440 if (ints[2])
2441 baud = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if ((s = strchr(str, ','))) {
2443 do {
2444 s++;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002445 } while (*s >= '0' && *s <= '9');
2446 if (*s)
2447 parity = *s++;
2448 if (*s)
2449 bits = *s - '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 }
2451
2452 /* Now construct a cflag setting. */
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002453 switch (baud) {
2454 case 1200:
2455 cflag |= B1200;
2456 break;
2457 case 9600:
2458 cflag |= B9600;
2459 break;
2460 case 19200:
2461 cflag |= B19200;
2462 break;
2463 case 38400:
2464 cflag |= B38400;
2465 break;
2466 case 2400:
2467 default:
2468 cflag |= B2400;
2469 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002471 switch (bits) {
2472 case 7:
2473 cflag |= CS7;
2474 break;
2475 default:
2476 case 8:
2477 cflag |= CS8;
2478 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 }
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002480 switch (parity) {
2481 case 'o':
2482 case 'O':
2483 cflag |= PARODD;
2484 break;
2485 case 'e':
2486 case 'E':
2487 cflag |= PARENB;
2488 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 }
2490
2491 serial_console_info = &cy_port[ints[1]];
2492 serial_console_cflag = cflag;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002493 serial_console = ints[1] + 64; /*callout_driver.minor_start */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494}
2495#endif
2496
2497/*
2498 * The following is probably out of date for 2.1.x serial console stuff.
2499 *
2500 * The console is registered early on from arch/m68k/kernel/setup.c, and
2501 * it therefore relies on the chip being setup correctly by 166-Bug. This
2502 * seems reasonable, as the serial port has been used to invoke the system
2503 * boot. It also means that this function must not rely on any data
2504 * initialisation performed by serial167_init() etc.
2505 *
2506 * Of course, once the console has been registered, we had better ensure
2507 * that serial167_init() doesn't leave the chip non-functional.
2508 *
2509 * The console must be locked when we get here.
2510 */
2511
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002512void serial167_console_write(struct console *co, const char *str,
2513 unsigned count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002515 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 unsigned long flags;
2517 volatile u_char sink;
2518 u_char ier;
2519 int port;
2520 u_char do_lf = 0;
2521 int i = 0;
2522
2523 local_irq_save(flags);
2524
2525 /* Ensure transmitter is enabled! */
2526
2527 port = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002528 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 while (base_addr[CyCCR])
2530 ;
2531 base_addr[CyCCR] = CyENB_XMTR;
2532
2533 ier = base_addr[CyIER];
2534 base_addr[CyIER] = CyTxMpty;
2535
2536 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002537 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 /* We have a Tx int. Acknowledge it */
2539 sink = pcc2chip[PccTPIACKR];
2540 if ((base_addr[CyLICR] >> 2) == port) {
2541 if (i == count) {
2542 /* Last char of string is now output */
2543 base_addr[CyTEOIR] = CyNOTRANS;
2544 break;
2545 }
2546 if (do_lf) {
2547 base_addr[CyTDR] = '\n';
2548 str++;
2549 i++;
2550 do_lf = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002551 } else if (*str == '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 base_addr[CyTDR] = '\r';
2553 do_lf = 1;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002554 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 base_addr[CyTDR] = *str++;
2556 i++;
2557 }
2558 base_addr[CyTEOIR] = 0;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002559 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 base_addr[CyTEOIR] = CyNOTRANS;
2561 }
2562 }
2563
2564 base_addr[CyIER] = ier;
2565
2566 local_irq_restore(flags);
2567}
2568
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002569static struct tty_driver *serial167_console_device(struct console *c,
2570 int *index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571{
2572 *index = c->index;
2573 return cy_serial_driver;
2574}
2575
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576static int __init serial167_console_setup(struct console *co, char *options)
2577{
2578 return 0;
2579}
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581static struct console sercons = {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002582 .name = "ttyS",
2583 .write = serial167_console_write,
2584 .device = serial167_console_device,
2585 .setup = serial167_console_setup,
2586 .flags = CON_PRINTBUFFER,
2587 .index = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588};
2589
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590static int __init serial167_console_init(void)
2591{
2592 if (vme_brdtype == VME_TYPE_MVME166 ||
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002593 vme_brdtype == VME_TYPE_MVME167 ||
2594 vme_brdtype == VME_TYPE_MVME177) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 mvme167_serial_console_setup(0);
2596 register_console(&sercons);
2597 }
2598 return 0;
2599}
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601console_initcall(serial167_console_init);
2602
2603#ifdef CONFIG_REMOTE_DEBUG
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002604void putDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002606 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 unsigned long flags;
2608 volatile u_char sink;
2609 u_char ier;
2610 int port;
2611
2612 local_irq_save(flags);
2613
2614 /* Ensure transmitter is enabled! */
2615
2616 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002617 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 while (base_addr[CyCCR])
2619 ;
2620 base_addr[CyCCR] = CyENB_XMTR;
2621
2622 ier = base_addr[CyIER];
2623 base_addr[CyIER] = CyTxMpty;
2624
2625 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002626 if (pcc2chip[PccSCCTICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 /* We have a Tx int. Acknowledge it */
2628 sink = pcc2chip[PccTPIACKR];
2629 if ((base_addr[CyLICR] >> 2) == port) {
2630 base_addr[CyTDR] = c;
2631 base_addr[CyTEOIR] = 0;
2632 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002633 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 base_addr[CyTEOIR] = CyNOTRANS;
2635 }
2636 }
2637
2638 base_addr[CyIER] = ier;
2639
2640 local_irq_restore(flags);
2641}
2642
2643int getDebugChar()
2644{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002645 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 unsigned long flags;
2647 volatile u_char sink;
2648 u_char ier;
2649 int port;
2650 int i, c;
2651
2652 i = debugiq.out;
2653 if (i != debugiq.in) {
2654 c = debugiq.buf[i];
2655 if (++i == DEBUG_LEN)
2656 i = 0;
2657 debugiq.out = i;
2658 return c;
2659 }
2660 /* OK, nothing in queue, wait in poll loop */
2661
2662 local_irq_save(flags);
2663
2664 /* Ensure receiver is enabled! */
2665
2666 port = DEBUG_PORT;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002667 base_addr[CyCAR] = (u_char) port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668#if 0
2669 while (base_addr[CyCCR])
2670 ;
2671 base_addr[CyCCR] = CyENB_RCVR;
2672#endif
2673 ier = base_addr[CyIER];
2674 base_addr[CyIER] = CyRxData;
2675
2676 while (1) {
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002677 if (pcc2chip[PccSCCRICR] & 0x20) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 /* We have a Rx int. Acknowledge it */
2679 sink = pcc2chip[PccRPIACKR];
2680 if ((base_addr[CyLICR] >> 2) == port) {
2681 int cnt = base_addr[CyRFOC];
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002682 while (cnt-- > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 c = base_addr[CyRDR];
2684 if (c == 0)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002685 printk
2686 ("!! debug char is null (cnt=%d) !!",
2687 cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 else
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002689 queueDebugChar(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 }
2691 base_addr[CyREOIR] = 0;
2692 i = debugiq.out;
2693 if (i == debugiq.in)
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002694 panic("Debug input queue empty!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 c = debugiq.buf[i];
2696 if (++i == DEBUG_LEN)
2697 i = 0;
2698 debugiq.out = i;
2699 break;
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002700 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 base_addr[CyREOIR] = CyNOTRANS;
2702 }
2703 }
2704
2705 base_addr[CyIER] = ier;
2706
2707 local_irq_restore(flags);
2708
2709 return (c);
2710}
2711
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002712void queueDebugChar(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713{
2714 int i;
2715
2716 i = debugiq.in;
2717 debugiq.buf[i] = c;
2718 if (++i == DEBUG_LEN)
2719 i = 0;
2720 if (i != debugiq.out)
2721 debugiq.in = i;
2722}
2723
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002724static void debug_setup()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725{
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002726 unsigned long flags;
2727 volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
2728 int i, cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002730 cflag = B19200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002732 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002734 for (i = 0; i < 4; i++) {
2735 base_addr[CyCAR] = i;
2736 base_addr[CyLICR] = i << 2;
2737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002739 debugiq.in = debugiq.out = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002741 base_addr[CyCAR] = DEBUG_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002743 /* baud rate */
2744 i = cflag & CBAUD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002746 base_addr[CyIER] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002748 base_addr[CyCMR] = CyASYNC;
2749 base_addr[CyLICR] = DEBUG_PORT << 2;
2750 base_addr[CyLIVR] = 0x5c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002752 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002754 base_addr[CyTCOR] = baud_co[i];
2755 base_addr[CyTBPR] = baud_bpr[i];
2756 base_addr[CyRCOR] = baud_co[i] >> 5;
2757 base_addr[CyRBPR] = baud_bpr[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002759 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002761 base_addr[CySCHR1] = 0;
2762 base_addr[CySCHR2] = 0;
2763 base_addr[CySCRL] = 0;
2764 base_addr[CySCRH] = 0;
2765 base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
2766 base_addr[CyCOR2] = 0;
2767 base_addr[CyCOR3] = Cy_1_STOP;
2768 base_addr[CyCOR4] = baud_cor4[i];
2769 base_addr[CyCOR5] = 0;
2770 base_addr[CyCOR6] = 0;
2771 base_addr[CyCOR7] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002773 write_cy_cmd(base_addr, CyINIT_CHAN);
2774 write_cy_cmd(base_addr, CyENB_RCVR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002776 base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002778 base_addr[CyRTPRL] = 2;
2779 base_addr[CyRTPRH] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002781 base_addr[CyMSVR1] = CyRTS;
2782 base_addr[CyMSVR2] = CyDTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002784 base_addr[CyIER] = CyRxData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002786 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
Jiri Slaby44bafdf2007-02-10 01:45:08 -08002788} /* debug_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790#endif
2791
2792MODULE_LICENSE("GPL");