blob: f0d5039a7b34c774ff534a33713231e110b7107c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 68328serial.c: Serial port driver for 68328 microcontroller
2 *
3 * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
4 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
5 * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
6 * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
7 * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
8 * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
9 *
10 * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
11 * Multiple UART support Daniel Potts <danielp@cse.unsw.edu.au>
12 * Power management support Daniel Potts <danielp@cse.unsw.edu.au>
13 * VZ Second Serial Port enable Phil Wilshire
14 * 2.4/2.5 port David McCullough
15 */
16
17#include <asm/dbg.h>
18#include <linux/module.h>
19#include <linux/errno.h>
Jiri Slabycea4b2c2012-04-02 13:54:35 +020020#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/signal.h>
22#include <linux/sched.h>
23#include <linux/timer.h>
24#include <linux/interrupt.h>
25#include <linux/tty.h>
26#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/major.h>
28#include <linux/string.h>
29#include <linux/fcntl.h>
30#include <linux/mm.h>
31#include <linux/kernel.h>
32#include <linux/console.h>
33#include <linux/reboot.h>
34#include <linux/keyboard.h>
35#include <linux/init.h>
36#include <linux/pm.h>
37#include <linux/bitops.h>
38#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090039#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#include <asm/io.h>
42#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/delay.h>
44#include <asm/uaccess.h>
45
46/* (es) */
47/* note: perhaps we can murge these files, so that you can just
48 * define 1 of them, and they can sort that out for themselves
49 */
50#if defined(CONFIG_M68EZ328)
51#include <asm/MC68EZ328.h>
52#else
53#if defined(CONFIG_M68VZ328)
54#include <asm/MC68VZ328.h>
55#else
56#include <asm/MC68328.h>
57#endif /* CONFIG_M68VZ328 */
58#endif /* CONFIG_M68EZ328 */
59
60#include "68328serial.h"
61
62/* Turn off usage of real serial interrupt code, to "support" Copilot */
63#ifdef CONFIG_XCOPILOT_BUGS
64#undef USE_INTS
65#else
66#define USE_INTS
67#endif
68
69static struct m68k_serial m68k_soft[NR_PORTS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
72
73/* multiple ports are contiguous in memory */
74m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076struct tty_driver *serial_driver;
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static void change_speed(struct m68k_serial *info);
79
80/*
81 * Setup for console. Argument comes from the boot command line.
82 */
83
Christoph Eggerf5e92c32010-07-20 15:26:54 -070084/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
85#ifdef CONFIG_M68VZ328
86#define CONSOLE_BAUD_RATE 19200
87#define DEFAULT_CBAUD B19200
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#endif
89
Christoph Eggerf5e92c32010-07-20 15:26:54 -070090
Linus Torvalds1da177e2005-04-16 15:20:36 -070091#ifndef CONSOLE_BAUD_RATE
92#define CONSOLE_BAUD_RATE 9600
93#define DEFAULT_CBAUD B9600
94#endif
95
96
97static int m68328_console_initted = 0;
98static int m68328_console_baud = CONSOLE_BAUD_RATE;
99static int m68328_console_cbaud = DEFAULT_CBAUD;
100
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static inline int serial_paranoia_check(struct m68k_serial *info,
103 char *name, const char *routine)
104{
105#ifdef SERIAL_PARANOIA_CHECK
106 static const char *badmagic =
107 "Warning: bad magic number for serial struct %s in %s\n";
108 static const char *badinfo =
109 "Warning: null m68k_serial for %s in %s\n";
110
111 if (!info) {
112 printk(badinfo, name, routine);
113 return 1;
114 }
115 if (info->magic != SERIAL_MAGIC) {
116 printk(badmagic, name, routine);
117 return 1;
118 }
119#endif
120 return 0;
121}
122
123/*
124 * This is used to figure out the divisor speeds and the timeouts
125 */
126static int baud_table[] = {
127 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
128 9600, 19200, 38400, 57600, 115200, 0 };
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130/* Utility routines */
131static inline int get_baud(struct m68k_serial *ss)
132{
133 unsigned long result = 115200;
134 unsigned short int baud = uart_addr[ss->line].ubaud;
135 if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
136 result >>= GET_FIELD(baud, UBAUD_DIVIDE);
137
138 return result;
139}
140
141/*
142 * ------------------------------------------------------------
143 * rs_stop() and rs_start()
144 *
145 * This routines are called before setting or resetting tty->stopped.
146 * They enable or disable transmitter interrupts, as necessary.
147 * ------------------------------------------------------------
148 */
149static void rs_stop(struct tty_struct *tty)
150{
151 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
152 m68328_uart *uart = &uart_addr[info->line];
153 unsigned long flags;
154
155 if (serial_paranoia_check(info, tty->name, "rs_stop"))
156 return;
157
Greg Ungerer727dda82006-06-28 15:54:22 +1000158 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 uart->ustcnt &= ~USTCNT_TXEN;
Greg Ungerer727dda82006-06-28 15:54:22 +1000160 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}
162
Alan Cox09a6ffa2008-04-30 00:54:01 -0700163static int rs_put_char(char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164{
Jiri Slaby107afb72012-04-02 13:54:38 +0200165 unsigned long flags;
166 int loops = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Greg Ungerer727dda82006-06-28 15:54:22 +1000168 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170 while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
171 loops++;
172 udelay(5);
173 }
174
175 UTX_TXDATA = ch;
176 udelay(5);
Greg Ungerer727dda82006-06-28 15:54:22 +1000177 local_irq_restore(flags);
Alan Cox09a6ffa2008-04-30 00:54:01 -0700178 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
181static void rs_start(struct tty_struct *tty)
182{
183 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
184 m68328_uart *uart = &uart_addr[info->line];
185 unsigned long flags;
186
187 if (serial_paranoia_check(info, tty->name, "rs_start"))
188 return;
189
Greg Ungerer727dda82006-06-28 15:54:22 +1000190 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
192#ifdef USE_INTS
193 uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
194#else
195 uart->ustcnt |= USTCNT_TXEN;
196#endif
197 }
Greg Ungerer727dda82006-06-28 15:54:22 +1000198 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
David Howells7d12e782006-10-05 14:55:46 +0100201static void receive_chars(struct m68k_serial *info, unsigned short rx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000203 struct tty_struct *tty = info->tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 m68328_uart *uart = &uart_addr[info->line];
Alan Cox33f0f882006-01-09 20:54:13 -0800205 unsigned char ch, flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 /*
208 * This do { } while() loop will get ALL chars out of Rx FIFO
209 */
210#ifndef CONFIG_XCOPILOT_BUGS
211 do {
212#endif
213 ch = GET_FIELD(rx, URX_RXDATA);
214
215 if(info->is_cons) {
216 if(URX_BREAK & rx) { /* whee, break received */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return;
218#ifdef CONFIG_MAGIC_SYSRQ
219 } else if (ch == 0x10) { /* ^P */
220 show_state();
David Rientjes7bf02ea2011-05-24 17:11:16 -0700221 show_free_areas(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 show_buffers();
223/* show_net_buffers(); */
224 return;
225 } else if (ch == 0x12) { /* ^R */
Eric W. Biederman804ebf42005-07-26 11:59:54 -0600226 emergency_restart();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 return;
228#endif /* CONFIG_MAGIC_SYSRQ */
229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 }
231
232 if(!tty)
233 goto clear_and_exit;
234
Alan Cox33f0f882006-01-09 20:54:13 -0800235 flag = TTY_NORMAL;
236
Jiri Slabyc21e2652012-04-02 13:54:36 +0200237 if (rx & URX_PARITY_ERROR)
Alan Cox33f0f882006-01-09 20:54:13 -0800238 flag = TTY_PARITY;
Jiri Slabyc21e2652012-04-02 13:54:36 +0200239 else if (rx & URX_OVRUN)
Alan Cox33f0f882006-01-09 20:54:13 -0800240 flag = TTY_OVERRUN;
Jiri Slabyc21e2652012-04-02 13:54:36 +0200241 else if (rx & URX_FRAME_ERROR)
Alan Cox33f0f882006-01-09 20:54:13 -0800242 flag = TTY_FRAME;
Jiri Slabyc21e2652012-04-02 13:54:36 +0200243
Alan Cox33f0f882006-01-09 20:54:13 -0800244 tty_insert_flip_char(tty, ch, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245#ifndef CONFIG_XCOPILOT_BUGS
246 } while((rx = uart->urx.w) & URX_DATA_READY);
247#endif
248
Greg Ungerer8e63e662006-02-08 09:19:17 +1000249 tty_schedule_flip(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251clear_and_exit:
252 return;
253}
254
Adrian Bunk41c28ff2006-03-23 03:00:56 -0800255static void transmit_chars(struct m68k_serial *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
257 m68328_uart *uart = &uart_addr[info->line];
258
259 if (info->x_char) {
260 /* Send next char */
261 uart->utx.b.txdata = info->x_char;
262 info->x_char = 0;
263 goto clear_and_return;
264 }
265
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000266 if((info->xmit_cnt <= 0) || info->tty->stopped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 /* That's peculiar... TX ints off */
268 uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
269 goto clear_and_return;
270 }
271
272 /* Send char */
273 uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
274 info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
275 info->xmit_cnt--;
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 if(info->xmit_cnt <= 0) {
278 /* All done for now... TX ints off */
279 uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
280 goto clear_and_return;
281 }
282
283clear_and_return:
284 /* Clear interrupt (should be auto)*/
285 return;
286}
287
288/*
289 * This is the serial driver's generic interrupt routine
290 */
David Howells7d12e782006-10-05 14:55:46 +0100291irqreturn_t rs_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Alan Cox25db8ad2008-08-19 20:49:40 -0700293 struct m68k_serial *info = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 m68328_uart *uart;
295 unsigned short rx;
296 unsigned short tx;
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 uart = &uart_addr[info->line];
299 rx = uart->urx.w;
300
301#ifdef USE_INTS
302 tx = uart->utx.w;
303
David Howells7d12e782006-10-05 14:55:46 +0100304 if (rx & URX_DATA_READY) receive_chars(info, rx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 if (tx & UTX_TX_AVAIL) transmit_chars(info);
306#else
David Howells7d12e782006-10-05 14:55:46 +0100307 receive_chars(info, rx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308#endif
309 return IRQ_HANDLED;
310}
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312static int startup(struct m68k_serial * info)
313{
314 m68328_uart *uart = &uart_addr[info->line];
315 unsigned long flags;
316
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200317 if (info->flags & ASYNC_INITIALIZED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 return 0;
319
320 if (!info->xmit_buf) {
321 info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
322 if (!info->xmit_buf)
323 return -ENOMEM;
324 }
325
Greg Ungerer727dda82006-06-28 15:54:22 +1000326 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 /*
329 * Clear the FIFO buffers and disable them
330 * (they will be reenabled in change_speed())
331 */
332
333 uart->ustcnt = USTCNT_UEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
335 (void)uart->urx.w;
336
337 /*
338 * Finally, enable sequencing and interrupts
339 */
340#ifdef USE_INTS
341 uart->ustcnt = USTCNT_UEN | USTCNT_RXEN |
342 USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
343#else
344 uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
345#endif
346
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000347 if (info->tty)
348 clear_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
350
351 /*
352 * and set the speed of the serial port
353 */
354
355 change_speed(info);
356
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200357 info->flags |= ASYNC_INITIALIZED;
Greg Ungerer727dda82006-06-28 15:54:22 +1000358 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 return 0;
360}
361
362/*
363 * This routine will shutdown a serial port; interrupts are disabled, and
364 * DTR is dropped if the hangup on close termio flag is on.
365 */
366static void shutdown(struct m68k_serial * info)
367{
368 m68328_uart *uart = &uart_addr[info->line];
369 unsigned long flags;
370
371 uart->ustcnt = 0; /* All off! */
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200372 if (!(info->flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return;
374
Greg Ungerer727dda82006-06-28 15:54:22 +1000375 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 if (info->xmit_buf) {
378 free_page((unsigned long) info->xmit_buf);
379 info->xmit_buf = 0;
380 }
381
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000382 if (info->tty)
383 set_bit(TTY_IO_ERROR, &info->tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200385 info->flags &= ~ASYNC_INITIALIZED;
Greg Ungerer727dda82006-06-28 15:54:22 +1000386 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
389struct {
390 int divisor, prescale;
391}
392#ifndef CONFIG_M68VZ328
393 hw_baud_table[18] = {
394 {0,0}, /* 0 */
395 {0,0}, /* 50 */
396 {0,0}, /* 75 */
397 {0,0}, /* 110 */
398 {0,0}, /* 134 */
399 {0,0}, /* 150 */
400 {0,0}, /* 200 */
401 {7,0x26}, /* 300 */
402 {6,0x26}, /* 600 */
403 {5,0x26}, /* 1200 */
404 {0,0}, /* 1800 */
405 {4,0x26}, /* 2400 */
406 {3,0x26}, /* 4800 */
407 {2,0x26}, /* 9600 */
408 {1,0x26}, /* 19200 */
409 {0,0x26}, /* 38400 */
410 {1,0x38}, /* 57600 */
411 {0,0x38}, /* 115200 */
412};
413#else
414 hw_baud_table[18] = {
415 {0,0}, /* 0 */
416 {0,0}, /* 50 */
417 {0,0}, /* 75 */
418 {0,0}, /* 110 */
419 {0,0}, /* 134 */
420 {0,0}, /* 150 */
421 {0,0}, /* 200 */
422 {0,0}, /* 300 */
423 {7,0x26}, /* 600 */
424 {6,0x26}, /* 1200 */
425 {0,0}, /* 1800 */
426 {5,0x26}, /* 2400 */
427 {4,0x26}, /* 4800 */
428 {3,0x26}, /* 9600 */
429 {2,0x26}, /* 19200 */
430 {1,0x26}, /* 38400 */
431 {0,0x26}, /* 57600 */
432 {1,0x38}, /* 115200 */
433};
434#endif
435/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
436
437/*
438 * This routine is called to set the UART divisor registers to match
439 * the specified baud rate for a serial port.
440 */
441static void change_speed(struct m68k_serial *info)
442{
443 m68328_uart *uart = &uart_addr[info->line];
444 unsigned short port;
445 unsigned short ustcnt;
446 unsigned cflag;
447 int i;
448
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000449 if (!info->tty || !info->tty->termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return;
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000451 cflag = info->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (!(port = info->port))
453 return;
454
455 ustcnt = uart->ustcnt;
456 uart->ustcnt = ustcnt & ~USTCNT_TXEN;
457
458 i = cflag & CBAUD;
459 if (i & CBAUDEX) {
460 i = (i & ~CBAUDEX) + B38400;
461 }
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
464 PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
465
466 ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
467
468 if ((cflag & CSIZE) == CS8)
469 ustcnt |= USTCNT_8_7;
470
471 if (cflag & CSTOPB)
472 ustcnt |= USTCNT_STOP;
473
474 if (cflag & PARENB)
475 ustcnt |= USTCNT_PARITYEN;
476 if (cflag & PARODD)
477 ustcnt |= USTCNT_ODD_EVEN;
478
479#ifdef CONFIG_SERIAL_68328_RTS_CTS
480 if (cflag & CRTSCTS) {
481 uart->utx.w &= ~ UTX_NOCTS;
482 } else {
483 uart->utx.w |= UTX_NOCTS;
484 }
485#endif
486
487 ustcnt |= USTCNT_TXEN;
488
489 uart->ustcnt = ustcnt;
490 return;
491}
492
493/*
494 * Fair output driver allows a process to speak.
495 */
496static void rs_fair_output(void)
497{
498 int left; /* Output no more than that */
499 unsigned long flags;
500 struct m68k_serial *info = &m68k_soft[0];
501 char c;
502
503 if (info == 0) return;
504 if (info->xmit_buf == 0) return;
505
Greg Ungerer727dda82006-06-28 15:54:22 +1000506 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 left = info->xmit_cnt;
508 while (left != 0) {
509 c = info->xmit_buf[info->xmit_tail];
510 info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
511 info->xmit_cnt--;
Greg Ungerer727dda82006-06-28 15:54:22 +1000512 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 rs_put_char(c);
515
Greg Ungerer727dda82006-06-28 15:54:22 +1000516 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 left = min(info->xmit_cnt, left-1);
518 }
519
520 /* Last character is being transmitted now (hopefully). */
521 udelay(5);
522
Greg Ungerer727dda82006-06-28 15:54:22 +1000523 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return;
525}
526
527/*
528 * m68k_console_print is registered for printk.
529 */
530void console_print_68328(const char *p)
531{
532 char c;
533
534 while((c=*(p++)) != 0) {
535 if(c == '\n')
536 rs_put_char('\r');
537 rs_put_char(c);
538 }
539
540 /* Comment this if you want to have a strict interrupt-driven output */
541 rs_fair_output();
542
543 return;
544}
545
546static void rs_set_ldisc(struct tty_struct *tty)
547{
548 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
549
550 if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
551 return;
552
553 info->is_cons = (tty->termios->c_line == N_TTY);
554
555 printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
556}
557
558static void rs_flush_chars(struct tty_struct *tty)
559{
560 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
561 m68328_uart *uart = &uart_addr[info->line];
562 unsigned long flags;
563
564 if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
565 return;
566#ifndef USE_INTS
567 for(;;) {
568#endif
569
570 /* Enable transmitter */
Greg Ungerer727dda82006-06-28 15:54:22 +1000571 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
574 !info->xmit_buf) {
Greg Ungerer727dda82006-06-28 15:54:22 +1000575 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return;
577 }
578
579#ifdef USE_INTS
580 uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
581#else
582 uart->ustcnt |= USTCNT_TXEN;
583#endif
584
585#ifdef USE_INTS
586 if (uart->utx.w & UTX_TX_AVAIL) {
587#else
588 if (1) {
589#endif
590 /* Send char */
591 uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
592 info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
593 info->xmit_cnt--;
594 }
595
596#ifndef USE_INTS
597 while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
598 }
599#endif
Greg Ungerer727dda82006-06-28 15:54:22 +1000600 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603extern void console_printn(const char * b, int count);
604
605static int rs_write(struct tty_struct * tty,
606 const unsigned char *buf, int count)
607{
608 int c, total = 0;
609 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
610 m68328_uart *uart = &uart_addr[info->line];
611 unsigned long flags;
612
613 if (serial_paranoia_check(info, tty->name, "rs_write"))
614 return 0;
615
616 if (!tty || !info->xmit_buf)
617 return 0;
618
Greg Ungerer727dda82006-06-28 15:54:22 +1000619 local_save_flags(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 while (1) {
Greg Ungerer727dda82006-06-28 15:54:22 +1000621 local_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
623 SERIAL_XMIT_SIZE - info->xmit_head));
Greg Ungerer727dda82006-06-28 15:54:22 +1000624 local_irq_restore(flags);
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (c <= 0)
627 break;
628
629 memcpy(info->xmit_buf + info->xmit_head, buf, c);
Greg Ungerer727dda82006-06-28 15:54:22 +1000630
631 local_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
633 info->xmit_cnt += c;
Greg Ungerer727dda82006-06-28 15:54:22 +1000634 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 buf += c;
636 count -= c;
637 total += c;
638 }
639
640 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
641 /* Enable transmitter */
Greg Ungerer727dda82006-06-28 15:54:22 +1000642 local_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643#ifndef USE_INTS
644 while(info->xmit_cnt) {
645#endif
646
647 uart->ustcnt |= USTCNT_TXEN;
648#ifdef USE_INTS
649 uart->ustcnt |= USTCNT_TX_INTR_MASK;
650#else
651 while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
652#endif
653 if (uart->utx.w & UTX_TX_AVAIL) {
654 uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
655 info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
656 info->xmit_cnt--;
657 }
658
659#ifndef USE_INTS
660 }
661#endif
Greg Ungerer727dda82006-06-28 15:54:22 +1000662 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
Greg Ungerer727dda82006-06-28 15:54:22 +1000664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return total;
666}
667
668static int rs_write_room(struct tty_struct *tty)
669{
670 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
671 int ret;
672
673 if (serial_paranoia_check(info, tty->name, "rs_write_room"))
674 return 0;
675 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
676 if (ret < 0)
677 ret = 0;
678 return ret;
679}
680
681static int rs_chars_in_buffer(struct tty_struct *tty)
682{
683 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
684
685 if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
686 return 0;
687 return info->xmit_cnt;
688}
689
690static void rs_flush_buffer(struct tty_struct *tty)
691{
692 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
Greg Ungerer727dda82006-06-28 15:54:22 +1000693 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
696 return;
Greg Ungerer727dda82006-06-28 15:54:22 +1000697 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Greg Ungerer727dda82006-06-28 15:54:22 +1000699 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 tty_wakeup(tty);
701}
702
703/*
704 * ------------------------------------------------------------
705 * rs_throttle()
706 *
707 * This routine is called by the upper-layer tty layer to signal that
708 * incoming characters should be throttled.
709 * ------------------------------------------------------------
710 */
711static void rs_throttle(struct tty_struct * tty)
712{
713 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
714
715 if (serial_paranoia_check(info, tty->name, "rs_throttle"))
716 return;
717
718 if (I_IXOFF(tty))
719 info->x_char = STOP_CHAR(tty);
720
721 /* Turn off RTS line (do this atomic) */
722}
723
724static void rs_unthrottle(struct tty_struct * tty)
725{
726 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
727
728 if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
729 return;
730
731 if (I_IXOFF(tty)) {
732 if (info->x_char)
733 info->x_char = 0;
734 else
735 info->x_char = START_CHAR(tty);
736 }
737
738 /* Assert RTS line (do this atomic) */
739}
740
741/*
742 * ------------------------------------------------------------
743 * rs_ioctl() and friends
744 * ------------------------------------------------------------
745 */
746
747static int get_serial_info(struct m68k_serial * info,
748 struct serial_struct * retinfo)
749{
750 struct serial_struct tmp;
751
752 if (!retinfo)
753 return -EFAULT;
754 memset(&tmp, 0, sizeof(tmp));
755 tmp.type = info->type;
756 tmp.line = info->line;
757 tmp.port = info->port;
758 tmp.irq = info->irq;
759 tmp.flags = info->flags;
760 tmp.baud_base = info->baud_base;
761 tmp.close_delay = info->close_delay;
762 tmp.closing_wait = info->closing_wait;
763 tmp.custom_divisor = info->custom_divisor;
Kulikov Vasiliy5d563562010-08-01 10:29:06 +0400764 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
765 return -EFAULT;
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return 0;
768}
769
770static int set_serial_info(struct m68k_serial * info,
771 struct serial_struct * new_info)
772{
773 struct serial_struct new_serial;
774 struct m68k_serial old_info;
775 int retval = 0;
776
777 if (!new_info)
778 return -EFAULT;
Kulikov Vasiliy5d563562010-08-01 10:29:06 +0400779 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
780 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 old_info = *info;
782
783 if (!capable(CAP_SYS_ADMIN)) {
784 if ((new_serial.baud_base != info->baud_base) ||
785 (new_serial.type != info->type) ||
786 (new_serial.close_delay != info->close_delay) ||
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200787 ((new_serial.flags & ~ASYNC_USR_MASK) !=
788 (info->flags & ~ASYNC_USR_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return -EPERM;
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200790 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
791 (new_serial.flags & ASYNC_USR_MASK));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 info->custom_divisor = new_serial.custom_divisor;
793 goto check_and_exit;
794 }
795
796 if (info->count > 1)
797 return -EBUSY;
798
799 /*
800 * OK, past this point, all the error checking has been done.
801 * At this point, we start making changes.....
802 */
803
804 info->baud_base = new_serial.baud_base;
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200805 info->flags = ((info->flags & ~ASYNC_FLAGS) |
806 (new_serial.flags & ASYNC_FLAGS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 info->type = new_serial.type;
808 info->close_delay = new_serial.close_delay;
809 info->closing_wait = new_serial.closing_wait;
810
811check_and_exit:
812 retval = startup(info);
813 return retval;
814}
815
816/*
817 * get_lsr_info - get line status register info
818 *
819 * Purpose: Let user call ioctl() to get info when the UART physically
820 * is emptied. On bus types like RS485, the transmitter must
821 * release the bus after transmitting. This must be done when
822 * the transmit shift register is empty, not be done when the
823 * transmit holding register is empty. This functionality
824 * allows an RS485 driver to be written in user space.
825 */
826static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
827{
828#ifdef CONFIG_SERIAL_68328_RTS_CTS
829 m68328_uart *uart = &uart_addr[info->line];
830#endif
831 unsigned char status;
Greg Ungerer727dda82006-06-28 15:54:22 +1000832 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Greg Ungerer727dda82006-06-28 15:54:22 +1000834 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835#ifdef CONFIG_SERIAL_68328_RTS_CTS
836 status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
837#else
838 status = 0;
839#endif
Greg Ungerer727dda82006-06-28 15:54:22 +1000840 local_irq_restore(flags);
Kulikov Vasiliy5d563562010-08-01 10:29:06 +0400841 return put_user(status, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842}
843
844/*
845 * This routine sends a break character out the serial port.
846 */
Nishanth Aravamudan6a72c7b2005-06-25 14:59:33 -0700847static void send_break(struct m68k_serial * info, unsigned int duration)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 m68328_uart *uart = &uart_addr[info->line];
850 unsigned long flags;
851 if (!info->port)
852 return;
Greg Ungerer727dda82006-06-28 15:54:22 +1000853 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854#ifdef USE_INTS
855 uart->utx.w |= UTX_SEND_BREAK;
Nishanth Aravamudan6a72c7b2005-06-25 14:59:33 -0700856 msleep_interruptible(duration);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 uart->utx.w &= ~UTX_SEND_BREAK;
858#endif
Greg Ungerer727dda82006-06-28 15:54:22 +1000859 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Alan Cox6caa76b2011-02-14 16:27:22 +0000862static int rs_ioctl(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 unsigned int cmd, unsigned long arg)
864{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
866 int retval;
867
868 if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
869 return -ENODEV;
870
871 if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
872 (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
873 (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
874 if (tty->flags & (1 << TTY_IO_ERROR))
875 return -EIO;
876 }
877
878 switch (cmd) {
879 case TCSBRK: /* SVID version: non-zero arg --> no break */
880 retval = tty_check_change(tty);
881 if (retval)
882 return retval;
883 tty_wait_until_sent(tty, 0);
884 if (!arg)
Nishanth Aravamudan6a72c7b2005-06-25 14:59:33 -0700885 send_break(info, 250); /* 1/4 second */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return 0;
887 case TCSBRKP: /* support for POSIX tcsendbreak() */
888 retval = tty_check_change(tty);
889 if (retval)
890 return retval;
891 tty_wait_until_sent(tty, 0);
Nishanth Aravamudan6a72c7b2005-06-25 14:59:33 -0700892 send_break(info, arg ? arg*(100) : 250);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 case TIOCGSERIAL:
Kulikov Vasiliy5d563562010-08-01 10:29:06 +0400895 return get_serial_info(info,
896 (struct serial_struct *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 case TIOCSSERIAL:
898 return set_serial_info(info,
899 (struct serial_struct *) arg);
900 case TIOCSERGETLSR: /* Get line status register */
Kulikov Vasiliy5d563562010-08-01 10:29:06 +0400901 return get_lsr_info(info, (unsigned int *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 case TIOCSERGSTRUCT:
Kulikov Vasiliy5d563562010-08-01 10:29:06 +0400903 if (copy_to_user((struct m68k_serial *) arg,
904 info, sizeof(struct m68k_serial)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 default:
908 return -ENOIOCTLCMD;
909 }
910 return 0;
911}
912
Alan Cox606d0992006-12-08 02:38:45 -0800913static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
915 struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 change_speed(info);
918
919 if ((old_termios->c_cflag & CRTSCTS) &&
920 !(tty->termios->c_cflag & CRTSCTS)) {
921 tty->hw_stopped = 0;
922 rs_start(tty);
923 }
924
925}
926
927/*
928 * ------------------------------------------------------------
929 * rs_close()
930 *
931 * This routine is called when the serial port gets closed. First, we
932 * wait for the last remaining data to be sent. Then, we unlink its
933 * S structure from the interrupt chain if necessary, and we free
934 * that IRQ if nothing is left in the chain.
935 * ------------------------------------------------------------
936 */
937static void rs_close(struct tty_struct *tty, struct file * filp)
938{
939 struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
940 m68328_uart *uart = &uart_addr[info->line];
941 unsigned long flags;
942
943 if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
944 return;
945
Greg Ungerer727dda82006-06-28 15:54:22 +1000946 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 if (tty_hung_up_p(filp)) {
Greg Ungerer727dda82006-06-28 15:54:22 +1000949 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 return;
951 }
952
953 if ((tty->count == 1) && (info->count != 1)) {
954 /*
955 * Uh, oh. tty->count is 1, which means that the tty
956 * structure will be freed. Info->count should always
957 * be one in these conditions. If it's greater than
958 * one, we've got real problems, since it means the
959 * serial port won't be shutdown.
960 */
961 printk("rs_close: bad serial port count; tty->count is 1, "
962 "info->count is %d\n", info->count);
963 info->count = 1;
964 }
965 if (--info->count < 0) {
966 printk("rs_close: bad serial port count for ttyS%d: %d\n",
967 info->line, info->count);
968 info->count = 0;
969 }
970 if (info->count) {
Greg Ungerer727dda82006-06-28 15:54:22 +1000971 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return;
973 }
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200974 info->flags |= ASYNC_CLOSING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 /*
976 * Now we wait for the transmit buffer to clear; and we notify
977 * the line discipline to only process XON/XOFF characters.
978 */
979 tty->closing = 1;
Jiri Slabycea4b2c2012-04-02 13:54:35 +0200980 if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 tty_wait_until_sent(tty, info->closing_wait);
982 /*
983 * At this point we stop accepting input. To do this, we
984 * disable the receive line status interrupts, and tell the
985 * interrupt driver to stop checking the data ready bit in the
986 * line status register.
987 */
988
989 uart->ustcnt &= ~USTCNT_RXEN;
990 uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
991
992 shutdown(info);
Alan Cox978e5952008-04-30 00:53:59 -0700993 rs_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 tty_ldisc_flush(tty);
996 tty->closing = 0;
Greg Ungererbc0c36d2011-02-08 21:32:36 +1000997 info->tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998#warning "This is not and has never been valid so fix it"
999#if 0
1000 if (tty->ldisc.num != ldiscs[N_TTY].num) {
1001 if (tty->ldisc.close)
1002 (tty->ldisc.close)(tty);
1003 tty->ldisc = ldiscs[N_TTY];
1004 tty->termios->c_line = N_TTY;
1005 if (tty->ldisc.open)
1006 (tty->ldisc.open)(tty);
1007 }
1008#endif
1009 if (info->blocked_open) {
1010 if (info->close_delay) {
1011 msleep_interruptible(jiffies_to_msecs(info->close_delay));
1012 }
1013 wake_up_interruptible(&info->open_wait);
1014 }
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001015 info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 wake_up_interruptible(&info->close_wait);
Greg Ungerer727dda82006-06-28 15:54:22 +10001017 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018}
1019
1020/*
1021 * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
1022 */
1023void rs_hangup(struct tty_struct *tty)
1024{
1025 struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
1026
1027 if (serial_paranoia_check(info, tty->name, "rs_hangup"))
1028 return;
1029
1030 rs_flush_buffer(tty);
1031 shutdown(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 info->count = 0;
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001033 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Greg Ungererbc0c36d2011-02-08 21:32:36 +10001034 info->tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 wake_up_interruptible(&info->open_wait);
1036}
1037
1038/*
1039 * ------------------------------------------------------------
1040 * rs_open() and friends
1041 * ------------------------------------------------------------
1042 */
1043static int block_til_ready(struct tty_struct *tty, struct file * filp,
1044 struct m68k_serial *info)
1045{
1046 DECLARE_WAITQUEUE(wait, current);
1047 int retval;
1048 int do_clocal = 0;
1049
1050 /*
1051 * If the device is in the middle of being closed, then block
1052 * until it's done, and then try again.
1053 */
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001054 if (info->flags & ASYNC_CLOSING) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 interruptible_sleep_on(&info->close_wait);
1056#ifdef SERIAL_DO_RESTART
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001057 if (info->flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return -EAGAIN;
1059 else
1060 return -ERESTARTSYS;
1061#else
1062 return -EAGAIN;
1063#endif
1064 }
1065
1066 /*
1067 * If non-blocking mode is set, or the port is not enabled,
1068 * then make the check up front and then exit.
1069 */
1070 if ((filp->f_flags & O_NONBLOCK) ||
1071 (tty->flags & (1 << TTY_IO_ERROR))) {
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001072 info->flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 return 0;
1074 }
1075
1076 if (tty->termios->c_cflag & CLOCAL)
1077 do_clocal = 1;
1078
1079 /*
1080 * Block waiting for the carrier detect and the line to become
1081 * free (i.e., not in use by the callout). While we are in
1082 * this loop, info->count is dropped by one, so that
1083 * rs_close() knows when to free things. We restore it upon
1084 * exit, either normal or abnormal.
1085 */
1086 retval = 0;
1087 add_wait_queue(&info->open_wait, &wait);
1088
1089 info->count--;
1090 info->blocked_open++;
1091 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 current->state = TASK_INTERRUPTIBLE;
1093 if (tty_hung_up_p(filp) ||
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001094 !(info->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095#ifdef SERIAL_DO_RESTART
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001096 if (info->flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 retval = -EAGAIN;
1098 else
1099 retval = -ERESTARTSYS;
1100#else
1101 retval = -EAGAIN;
1102#endif
1103 break;
1104 }
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001105 if (!(info->flags & ASYNC_CLOSING) && do_clocal)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 break;
1107 if (signal_pending(current)) {
1108 retval = -ERESTARTSYS;
1109 break;
1110 }
Arnd Bergmanne142a312010-06-01 22:53:10 +02001111 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001113 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115 current->state = TASK_RUNNING;
1116 remove_wait_queue(&info->open_wait, &wait);
1117 if (!tty_hung_up_p(filp))
1118 info->count++;
1119 info->blocked_open--;
1120
1121 if (retval)
1122 return retval;
Jiri Slabycea4b2c2012-04-02 13:54:35 +02001123 info->flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return 0;
1125}
1126
1127/*
1128 * This routine is called whenever a serial port is opened. It
1129 * enables interrupts for a serial port, linking in its S structure into
1130 * the IRQ chain. It also performs the serial-specific
1131 * initialization for the tty structure.
1132 */
1133int rs_open(struct tty_struct *tty, struct file * filp)
1134{
1135 struct m68k_serial *info;
Jiri Slaby410235f2012-03-05 14:52:01 +01001136 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Jiri Slaby410235f2012-03-05 14:52:01 +01001138 info = &m68k_soft[tty->index];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 if (serial_paranoia_check(info, tty->name, "rs_open"))
1141 return -ENODEV;
1142
1143 info->count++;
1144 tty->driver_data = info;
Greg Ungererbc0c36d2011-02-08 21:32:36 +10001145 info->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 /*
1148 * Start up serial port
1149 */
1150 retval = startup(info);
1151 if (retval)
1152 return retval;
1153
1154 return block_til_ready(tty, filp, info);
1155}
1156
1157/* Finally, routines used to initialize the serial driver. */
1158
1159static void show_serial_version(void)
1160{
1161 printk("MC68328 serial driver version 1.00\n");
1162}
1163
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001164static const struct tty_operations rs_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 .open = rs_open,
1166 .close = rs_close,
1167 .write = rs_write,
1168 .flush_chars = rs_flush_chars,
1169 .write_room = rs_write_room,
1170 .chars_in_buffer = rs_chars_in_buffer,
1171 .flush_buffer = rs_flush_buffer,
1172 .ioctl = rs_ioctl,
1173 .throttle = rs_throttle,
1174 .unthrottle = rs_unthrottle,
1175 .set_termios = rs_set_termios,
1176 .stop = rs_stop,
1177 .start = rs_start,
1178 .hangup = rs_hangup,
1179 .set_ldisc = rs_set_ldisc,
1180};
1181
1182/* rs_init inits the driver */
1183static int __init
1184rs68328_init(void)
1185{
Jiri Slaby107afb72012-04-02 13:54:38 +02001186 unsigned long flags;
1187 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 struct m68k_serial *info;
1189
1190 serial_driver = alloc_tty_driver(NR_PORTS);
1191 if (!serial_driver)
1192 return -ENOMEM;
1193
1194 show_serial_version();
1195
1196 /* Initialize the tty_driver structure */
1197 /* SPARC: Not all of this is exactly right for us. */
1198
1199 serial_driver->name = "ttyS";
1200 serial_driver->major = TTY_MAJOR;
1201 serial_driver->minor_start = 64;
1202 serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
1203 serial_driver->subtype = SERIAL_TYPE_NORMAL;
1204 serial_driver->init_termios = tty_std_termios;
1205 serial_driver->init_termios.c_cflag =
1206 m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
1207 serial_driver->flags = TTY_DRIVER_REAL_RAW;
1208 tty_set_operations(serial_driver, &rs_ops);
1209
1210 if (tty_register_driver(serial_driver)) {
1211 put_tty_driver(serial_driver);
1212 printk(KERN_ERR "Couldn't register serial driver\n");
1213 return -ENOMEM;
1214 }
1215
Greg Ungerer727dda82006-06-28 15:54:22 +10001216 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218 for(i=0;i<NR_PORTS;i++) {
1219
1220 info = &m68k_soft[i];
1221 info->magic = SERIAL_MAGIC;
1222 info->port = (int) &uart_addr[i];
Greg Ungererbc0c36d2011-02-08 21:32:36 +10001223 info->tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 info->irq = uart_irqs[i];
1225 info->custom_divisor = 16;
1226 info->close_delay = 50;
1227 info->closing_wait = 3000;
1228 info->x_char = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 info->count = 0;
1230 info->blocked_open = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 init_waitqueue_head(&info->open_wait);
1232 init_waitqueue_head(&info->close_wait);
1233 info->line = i;
1234 info->is_cons = 1; /* Means shortcuts work */
1235
1236 printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line,
1237 info->port, info->irq);
1238 printk(" is a builtin MC68328 UART\n");
1239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240#ifdef CONFIG_M68VZ328
1241 if (i > 0 )
1242 PJSEL &= 0xCF; /* PSW enable second port output */
1243#endif
1244
1245 if (request_irq(uart_irqs[i],
1246 rs_interrupt,
Yong Zhang9cfb5c02011-09-22 16:59:15 +08001247 0,
Alan Cox25db8ad2008-08-19 20:49:40 -07001248 "M68328_UART", info))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 panic("Unable to attach 68328 serial interrupt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 }
Greg Ungerer727dda82006-06-28 15:54:22 +10001251 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 return 0;
1253}
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255module_init(rs68328_init);
1256
1257
1258
1259static void m68328_set_baud(void)
1260{
1261 unsigned short ustcnt;
1262 int i;
1263
1264 ustcnt = USTCNT;
1265 USTCNT = ustcnt & ~USTCNT_TXEN;
1266
1267again:
Thiago Farina8b505ca2009-12-09 12:31:30 -08001268 for (i = 0; i < ARRAY_SIZE(baud_table); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if (baud_table[i] == m68328_console_baud)
1270 break;
Thiago Farina8b505ca2009-12-09 12:31:30 -08001271 if (i >= ARRAY_SIZE(baud_table)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 m68328_console_baud = 9600;
1273 goto again;
1274 }
1275
1276 UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
1277 PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
1278 ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
1279 ustcnt |= USTCNT_8_7;
1280 ustcnt |= USTCNT_TXEN;
1281 USTCNT = ustcnt;
1282 m68328_console_initted = 1;
1283 return;
1284}
1285
1286
1287int m68328_console_setup(struct console *cp, char *arg)
1288{
1289 int i, n = CONSOLE_BAUD_RATE;
1290
1291 if (!cp)
1292 return(-1);
1293
1294 if (arg)
1295 n = simple_strtoul(arg,NULL,0);
1296
Thiago Farina8b505ca2009-12-09 12:31:30 -08001297 for (i = 0; i < ARRAY_SIZE(baud_table); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (baud_table[i] == n)
1299 break;
Greg Ungerere9a137c2010-05-24 14:32:55 -07001300 if (i < ARRAY_SIZE(baud_table)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 m68328_console_baud = n;
1302 m68328_console_cbaud = 0;
1303 if (i > 15) {
1304 m68328_console_cbaud |= CBAUDEX;
1305 i -= 15;
1306 }
1307 m68328_console_cbaud |= i;
1308 }
1309
1310 m68328_set_baud(); /* make sure baud rate changes */
1311 return(0);
1312}
1313
1314
1315static struct tty_driver *m68328_console_device(struct console *c, int *index)
1316{
1317 *index = c->index;
1318 return serial_driver;
1319}
1320
1321
1322void m68328_console_write (struct console *co, const char *str,
1323 unsigned int count)
1324{
1325 if (!m68328_console_initted)
1326 m68328_set_baud();
1327 while (count--) {
1328 if (*str == '\n')
1329 rs_put_char('\r');
1330 rs_put_char( *str++ );
1331 }
1332}
1333
1334
1335static struct console m68328_driver = {
1336 .name = "ttyS",
1337 .write = m68328_console_write,
1338 .device = m68328_console_device,
1339 .setup = m68328_console_setup,
1340 .flags = CON_PRINTBUFFER,
1341 .index = -1,
1342};
1343
1344
1345static int __init m68328_console_init(void)
1346{
1347 register_console(&m68328_driver);
1348 return 0;
1349}
1350
1351console_initcall(m68328_console_init);