blob: af4de1fe84454eca88f3921cfe786282e14fdf37 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/char/riscom.c -- RISCom/8 multiport serial driver.
3 *
4 * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com)
5 *
6 * This code is loosely based on the Linux serial driver, written by
Alan Cox9492e132008-04-30 00:54:15 -07007 * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
8 * programming info was obtained from various drivers for other OSes
9 * (FreeBSD, ISC, etc), but no source code from those drivers were
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * directly included in this driver.
11 *
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 * Revision 1.1
28 *
29 * ChangeLog:
30 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 27-Jun-2001
31 * - get rid of check_region and several cleanups
32 */
33
34#include <linux/module.h>
35
Alan Cox9492e132008-04-30 00:54:15 -070036#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/kernel.h>
38#include <linux/sched.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
41#include <linux/errno.h>
42#include <linux/tty.h>
43#include <linux/mm.h>
44#include <linux/serial.h>
45#include <linux/fcntl.h>
46#include <linux/major.h>
47#include <linux/init.h>
48#include <linux/delay.h>
Alan Cox33f0f882006-01-09 20:54:13 -080049#include <linux/tty_flip.h>
Jeff Garzikd9afa432008-02-06 01:36:11 -080050#include <linux/spinlock.h>
Scott James Remnant5c9f5802009-04-06 17:33:26 +010051#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Alan Cox9492e132008-04-30 00:54:15 -070053#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55#include "riscom8.h"
56#include "riscom8_reg.h"
57
58/* Am I paranoid or not ? ;-) */
59#define RISCOM_PARANOIA_CHECK
60
Alan Cox9492e132008-04-30 00:54:15 -070061/*
62 * Crazy InteliCom/8 boards sometimes have swapped CTS & DSR signals.
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 * You can slightly speed up things by #undefing the following option,
Alan Cox9492e132008-04-30 00:54:15 -070064 * if you are REALLY sure that your board is correct one.
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 */
66
67#define RISCOM_BRAIN_DAMAGED_CTS
68
Alan Cox9492e132008-04-30 00:54:15 -070069/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 * The following defines are mostly for testing purposes. But if you need
71 * some nice reporting in your syslog, you can define them also.
72 */
73#undef RC_REPORT_FIFO
74#undef RC_REPORT_OVERRUN
75
76
77#define RISCOM_LEGAL_FLAGS \
78 (ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \
79 ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \
80 ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct tty_driver *riscom_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Jeff Garzikd9afa432008-02-06 01:36:11 -080084static DEFINE_SPINLOCK(riscom_lock);
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086static struct riscom_board rc_board[RC_NBOARD] = {
87 {
88 .base = RC_IOBASE1,
89 },
90 {
91 .base = RC_IOBASE2,
92 },
93 {
94 .base = RC_IOBASE3,
95 },
96 {
97 .base = RC_IOBASE4,
98 },
99};
100
101static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
102
103/* RISCom/8 I/O ports addresses (without address translation) */
104static unsigned short rc_ioport[] = {
Tobias Klauserfe971072006-01-09 20:54:02 -0800105#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c,
Tobias Klauserfe971072006-01-09 20:54:02 -0800107#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, 0x10,
109 0x11, 0x12, 0x18, 0x28, 0x31, 0x32, 0x39, 0x3a, 0x40, 0x41, 0x61, 0x62,
110 0x63, 0x64, 0x6b, 0x70, 0x71, 0x78, 0x7a, 0x7b, 0x7f, 0x100, 0x101
Tobias Klauserfe971072006-01-09 20:54:02 -0800111#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
Tobias Klauserfe971072006-01-09 20:54:02 -0800113#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115
Alan Cox9492e132008-04-30 00:54:15 -0700116static int rc_paranoia_check(struct riscom_port const *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 char *name, const char *routine)
118{
119#ifdef RISCOM_PARANOIA_CHECK
120 static const char badmagic[] = KERN_INFO
121 "rc: Warning: bad riscom port magic number for device %s in %s\n";
122 static const char badinfo[] = KERN_INFO
123 "rc: Warning: null riscom port for device %s in %s\n";
124
125 if (!port) {
126 printk(badinfo, name, routine);
127 return 1;
128 }
129 if (port->magic != RISCOM8_MAGIC) {
130 printk(badmagic, name, routine);
131 return 1;
132 }
133#endif
134 return 0;
135}
136
137/*
Alan Cox9492e132008-04-30 00:54:15 -0700138 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 * Service functions for RISCom/8 driver.
Alan Cox9492e132008-04-30 00:54:15 -0700140 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 */
142
143/* Get board number from pointer */
Alan Cox9492e132008-04-30 00:54:15 -0700144static inline int board_No(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 return bp - rc_board;
147}
148
149/* Get port number from pointer */
Alan Cox9492e132008-04-30 00:54:15 -0700150static inline int port_No(struct riscom_port const *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Alan Cox9492e132008-04-30 00:54:15 -0700152 return RC_PORT(port - rc_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153}
154
155/* Get pointer to board from pointer to port */
Alan Cox9492e132008-04-30 00:54:15 -0700156static inline struct riscom_board *port_Board(struct riscom_port const *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
158 return &rc_board[RC_BOARD(port - rc_port)];
159}
160
161/* Input Byte from CL CD180 register */
Alan Cox9492e132008-04-30 00:54:15 -0700162static inline unsigned char rc_in(struct riscom_board const *bp,
163 unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164{
165 return inb(bp->base + RC_TO_ISA(reg));
166}
167
168/* Output Byte to CL CD180 register */
Alan Cox9492e132008-04-30 00:54:15 -0700169static inline void rc_out(struct riscom_board const *bp, unsigned short reg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 unsigned char val)
171{
172 outb(val, bp->base + RC_TO_ISA(reg));
173}
174
175/* Wait for Channel Command Register ready */
Alan Cox9492e132008-04-30 00:54:15 -0700176static void rc_wait_CCR(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 unsigned long delay;
179
180 /* FIXME: need something more descriptive then 100000 :) */
Alan Cox9492e132008-04-30 00:54:15 -0700181 for (delay = 100000; delay; delay--)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 if (!rc_in(bp, CD180_CCR))
183 return;
Alan Cox9492e132008-04-30 00:54:15 -0700184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
186}
187
188/*
189 * RISCom/8 probe functions.
190 */
191
Alan Cox9492e132008-04-30 00:54:15 -0700192static int rc_request_io_range(struct riscom_board * const bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193{
194 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700195
196 for (i = 0; i < RC_NIOPORT; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
198 "RISCom/8")) {
199 goto out_release;
200 }
201 return 0;
202out_release:
203 printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
204 board_No(bp), bp->base);
Alan Cox9492e132008-04-30 00:54:15 -0700205 while (--i >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
207 return 1;
208}
209
Alan Cox9492e132008-04-30 00:54:15 -0700210static void rc_release_io_range(struct riscom_board * const bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
212 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700213
214 for (i = 0; i < RC_NIOPORT; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
216}
Alan Cox9492e132008-04-30 00:54:15 -0700217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218/* Reset and setup CD180 chip */
Alan Cox9492e132008-04-30 00:54:15 -0700219static void __init rc_init_CD180(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
221 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700222
Jeff Garzikd9afa432008-02-06 01:36:11 -0800223 spin_lock_irqsave(&riscom_lock, flags);
224
Alan Cox9492e132008-04-30 00:54:15 -0700225 rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
226 rc_wait_CCR(bp); /* Wait for CCR ready */
227 rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800228 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -0700229 msleep(50); /* Delay 0.05 sec */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800230 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -0700231 rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
232 rc_out(bp, CD180_GICR, 0); /* Clear all bits */
233 rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
234 rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for tx intr */
235 rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for rx intr */
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 /* Setting up prescaler. We need 4 ticks per 1 ms */
238 rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
239 rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
Alan Cox9492e132008-04-30 00:54:15 -0700240
Jeff Garzikd9afa432008-02-06 01:36:11 -0800241 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244/* Main probing routine, also sets irq. */
245static int __init rc_probe(struct riscom_board *bp)
246{
247 unsigned char val1, val2;
248 int irqs = 0;
249 int retries;
Alan Cox9492e132008-04-30 00:54:15 -0700250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 bp->irq = 0;
252
253 if (rc_request_io_range(bp))
254 return 1;
Alan Cox9492e132008-04-30 00:54:15 -0700255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /* Are the I/O ports here ? */
257 rc_out(bp, CD180_PPRL, 0x5a);
258 outb(0xff, 0x80);
259 val1 = rc_in(bp, CD180_PPRL);
260 rc_out(bp, CD180_PPRL, 0xa5);
261 outb(0x00, 0x80);
262 val2 = rc_in(bp, CD180_PPRL);
Alan Cox9492e132008-04-30 00:54:15 -0700263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 if ((val1 != 0x5a) || (val2 != 0xa5)) {
265 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
266 board_No(bp), bp->base);
267 goto out_release;
268 }
Alan Cox9492e132008-04-30 00:54:15 -0700269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 /* It's time to find IRQ for this board */
Alan Cox9492e132008-04-30 00:54:15 -0700271 for (retries = 0; retries < 5 && irqs <= 0; retries++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 irqs = probe_irq_on();
Alan Cox9492e132008-04-30 00:54:15 -0700273 rc_init_CD180(bp); /* Reset CD180 chip */
274 rc_out(bp, CD180_CAR, 2); /* Select port 2 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 rc_wait_CCR(bp);
Alan Cox9492e132008-04-30 00:54:15 -0700276 rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
277 rc_out(bp, CD180_IER, IER_TXRDY);/* Enable tx empty intr */
Jiri Slabyc4ebd922007-07-17 04:05:20 -0700278 msleep(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 irqs = probe_irq_off(irqs);
Alan Cox9492e132008-04-30 00:54:15 -0700280 val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
281 val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
282 rc_init_CD180(bp); /* Reset CD180 again */
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
285 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
286 "found.\n", board_No(bp), bp->base);
287 goto out_release;
288 }
289 }
Alan Cox9492e132008-04-30 00:54:15 -0700290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 if (irqs <= 0) {
292 printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
293 "at 0x%03x.\n", board_No(bp), bp->base);
294 goto out_release;
295 }
296 bp->irq = irqs;
297 bp->flags |= RC_BOARD_PRESENT;
Alan Cox9492e132008-04-30 00:54:15 -0700298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
300 "0x%03x, IRQ %d.\n",
301 board_No(bp),
302 (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
303 bp->base, bp->irq);
Alan Cox9492e132008-04-30 00:54:15 -0700304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return 0;
306out_release:
307 rc_release_io_range(bp);
308 return 1;
309}
310
Alan Cox9492e132008-04-30 00:54:15 -0700311/*
312 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 * Interrupt processing routines.
Alan Cox9492e132008-04-30 00:54:15 -0700314 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 */
316
Alan Cox9492e132008-04-30 00:54:15 -0700317static struct riscom_port *rc_get_port(struct riscom_board const *bp,
318 unsigned char const *what)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 unsigned char channel;
Alan Cox9492e132008-04-30 00:54:15 -0700321 struct riscom_port *port;
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
324 if (channel < CD180_NCH) {
325 port = &rc_port[board_No(bp) * RC_NPORT + channel];
Alan Cox85f8f812008-07-16 21:55:29 +0100326 if (port->port.flags & ASYNC_INITIALIZED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 return port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
Alan Cox9492e132008-04-30 00:54:15 -0700329 printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 board_No(bp), what, channel);
331 return NULL;
332}
333
Alan Cox9492e132008-04-30 00:54:15 -0700334static void rc_receive_exc(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 struct riscom_port *port;
337 struct tty_struct *tty;
338 unsigned char status;
Alan Cox33f0f882006-01-09 20:54:13 -0800339 unsigned char ch, flag;
Alan Cox9492e132008-04-30 00:54:15 -0700340
341 port = rc_get_port(bp, "Receive");
342 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return;
344
Alan Cox6ff1ab22009-09-19 13:13:22 -0700345 tty = tty_port_tty_get(&port->port);
Alan Cox9492e132008-04-30 00:54:15 -0700346
347#ifdef RC_REPORT_OVERRUN
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 status = rc_in(bp, CD180_RCSR);
Alan Cox33f0f882006-01-09 20:54:13 -0800349 if (status & RCSR_OE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 port->overrun++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 status &= port->mark_mask;
Alan Cox9492e132008-04-30 00:54:15 -0700352#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 status = rc_in(bp, CD180_RCSR) & port->mark_mask;
Alan Cox9492e132008-04-30 00:54:15 -0700354#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 ch = rc_in(bp, CD180_RDR);
Alan Cox9492e132008-04-30 00:54:15 -0700356 if (!status)
Alan Cox6ff1ab22009-09-19 13:13:22 -0700357 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (status & RCSR_TOUT) {
359 printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
Alan Cox9492e132008-04-30 00:54:15 -0700360 "Hardware problems ?\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 board_No(bp), port_No(port));
Alan Cox6ff1ab22009-09-19 13:13:22 -0700362 goto out;
Alan Cox9492e132008-04-30 00:54:15 -0700363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 } else if (status & RCSR_BREAK) {
365 printk(KERN_INFO "rc%d: port %d: Handling break...\n",
366 board_No(bp), port_No(port));
Alan Cox33f0f882006-01-09 20:54:13 -0800367 flag = TTY_BREAK;
Alan Cox6ff1ab22009-09-19 13:13:22 -0700368 if (tty && (port->port.flags & ASYNC_SAK))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 do_SAK(tty);
Alan Cox9492e132008-04-30 00:54:15 -0700370
371 } else if (status & RCSR_PE)
Alan Cox33f0f882006-01-09 20:54:13 -0800372 flag = TTY_PARITY;
Alan Cox9492e132008-04-30 00:54:15 -0700373
374 else if (status & RCSR_FE)
Alan Cox33f0f882006-01-09 20:54:13 -0800375 flag = TTY_FRAME;
Alan Cox9492e132008-04-30 00:54:15 -0700376
377 else if (status & RCSR_OE)
Alan Cox33f0f882006-01-09 20:54:13 -0800378 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 else
Alan Cox33f0f882006-01-09 20:54:13 -0800380 flag = TTY_NORMAL;
Alan Cox9492e132008-04-30 00:54:15 -0700381
Alan Cox6ff1ab22009-09-19 13:13:22 -0700382 if (tty) {
383 tty_insert_flip_char(tty, ch, flag);
384 tty_flip_buffer_push(tty);
385 }
386out:
387 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
Alan Cox9492e132008-04-30 00:54:15 -0700390static void rc_receive(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
392 struct riscom_port *port;
393 struct tty_struct *tty;
394 unsigned char count;
Alan Cox9492e132008-04-30 00:54:15 -0700395
396 port = rc_get_port(bp, "Receive");
397 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return;
Alan Cox9492e132008-04-30 00:54:15 -0700399
Alan Cox6ff1ab22009-09-19 13:13:22 -0700400 tty = tty_port_tty_get(&port->port);
Alan Cox9492e132008-04-30 00:54:15 -0700401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 count = rc_in(bp, CD180_RDCR);
Alan Cox9492e132008-04-30 00:54:15 -0700403
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404#ifdef RC_REPORT_FIFO
405 port->hits[count > 8 ? 9 : count]++;
Alan Cox9492e132008-04-30 00:54:15 -0700406#endif
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 while (count--) {
Alan Cox6ff1ab22009-09-19 13:13:22 -0700409 u8 ch = rc_in(bp, CD180_RDR);
410 if (tty)
411 tty_insert_flip_char(tty, ch, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 }
Alan Cox6ff1ab22009-09-19 13:13:22 -0700413 if (tty) {
414 tty_flip_buffer_push(tty);
415 tty_kref_put(tty);
416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
Alan Cox9492e132008-04-30 00:54:15 -0700419static void rc_transmit(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
421 struct riscom_port *port;
422 struct tty_struct *tty;
423 unsigned char count;
Alan Cox9492e132008-04-30 00:54:15 -0700424
425 port = rc_get_port(bp, "Transmit");
426 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 return;
Alan Cox9492e132008-04-30 00:54:15 -0700428
Alan Cox6ff1ab22009-09-19 13:13:22 -0700429 tty = tty_port_tty_get(&port->port);
Alan Cox9492e132008-04-30 00:54:15 -0700430
431 if (port->IER & IER_TXEMPTY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 /* FIFO drained */
433 rc_out(bp, CD180_CAR, port_No(port));
434 port->IER &= ~IER_TXEMPTY;
435 rc_out(bp, CD180_IER, port->IER);
Alan Cox6ff1ab22009-09-19 13:13:22 -0700436 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
Alan Cox9492e132008-04-30 00:54:15 -0700438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if ((port->xmit_cnt <= 0 && !port->break_length)
Alan Cox6ff1ab22009-09-19 13:13:22 -0700440 || (tty && (tty->stopped || tty->hw_stopped))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 rc_out(bp, CD180_CAR, port_No(port));
442 port->IER &= ~IER_TXRDY;
443 rc_out(bp, CD180_IER, port->IER);
Alan Cox6ff1ab22009-09-19 13:13:22 -0700444 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
Alan Cox9492e132008-04-30 00:54:15 -0700446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if (port->break_length) {
448 if (port->break_length > 0) {
449 if (port->COR2 & COR2_ETC) {
450 rc_out(bp, CD180_TDR, CD180_C_ESC);
451 rc_out(bp, CD180_TDR, CD180_C_SBRK);
452 port->COR2 &= ~COR2_ETC;
453 }
454 count = min_t(int, port->break_length, 0xff);
455 rc_out(bp, CD180_TDR, CD180_C_ESC);
456 rc_out(bp, CD180_TDR, CD180_C_DELAY);
457 rc_out(bp, CD180_TDR, count);
Alan Cox9492e132008-04-30 00:54:15 -0700458 port->break_length -= count;
459 if (port->break_length == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 port->break_length--;
461 } else {
462 rc_out(bp, CD180_TDR, CD180_C_ESC);
463 rc_out(bp, CD180_TDR, CD180_C_EBRK);
464 rc_out(bp, CD180_COR2, port->COR2);
465 rc_wait_CCR(bp);
466 rc_out(bp, CD180_CCR, CCR_CORCHG2);
467 port->break_length = 0;
468 }
Jiri Slaby7e63d0c2009-09-06 23:10:09 +0200469 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 }
Alan Cox9492e132008-04-30 00:54:15 -0700471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 count = CD180_NFIFO;
473 do {
Alan Cox85f8f812008-07-16 21:55:29 +0100474 rc_out(bp, CD180_TDR, port->port.xmit_buf[port->xmit_tail++]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
476 if (--port->xmit_cnt <= 0)
477 break;
478 } while (--count > 0);
Alan Cox9492e132008-04-30 00:54:15 -0700479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 if (port->xmit_cnt <= 0) {
481 rc_out(bp, CD180_CAR, port_No(port));
482 port->IER &= ~IER_TXRDY;
483 rc_out(bp, CD180_IER, port->IER);
484 }
Alan Cox6ff1ab22009-09-19 13:13:22 -0700485 if (tty && port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800486 tty_wakeup(tty);
Alan Cox6ff1ab22009-09-19 13:13:22 -0700487out:
488 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Alan Cox9492e132008-04-30 00:54:15 -0700491static void rc_check_modem(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
493 struct riscom_port *port;
494 struct tty_struct *tty;
495 unsigned char mcr;
Alan Cox9492e132008-04-30 00:54:15 -0700496
497 port = rc_get_port(bp, "Modem");
498 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return;
Alan Cox9492e132008-04-30 00:54:15 -0700500
Alan Cox6ff1ab22009-09-19 13:13:22 -0700501 tty = tty_port_tty_get(&port->port);
Alan Cox9492e132008-04-30 00:54:15 -0700502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 mcr = rc_in(bp, CD180_MCR);
Alan Cox9492e132008-04-30 00:54:15 -0700504 if (mcr & MCR_CDCHG) {
505 if (rc_in(bp, CD180_MSVR) & MSVR_CD)
Alan Cox85f8f812008-07-16 21:55:29 +0100506 wake_up_interruptible(&port->port.open_wait);
Alan Cox6ff1ab22009-09-19 13:13:22 -0700507 else if (tty)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800508 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 }
Alan Cox9492e132008-04-30 00:54:15 -0700510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511#ifdef RISCOM_BRAIN_DAMAGED_CTS
512 if (mcr & MCR_CTSCHG) {
513 if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 port->IER |= IER_TXRDY;
Alan Cox6ff1ab22009-09-19 13:13:22 -0700515 if (tty) {
516 tty->hw_stopped = 0;
517 if (port->xmit_cnt <= port->wakeup_chars)
518 tty_wakeup(tty);
519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 } else {
Alan Cox6ff1ab22009-09-19 13:13:22 -0700521 if (tty)
522 tty->hw_stopped = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 port->IER &= ~IER_TXRDY;
524 }
525 rc_out(bp, CD180_IER, port->IER);
526 }
527 if (mcr & MCR_DSRCHG) {
528 if (rc_in(bp, CD180_MSVR) & MSVR_DSR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 port->IER |= IER_TXRDY;
Alan Cox6ff1ab22009-09-19 13:13:22 -0700530 if (tty) {
531 tty->hw_stopped = 0;
532 if (port->xmit_cnt <= port->wakeup_chars)
533 tty_wakeup(tty);
534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 } else {
Alan Cox6ff1ab22009-09-19 13:13:22 -0700536 if (tty)
537 tty->hw_stopped = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 port->IER &= ~IER_TXRDY;
539 }
540 rc_out(bp, CD180_IER, port->IER);
541 }
542#endif /* RISCOM_BRAIN_DAMAGED_CTS */
Alan Cox9492e132008-04-30 00:54:15 -0700543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 /* Clear change bits */
545 rc_out(bp, CD180_MCR, 0);
Alan Cox6ff1ab22009-09-19 13:13:22 -0700546 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547}
548
549/* The main interrupt processing routine */
Alan Cox9492e132008-04-30 00:54:15 -0700550static irqreturn_t rc_interrupt(int dummy, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
552 unsigned char status;
553 unsigned char ack;
Jeff Garzikf07ef392007-10-23 19:12:11 -0400554 struct riscom_board *bp = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 unsigned long loop = 0;
556 int handled = 0;
557
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400558 if (!(bp->flags & RC_BOARD_ACTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return IRQ_NONE;
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
562 (RC_BSR_TOUT | RC_BSR_TINT |
563 RC_BSR_MINT | RC_BSR_RINT))) {
564 handled = 1;
Alan Cox9492e132008-04-30 00:54:15 -0700565 if (status & RC_BSR_TOUT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 printk(KERN_WARNING "rc%d: Got timeout. Hardware "
567 "error?\n", board_No(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 else if (status & RC_BSR_RINT) {
569 ack = rc_in(bp, RC_ACK_RINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (ack == (RC_ID | GIVR_IT_RCV))
571 rc_receive(bp);
572 else if (ack == (RC_ID | GIVR_IT_REXC))
573 rc_receive_exc(bp);
574 else
575 printk(KERN_WARNING "rc%d: Bad receive ack "
576 "0x%02x.\n",
577 board_No(bp), ack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 } else if (status & RC_BSR_TINT) {
579 ack = rc_in(bp, RC_ACK_TINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 if (ack == (RC_ID | GIVR_IT_TX))
581 rc_transmit(bp);
582 else
583 printk(KERN_WARNING "rc%d: Bad transmit ack "
584 "0x%02x.\n",
585 board_No(bp), ack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 } else /* if (status & RC_BSR_MINT) */ {
587 ack = rc_in(bp, RC_ACK_MINT);
Alan Cox9492e132008-04-30 00:54:15 -0700588 if (ack == (RC_ID | GIVR_IT_MODEM))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 rc_check_modem(bp);
590 else
591 printk(KERN_WARNING "rc%d: Bad modem ack "
592 "0x%02x.\n",
593 board_No(bp), ack);
Alan Cox9492e132008-04-30 00:54:15 -0700594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
596 rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
597 }
598 return IRQ_RETVAL(handled);
599}
600
601/*
602 * Routines for open & close processing.
603 */
604
605/* Called with disabled interrupts */
Alan Cox9492e132008-04-30 00:54:15 -0700606static int rc_setup_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 int error;
609
Alan Cox9492e132008-04-30 00:54:15 -0700610 if (bp->flags & RC_BOARD_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700612
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700613 error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
Jeff Garzikf07ef392007-10-23 19:12:11 -0400614 "RISCom/8", bp);
Alan Cox9492e132008-04-30 00:54:15 -0700615 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 return error;
Alan Cox9492e132008-04-30 00:54:15 -0700617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 rc_out(bp, RC_CTOUT, 0); /* Just in case */
619 bp->DTR = ~0;
620 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
Alan Cox9492e132008-04-30 00:54:15 -0700621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 bp->flags |= RC_BOARD_ACTIVE;
Alan Cox9492e132008-04-30 00:54:15 -0700623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return 0;
625}
626
627/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400628static void rc_shutdown_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 if (!(bp->flags & RC_BOARD_ACTIVE))
631 return;
Alan Cox9492e132008-04-30 00:54:15 -0700632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 bp->flags &= ~RC_BOARD_ACTIVE;
Alan Cox9492e132008-04-30 00:54:15 -0700634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 free_irq(bp->irq, NULL);
Alan Cox9492e132008-04-30 00:54:15 -0700636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 bp->DTR = ~0;
638 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
Alan Cox9492e132008-04-30 00:54:15 -0700639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642/*
Alan Cox9492e132008-04-30 00:54:15 -0700643 * Setting up port characteristics.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 * Must be called with disabled interrupts
645 */
Alan Cox6ff1ab22009-09-19 13:13:22 -0700646static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp,
647 struct riscom_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 unsigned long baud;
650 long tmp;
651 unsigned char cor1 = 0, cor3 = 0;
652 unsigned char mcor1 = 0, mcor2 = 0;
Alan Cox9492e132008-04-30 00:54:15 -0700653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 port->IER = 0;
655 port->COR2 = 0;
656 port->MSVR = MSVR_RTS;
Alan Cox9492e132008-04-30 00:54:15 -0700657
Alan Coxc7bce302006-09-30 23:27:24 -0700658 baud = tty_get_baud_rate(tty);
Alan Cox9492e132008-04-30 00:54:15 -0700659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 /* Select port on the board */
661 rc_out(bp, CD180_CAR, port_No(port));
Alan Cox9492e132008-04-30 00:54:15 -0700662
Alan Coxc7bce302006-09-30 23:27:24 -0700663 if (!baud) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 /* Drop DTR & exit */
665 bp->DTR |= (1u << port_No(port));
666 rc_out(bp, RC_DTR, bp->DTR);
667 return;
668 } else {
669 /* Set DTR on */
670 bp->DTR &= ~(1u << port_No(port));
671 rc_out(bp, RC_DTR, bp->DTR);
672 }
Alan Cox9492e132008-04-30 00:54:15 -0700673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 /*
Alan Cox9492e132008-04-30 00:54:15 -0700675 * Now we must calculate some speed depended things
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 */
Alan Cox9492e132008-04-30 00:54:15 -0700677
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 /* Set baud rate for port */
Alan Coxc7bce302006-09-30 23:27:24 -0700679 tmp = (((RC_OSCFREQ + baud/2) / baud +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 CD180_TPC/2) / CD180_TPC);
681
Alan Cox9492e132008-04-30 00:54:15 -0700682 rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
683 rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
684 rc_out(bp, CD180_RBPRL, tmp & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 rc_out(bp, CD180_TBPRL, tmp & 0xff);
Alan Cox9492e132008-04-30 00:54:15 -0700686
Alan Coxc7bce302006-09-30 23:27:24 -0700687 baud = (baud + 5) / 10; /* Estimated CPS */
Alan Cox9492e132008-04-30 00:54:15 -0700688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 /* Two timer ticks seems enough to wakeup something like SLIP driver */
Alan Cox9492e132008-04-30 00:54:15 -0700690 tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
692 SERIAL_XMIT_SIZE - 1 : tmp);
Alan Cox9492e132008-04-30 00:54:15 -0700693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /* Receiver timeout will be transmission time for 1.5 chars */
695 tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
696 tmp = (tmp > 0xff) ? 0xff : tmp;
697 rc_out(bp, CD180_RTPR, tmp);
Alan Cox9492e132008-04-30 00:54:15 -0700698
699 switch (C_CSIZE(tty)) {
700 case CS5:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 cor1 |= COR1_5BITS;
702 break;
Alan Cox9492e132008-04-30 00:54:15 -0700703 case CS6:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 cor1 |= COR1_6BITS;
705 break;
Alan Cox9492e132008-04-30 00:54:15 -0700706 case CS7:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 cor1 |= COR1_7BITS;
708 break;
Alan Cox9492e132008-04-30 00:54:15 -0700709 case CS8:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 cor1 |= COR1_8BITS;
711 break;
712 }
Alan Cox9492e132008-04-30 00:54:15 -0700713 if (C_CSTOPB(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 cor1 |= COR1_2SB;
Alan Cox9492e132008-04-30 00:54:15 -0700715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 cor1 |= COR1_IGNORE;
Alan Cox9492e132008-04-30 00:54:15 -0700717 if (C_PARENB(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 cor1 |= COR1_NORMPAR;
Alan Cox9492e132008-04-30 00:54:15 -0700719 if (C_PARODD(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 cor1 |= COR1_ODDP;
Alan Cox9492e132008-04-30 00:54:15 -0700721 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 cor1 &= ~COR1_IGNORE;
723 }
724 /* Set marking of some errors */
725 port->mark_mask = RCSR_OE | RCSR_TOUT;
Alan Cox9492e132008-04-30 00:54:15 -0700726 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 port->mark_mask |= RCSR_FE | RCSR_PE;
Alan Cox9492e132008-04-30 00:54:15 -0700728 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 port->mark_mask |= RCSR_BREAK;
Alan Cox9492e132008-04-30 00:54:15 -0700730 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
Alan Cox9492e132008-04-30 00:54:15 -0700732 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 port->mark_mask &= ~RCSR_BREAK;
Alan Cox9492e132008-04-30 00:54:15 -0700734 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* Real raw mode. Ignore all */
736 port->mark_mask &= ~RCSR_OE;
737 }
738 /* Enable Hardware Flow Control */
739 if (C_CRTSCTS(tty)) {
740#ifdef RISCOM_BRAIN_DAMAGED_CTS
741 port->IER |= IER_DSR | IER_CTS;
742 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
743 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
Alan Cox9492e132008-04-30 00:54:15 -0700744 tty->hw_stopped = !(rc_in(bp, CD180_MSVR) &
745 (MSVR_CTS|MSVR_DSR));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746#else
747 port->COR2 |= COR2_CTSAE;
748#endif
749 }
750 /* Enable Software Flow Control. FIXME: I'm not sure about this */
751 /* Some people reported that it works, but I still doubt */
752 if (I_IXON(tty)) {
753 port->COR2 |= COR2_TXIBE;
754 cor3 |= (COR3_FCT | COR3_SCDE);
755 if (I_IXANY(tty))
756 port->COR2 |= COR2_IXM;
757 rc_out(bp, CD180_SCHR1, START_CHAR(tty));
758 rc_out(bp, CD180_SCHR2, STOP_CHAR(tty));
759 rc_out(bp, CD180_SCHR3, START_CHAR(tty));
760 rc_out(bp, CD180_SCHR4, STOP_CHAR(tty));
761 }
762 if (!C_CLOCAL(tty)) {
763 /* Enable CD check */
764 port->IER |= IER_CD;
765 mcor1 |= MCOR1_CDZD;
766 mcor2 |= MCOR2_CDOD;
767 }
Alan Cox9492e132008-04-30 00:54:15 -0700768
769 if (C_CREAD(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 /* Enable receiver */
771 port->IER |= IER_RXD;
Alan Cox9492e132008-04-30 00:54:15 -0700772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 /* Set input FIFO size (1-8 bytes) */
Alan Cox9492e132008-04-30 00:54:15 -0700774 cor3 |= RISCOM_RXFIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 /* Setting up CD180 channel registers */
776 rc_out(bp, CD180_COR1, cor1);
777 rc_out(bp, CD180_COR2, port->COR2);
778 rc_out(bp, CD180_COR3, cor3);
779 /* Make CD180 know about registers change */
780 rc_wait_CCR(bp);
781 rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
782 /* Setting up modem option registers */
783 rc_out(bp, CD180_MCOR1, mcor1);
784 rc_out(bp, CD180_MCOR2, mcor2);
785 /* Enable CD180 transmitter & receiver */
786 rc_wait_CCR(bp);
787 rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
788 /* Enable interrupts */
789 rc_out(bp, CD180_IER, port->IER);
790 /* And finally set RTS on */
791 rc_out(bp, CD180_MSVR, port->MSVR);
792}
793
794/* Must be called with interrupts enabled */
Alan Cox8f1e6722009-11-30 13:16:47 +0000795static int rc_activate_port(struct tty_port *port, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
Alan Cox8f1e6722009-11-30 13:16:47 +0000797 struct riscom_port *rp = container_of(port, struct riscom_port, port);
798 struct riscom_board *bp = port_Board(rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700800
Alan Cox8f1e6722009-11-30 13:16:47 +0000801 if (tty_port_alloc_xmit_buf(port) < 0)
Alan Cox85f8f812008-07-16 21:55:29 +0100802 return -ENOMEM;
803
Jeff Garzikd9afa432008-02-06 01:36:11 -0800804 spin_lock_irqsave(&riscom_lock, flags);
805
Alan Cox6ff1ab22009-09-19 13:13:22 -0700806 clear_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox8f1e6722009-11-30 13:16:47 +0000807 bp->count++;
808 rp->xmit_cnt = rp->xmit_head = rp->xmit_tail = 0;
809 rc_change_speed(tty, bp, rp);
Jeff Garzikd9afa432008-02-06 01:36:11 -0800810 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return 0;
812}
813
814/* Must be called with interrupts disabled */
Alan Coxd99101f2008-07-16 21:55:37 +0100815static void rc_shutdown_port(struct tty_struct *tty,
816 struct riscom_board *bp, struct riscom_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818#ifdef RC_REPORT_OVERRUN
819 printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
820 board_No(bp), port_No(port), port->overrun);
Alan Cox9492e132008-04-30 00:54:15 -0700821#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822#ifdef RC_REPORT_FIFO
823 {
824 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
827 board_No(bp), port_No(port));
Alan Cox9492e132008-04-30 00:54:15 -0700828 for (i = 0; i < 10; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 printk("%ld ", port->hits[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 printk("].\n");
831 }
Alan Cox9492e132008-04-30 00:54:15 -0700832#endif
Alan Cox85f8f812008-07-16 21:55:29 +0100833 tty_port_free_xmit_buf(&port->port);
Alan Cox9492e132008-04-30 00:54:15 -0700834
835 /* Select port */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 rc_out(bp, CD180_CAR, port_No(port));
837 /* Reset port */
838 rc_wait_CCR(bp);
839 rc_out(bp, CD180_CCR, CCR_SOFTRESET);
840 /* Disable all interrupts from this port */
841 port->IER = 0;
842 rc_out(bp, CD180_IER, port->IER);
Alan Cox9492e132008-04-30 00:54:15 -0700843
Alan Coxd99101f2008-07-16 21:55:37 +0100844 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox9492e132008-04-30 00:54:15 -0700845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (--bp->count < 0) {
847 printk(KERN_INFO "rc%d: rc_shutdown_port: "
848 "bad board count: %d\n",
849 board_No(bp), bp->count);
850 bp->count = 0;
851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 /*
853 * If this is the last opened port on the board
854 * shutdown whole board
855 */
Alan Cox9492e132008-04-30 00:54:15 -0700856 if (!bp->count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 rc_shutdown_board(bp);
858}
859
Alan Cox31f35932009-01-02 13:45:05 +0000860static int carrier_raised(struct tty_port *port)
861{
862 struct riscom_port *p = container_of(port, struct riscom_port, port);
863 struct riscom_board *bp = port_Board(p);
864 unsigned long flags;
865 int CD;
866
867 spin_lock_irqsave(&riscom_lock, flags);
868 rc_out(bp, CD180_CAR, port_No(p));
869 CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
870 rc_out(bp, CD180_MSVR, MSVR_RTS);
871 bp->DTR &= ~(1u << port_No(p));
872 rc_out(bp, RC_DTR, bp->DTR);
873 spin_unlock_irqrestore(&riscom_lock, flags);
874 return CD;
875}
876
Alan Cox8f1e6722009-11-30 13:16:47 +0000877static void dtr_rts(struct tty_port *port, int onoff)
878{
879 struct riscom_port *p = container_of(port, struct riscom_port, port);
880 struct riscom_board *bp = port_Board(p);
881 unsigned long flags;
882
883 spin_lock_irqsave(&riscom_lock, flags);
884 bp->DTR &= ~(1u << port_No(p));
885 if (onoff == 0)
886 bp->DTR |= (1u << port_No(p));
887 rc_out(bp, RC_DTR, bp->DTR);
888 spin_unlock_irqrestore(&riscom_lock, flags);
889}
890
Alan Cox9492e132008-04-30 00:54:15 -0700891static int rc_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
893 int board;
894 int error;
Alan Cox9492e132008-04-30 00:54:15 -0700895 struct riscom_port *port;
896 struct riscom_board *bp;
897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 board = RC_BOARD(tty->index);
899 if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
900 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -0700901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 bp = &rc_board[board];
903 port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
904 if (rc_paranoia_check(port, tty->name, "rc_open"))
905 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -0700906
907 error = rc_setup_board(bp);
908 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return error;
Alan Cox9492e132008-04-30 00:54:15 -0700910
Alan Coxa2d1e352010-04-23 16:01:18 +0100911 tty->driver_data = port;
Alan Cox8f1e6722009-11-30 13:16:47 +0000912 return tty_port_open(&port->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
Alan Cox978e5952008-04-30 00:53:59 -0700915static void rc_flush_buffer(struct tty_struct *tty)
916{
Alan Coxc9f19e92009-01-02 13:47:26 +0000917 struct riscom_port *port = tty->driver_data;
Alan Cox978e5952008-04-30 00:53:59 -0700918 unsigned long flags;
919
920 if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
921 return;
922
923 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox978e5952008-04-30 00:53:59 -0700924 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
Alan Cox978e5952008-04-30 00:53:59 -0700925 spin_unlock_irqrestore(&riscom_lock, flags);
926
927 tty_wakeup(tty);
928}
929
Jiri Slaby90387f52009-08-22 09:04:42 +0200930static void rc_close_port(struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 unsigned long flags;
Alan Coxc1469422009-09-19 13:13:21 -0700933 struct riscom_port *rp = container_of(port, struct riscom_port, port);
934 struct riscom_board *bp = port_Board(rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 unsigned long timeout;
Alan Coxa6614992009-01-02 13:46:50 +0000936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 /*
938 * At this point we stop accepting input. To do this, we
939 * disable the receive line status interrupts, and tell the
940 * interrupt driver to stop checking the data ready bit in the
941 * line status register.
942 */
Alan Coxc2ba38c2009-01-02 13:45:50 +0000943
944 spin_lock_irqsave(&riscom_lock, flags);
Alan Coxc1469422009-09-19 13:13:21 -0700945 rp->IER &= ~IER_RXD;
Alan Cox8f1e6722009-11-30 13:16:47 +0000946
947 rp->IER &= ~IER_TXRDY;
948 rp->IER |= IER_TXEMPTY;
949 rc_out(bp, CD180_CAR, port_No(rp));
950 rc_out(bp, CD180_IER, rp->IER);
951 /*
952 * Before we drop DTR, make sure the UART transmitter
953 * has completely drained; this is especially
954 * important if there is a transmit FIFO!
955 */
956 timeout = jiffies + HZ;
957 while (rp->IER & IER_TXEMPTY) {
958 spin_unlock_irqrestore(&riscom_lock, flags);
959 msleep_interruptible(jiffies_to_msecs(rp->timeout));
960 spin_lock_irqsave(&riscom_lock, flags);
961 if (time_after(jiffies, timeout))
962 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 }
Jiri Slaby90387f52009-08-22 09:04:42 +0200964 rc_shutdown_port(port->tty, bp, rp);
Alan Coxc2ba38c2009-01-02 13:45:50 +0000965 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxc1469422009-09-19 13:13:21 -0700966}
967
968static void rc_close(struct tty_struct *tty, struct file *filp)
969{
970 struct riscom_port *port = tty->driver_data;
971
972 if (!port || rc_paranoia_check(port, tty->name, "close"))
973 return;
Alan Cox6ff1ab22009-09-19 13:13:22 -0700974 tty_port_close(&port->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975}
976
Alan Cox9492e132008-04-30 00:54:15 -0700977static int rc_write(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 const unsigned char *buf, int count)
979{
Alan Coxc9f19e92009-01-02 13:47:26 +0000980 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 struct riscom_board *bp;
982 int c, total = 0;
983 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (rc_paranoia_check(port, tty->name, "rc_write"))
986 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 bp = port_Board(port);
989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -0800991 spin_lock_irqsave(&riscom_lock, flags);
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
994 SERIAL_XMIT_SIZE - port->xmit_head));
Jeff Garzikd9afa432008-02-06 01:36:11 -0800995 if (c <= 0)
996 break; /* lock continues to be held */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Alan Cox85f8f812008-07-16 21:55:29 +0100998 memcpy(port->port.xmit_buf + port->xmit_head, buf, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
1000 port->xmit_cnt += c;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001001
1002 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 buf += c;
1005 count -= c;
1006 total += c;
1007 }
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1010 !(port->IER & IER_TXRDY)) {
1011 port->IER |= IER_TXRDY;
1012 rc_out(bp, CD180_CAR, port_No(port));
1013 rc_out(bp, CD180_IER, port->IER);
1014 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001015
1016 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 return total;
1019}
1020
Alan Cox9492e132008-04-30 00:54:15 -07001021static int rc_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022{
Alan Coxc9f19e92009-01-02 13:47:26 +00001023 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 unsigned long flags;
Alan Coxbbbbb962008-04-30 00:54:05 -07001025 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 if (rc_paranoia_check(port, tty->name, "rc_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001028 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Jeff Garzikd9afa432008-02-06 01:36:11 -08001030 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -07001031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
1033 goto out;
1034
Alan Cox85f8f812008-07-16 21:55:29 +01001035 port->port.xmit_buf[port->xmit_head++] = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1037 port->xmit_cnt++;
Alan Coxbbbbb962008-04-30 00:54:05 -07001038 ret = 1;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001039
1040out:
1041 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxbbbbb962008-04-30 00:54:05 -07001042 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043}
1044
Alan Cox9492e132008-04-30 00:54:15 -07001045static void rc_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046{
Alan Coxc9f19e92009-01-02 13:47:26 +00001047 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
1051 return;
Alan Cox9492e132008-04-30 00:54:15 -07001052
Alan Coxd99101f2008-07-16 21:55:37 +01001053 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return;
1055
Jeff Garzikd9afa432008-02-06 01:36:11 -08001056 spin_lock_irqsave(&riscom_lock, flags);
1057
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 port->IER |= IER_TXRDY;
1059 rc_out(port_Board(port), CD180_CAR, port_No(port));
1060 rc_out(port_Board(port), CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001061
1062 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063}
1064
Alan Cox9492e132008-04-30 00:54:15 -07001065static int rc_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
Alan Coxc9f19e92009-01-02 13:47:26 +00001067 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 int ret;
Alan Cox9492e132008-04-30 00:54:15 -07001069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (rc_paranoia_check(port, tty->name, "rc_write_room"))
1071 return 0;
1072
1073 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1074 if (ret < 0)
1075 ret = 0;
1076 return ret;
1077}
1078
1079static int rc_chars_in_buffer(struct tty_struct *tty)
1080{
Alan Coxc9f19e92009-01-02 13:47:26 +00001081 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
1084 return 0;
Alan Cox9492e132008-04-30 00:54:15 -07001085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return port->xmit_cnt;
1087}
1088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089static int rc_tiocmget(struct tty_struct *tty, struct file *file)
1090{
Alan Coxc9f19e92009-01-02 13:47:26 +00001091 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001092 struct riscom_board *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 unsigned char status;
1094 unsigned int result;
1095 unsigned long flags;
1096
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001097 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return -ENODEV;
1099
1100 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001101
1102 spin_lock_irqsave(&riscom_lock, flags);
1103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 rc_out(bp, CD180_CAR, port_No(port));
1105 status = rc_in(bp, CD180_MSVR);
1106 result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001107
1108 spin_unlock_irqrestore(&riscom_lock, flags);
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
1111 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1112 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
1113 | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
1114 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1115 return result;
1116}
1117
1118static int rc_tiocmset(struct tty_struct *tty, struct file *file,
1119 unsigned int set, unsigned int clear)
1120{
Alan Coxc9f19e92009-01-02 13:47:26 +00001121 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 unsigned long flags;
1123 struct riscom_board *bp;
1124
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001125 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 return -ENODEV;
1127
1128 bp = port_Board(port);
1129
Jeff Garzikd9afa432008-02-06 01:36:11 -08001130 spin_lock_irqsave(&riscom_lock, flags);
1131
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 if (set & TIOCM_RTS)
1133 port->MSVR |= MSVR_RTS;
1134 if (set & TIOCM_DTR)
1135 bp->DTR &= ~(1u << port_No(port));
1136
1137 if (clear & TIOCM_RTS)
1138 port->MSVR &= ~MSVR_RTS;
1139 if (clear & TIOCM_DTR)
1140 bp->DTR |= (1u << port_No(port));
1141
1142 rc_out(bp, CD180_CAR, port_No(port));
1143 rc_out(bp, CD180_MSVR, port->MSVR);
1144 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001145
1146 spin_unlock_irqrestore(&riscom_lock, flags);
1147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return 0;
1149}
1150
Alan Cox781cff52008-07-22 11:18:30 +01001151static int rc_send_break(struct tty_struct *tty, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152{
Alan Coxc9f19e92009-01-02 13:47:26 +00001153 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 struct riscom_board *bp = port_Board(port);
1155 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001156
Alan Cox781cff52008-07-22 11:18:30 +01001157 if (length == 0 || length == -1)
1158 return -EOPNOTSUPP;
1159
Jeff Garzikd9afa432008-02-06 01:36:11 -08001160 spin_lock_irqsave(&riscom_lock, flags);
1161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 port->break_length = RISCOM_TPS / HZ * length;
1163 port->COR2 |= COR2_ETC;
1164 port->IER |= IER_TXRDY;
1165 rc_out(bp, CD180_CAR, port_No(port));
1166 rc_out(bp, CD180_COR2, port->COR2);
1167 rc_out(bp, CD180_IER, port->IER);
1168 rc_wait_CCR(bp);
1169 rc_out(bp, CD180_CCR, CCR_CORCHG2);
1170 rc_wait_CCR(bp);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001171
1172 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Cox781cff52008-07-22 11:18:30 +01001173 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174}
1175
Alan Cox6ff1ab22009-09-19 13:13:22 -07001176static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port,
Alan Cox9492e132008-04-30 00:54:15 -07001177 struct serial_struct __user *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178{
1179 struct serial_struct tmp;
1180 struct riscom_board *bp = port_Board(port);
1181 int change_speed;
Alan Cox9492e132008-04-30 00:54:15 -07001182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
1184 return -EFAULT;
Alan Cox9492e132008-04-30 00:54:15 -07001185
Alan Coxbf936f92010-06-01 22:52:43 +02001186 mutex_lock(&port->port.mutex);
Alan Cox85f8f812008-07-16 21:55:29 +01001187 change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 (tmp.flags & ASYNC_SPD_MASK));
Alan Cox9492e132008-04-30 00:54:15 -07001189
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01001191 if ((tmp.close_delay != port->port.close_delay) ||
1192 (tmp.closing_wait != port->port.closing_wait) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 ((tmp.flags & ~ASYNC_USR_MASK) !=
Alan Coxbf936f92010-06-01 22:52:43 +02001194 (port->port.flags & ~ASYNC_USR_MASK))) {
1195 mutex_unlock(&port->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 return -EPERM;
Alan Coxbf936f92010-06-01 22:52:43 +02001197 }
Alan Cox85f8f812008-07-16 21:55:29 +01001198 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 (tmp.flags & ASYNC_USR_MASK));
1200 } else {
Alan Cox85f8f812008-07-16 21:55:29 +01001201 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 (tmp.flags & ASYNC_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001203 port->port.close_delay = tmp.close_delay;
1204 port->port.closing_wait = tmp.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
1206 if (change_speed) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001207 unsigned long flags;
1208
1209 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox6ff1ab22009-09-19 13:13:22 -07001210 rc_change_speed(tty, bp, port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001211 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
Alan Coxbf936f92010-06-01 22:52:43 +02001213 mutex_unlock(&port->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 return 0;
1215}
1216
Alan Cox9492e132008-04-30 00:54:15 -07001217static int rc_get_serial_info(struct riscom_port *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 struct serial_struct __user *retinfo)
1219{
1220 struct serial_struct tmp;
1221 struct riscom_board *bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 memset(&tmp, 0, sizeof(tmp));
1224 tmp.type = PORT_CIRRUS;
1225 tmp.line = port - rc_port;
Alan Coxbf936f92010-06-01 22:52:43 +02001226
1227 mutex_lock(&port->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 tmp.port = bp->base;
1229 tmp.irq = bp->irq;
Alan Cox85f8f812008-07-16 21:55:29 +01001230 tmp.flags = port->port.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001232 tmp.close_delay = port->port.close_delay * HZ/100;
1233 tmp.closing_wait = port->port.closing_wait * HZ/100;
Alan Coxbf936f92010-06-01 22:52:43 +02001234 mutex_unlock(&port->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 tmp.xmit_fifo_size = CD180_NFIFO;
1236 return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
1237}
1238
Alan Cox9492e132008-04-30 00:54:15 -07001239static int rc_ioctl(struct tty_struct *tty, struct file *filp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241{
Alan Coxc9f19e92009-01-02 13:47:26 +00001242 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 void __user *argp = (void __user *)arg;
Alan Cox781cff52008-07-22 11:18:30 +01001244 int retval;
Alan Cox9492e132008-04-30 00:54:15 -07001245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
1247 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -07001248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 switch (cmd) {
Alan Cox9492e132008-04-30 00:54:15 -07001250 case TIOCGSERIAL:
Alan Coxeb174552008-04-30 00:53:21 -07001251 retval = rc_get_serial_info(port, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 break;
Alan Cox9492e132008-04-30 00:54:15 -07001253 case TIOCSSERIAL:
Alan Cox6ff1ab22009-09-19 13:13:22 -07001254 retval = rc_set_serial_info(tty, port, argp);
Alan Coxeb174552008-04-30 00:53:21 -07001255 break;
Alan Cox9492e132008-04-30 00:54:15 -07001256 default:
Alan Coxeb174552008-04-30 00:53:21 -07001257 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
Alan Coxeb174552008-04-30 00:53:21 -07001259 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260}
1261
Alan Cox9492e132008-04-30 00:54:15 -07001262static void rc_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263{
Alan Coxc9f19e92009-01-02 13:47:26 +00001264 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 struct riscom_board *bp;
1266 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if (rc_paranoia_check(port, tty->name, "rc_throttle"))
1269 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001271
1272 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 port->MSVR &= ~MSVR_RTS;
1274 rc_out(bp, CD180_CAR, port_No(port));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001275 if (I_IXOFF(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 rc_wait_CCR(bp);
1277 rc_out(bp, CD180_CCR, CCR_SSCH2);
1278 rc_wait_CCR(bp);
1279 }
1280 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001281 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282}
1283
Alan Cox9492e132008-04-30 00:54:15 -07001284static void rc_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
Alan Coxc9f19e92009-01-02 13:47:26 +00001286 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 struct riscom_board *bp;
1288 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
1291 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001293
Alan Cox9492e132008-04-30 00:54:15 -07001294 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 port->MSVR |= MSVR_RTS;
1296 rc_out(bp, CD180_CAR, port_No(port));
1297 if (I_IXOFF(tty)) {
1298 rc_wait_CCR(bp);
1299 rc_out(bp, CD180_CCR, CCR_SSCH1);
1300 rc_wait_CCR(bp);
1301 }
1302 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001303 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304}
1305
Alan Cox9492e132008-04-30 00:54:15 -07001306static void rc_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307{
Alan Coxc9f19e92009-01-02 13:47:26 +00001308 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 struct riscom_board *bp;
1310 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 if (rc_paranoia_check(port, tty->name, "rc_stop"))
1313 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001314
Alan Cox9492e132008-04-30 00:54:15 -07001315 bp = port_Board(port);
1316
1317 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 port->IER &= ~IER_TXRDY;
1319 rc_out(bp, CD180_CAR, port_No(port));
1320 rc_out(bp, CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001321 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322}
1323
Alan Cox9492e132008-04-30 00:54:15 -07001324static void rc_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325{
Alan Coxc9f19e92009-01-02 13:47:26 +00001326 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 struct riscom_board *bp;
1328 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (rc_paranoia_check(port, tty->name, "rc_start"))
1331 return;
Alan Cox9492e132008-04-30 00:54:15 -07001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001334
Jeff Garzikd9afa432008-02-06 01:36:11 -08001335 spin_lock_irqsave(&riscom_lock, flags);
1336
Alan Cox85f8f812008-07-16 21:55:29 +01001337 if (port->xmit_cnt && port->port.xmit_buf && !(port->IER & IER_TXRDY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 port->IER |= IER_TXRDY;
1339 rc_out(bp, CD180_CAR, port_No(port));
1340 rc_out(bp, CD180_IER, port->IER);
1341 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001342 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
1344
Alan Cox9492e132008-04-30 00:54:15 -07001345static void rc_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
Alan Coxc9f19e92009-01-02 13:47:26 +00001347 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (rc_paranoia_check(port, tty->name, "rc_hangup"))
1350 return;
Alan Cox9492e132008-04-30 00:54:15 -07001351
Alan Cox6ff1ab22009-09-19 13:13:22 -07001352 tty_port_hangup(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353}
1354
Alan Cox9492e132008-04-30 00:54:15 -07001355static void rc_set_termios(struct tty_struct *tty,
1356 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357{
Alan Coxc9f19e92009-01-02 13:47:26 +00001358 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
1362 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Jeff Garzikd9afa432008-02-06 01:36:11 -08001364 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox6ff1ab22009-09-19 13:13:22 -07001365 rc_change_speed(tty, port_Board(port), port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001366 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 if ((old_termios->c_cflag & CRTSCTS) &&
1369 !(tty->termios->c_cflag & CRTSCTS)) {
1370 tty->hw_stopped = 0;
1371 rc_start(tty);
1372 }
1373}
1374
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001375static const struct tty_operations riscom_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 .open = rc_open,
1377 .close = rc_close,
1378 .write = rc_write,
1379 .put_char = rc_put_char,
1380 .flush_chars = rc_flush_chars,
1381 .write_room = rc_write_room,
1382 .chars_in_buffer = rc_chars_in_buffer,
1383 .flush_buffer = rc_flush_buffer,
1384 .ioctl = rc_ioctl,
1385 .throttle = rc_throttle,
1386 .unthrottle = rc_unthrottle,
1387 .set_termios = rc_set_termios,
1388 .stop = rc_stop,
1389 .start = rc_start,
1390 .hangup = rc_hangup,
1391 .tiocmget = rc_tiocmget,
1392 .tiocmset = rc_tiocmset,
Alan Cox781cff52008-07-22 11:18:30 +01001393 .break_ctl = rc_send_break,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394};
1395
Alan Cox31f35932009-01-02 13:45:05 +00001396static const struct tty_port_operations riscom_port_ops = {
1397 .carrier_raised = carrier_raised,
Alan Cox8f1e6722009-11-30 13:16:47 +00001398 .dtr_rts = dtr_rts,
Alan Cox6ff1ab22009-09-19 13:13:22 -07001399 .shutdown = rc_close_port,
Alan Cox8f1e6722009-11-30 13:16:47 +00001400 .activate = rc_activate_port,
Alan Cox31f35932009-01-02 13:45:05 +00001401};
1402
1403
Jiri Slaby1386a822008-02-07 00:16:36 -08001404static int __init rc_init_drivers(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405{
1406 int error;
1407 int i;
1408
1409 riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
Alan Cox9492e132008-04-30 00:54:15 -07001410 if (!riscom_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return -ENOMEM;
Alan Cox9492e132008-04-30 00:54:15 -07001412
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 riscom_driver->owner = THIS_MODULE;
1414 riscom_driver->name = "ttyL";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 riscom_driver->major = RISCOM8_NORMAL_MAJOR;
1416 riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
1417 riscom_driver->subtype = SERIAL_TYPE_NORMAL;
1418 riscom_driver->init_termios = tty_std_termios;
1419 riscom_driver->init_termios.c_cflag =
1420 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08001421 riscom_driver->init_termios.c_ispeed = 9600;
1422 riscom_driver->init_termios.c_ospeed = 9600;
Alan Cox781cff52008-07-22 11:18:30 +01001423 riscom_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 tty_set_operations(riscom_driver, &riscom_ops);
Alan Cox9492e132008-04-30 00:54:15 -07001425 error = tty_register_driver(riscom_driver);
1426 if (error != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 put_tty_driver(riscom_driver);
1428 printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
Alan Cox9492e132008-04-30 00:54:15 -07001429 "error = %d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 return 1;
1431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 memset(rc_port, 0, sizeof(rc_port));
1433 for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
Alan Cox85f8f812008-07-16 21:55:29 +01001434 tty_port_init(&rc_port[i].port);
Alan Cox31f35932009-01-02 13:45:05 +00001435 rc_port[i].port.ops = &riscom_port_ops;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001436 rc_port[i].magic = RISCOM8_MAGIC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 return 0;
1439}
1440
1441static void rc_release_drivers(void)
1442{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 tty_unregister_driver(riscom_driver);
1444 put_tty_driver(riscom_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445}
1446
1447#ifndef MODULE
1448/*
1449 * Called at boot time.
Alan Cox9492e132008-04-30 00:54:15 -07001450 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 * You can specify IO base for up to RC_NBOARD cards,
1452 * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
1453 * Note that there will be no probing at default
1454 * addresses in this case.
1455 *
Alan Cox9492e132008-04-30 00:54:15 -07001456 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457static int __init riscom8_setup(char *str)
1458{
1459 int ints[RC_NBOARD];
1460 int i;
1461
1462 str = get_options(str, ARRAY_SIZE(ints), ints);
1463
1464 for (i = 0; i < RC_NBOARD; i++) {
1465 if (i < ints[0])
1466 rc_board[i].base = ints[i+1];
Alan Cox9492e132008-04-30 00:54:15 -07001467 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 rc_board[i].base = 0;
1469 }
1470 return 1;
1471}
1472
1473__setup("riscom8=", riscom8_setup);
1474#endif
1475
1476static char banner[] __initdata =
1477 KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
1478 "1994-1996.\n";
1479static char no_boards_msg[] __initdata =
1480 KERN_INFO "rc: No RISCom/8 boards detected.\n";
1481
Alan Cox9492e132008-04-30 00:54:15 -07001482/*
1483 * This routine must be called by kernel at boot time
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 */
1485static int __init riscom8_init(void)
1486{
1487 int i;
1488 int found = 0;
1489
1490 printk(banner);
1491
Alan Cox9492e132008-04-30 00:54:15 -07001492 if (rc_init_drivers())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return -EIO;
1494
Alan Cox9492e132008-04-30 00:54:15 -07001495 for (i = 0; i < RC_NBOARD; i++)
1496 if (rc_board[i].base && !rc_probe(&rc_board[i]))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 found++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (!found) {
1499 rc_release_drivers();
1500 printk(no_boards_msg);
1501 return -EIO;
1502 }
1503 return 0;
1504}
1505
1506#ifdef MODULE
1507static int iobase;
1508static int iobase1;
1509static int iobase2;
1510static int iobase3;
Rusty Russell8d3b33f2006-03-25 03:07:05 -08001511module_param(iobase, int, 0);
1512module_param(iobase1, int, 0);
1513module_param(iobase2, int, 0);
1514module_param(iobase3, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516MODULE_LICENSE("GPL");
Scott James Remnant5c9f5802009-04-06 17:33:26 +01001517MODULE_ALIAS_CHARDEV_MAJOR(RISCOM8_NORMAL_MAJOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518#endif /* MODULE */
1519
1520/*
1521 * You can setup up to 4 boards (current value of RC_NBOARD)
1522 * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
1523 *
1524 */
Alan Cox9492e132008-04-30 00:54:15 -07001525static int __init riscom8_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526{
1527#ifdef MODULE
1528 int i;
1529
1530 if (iobase || iobase1 || iobase2 || iobase3) {
Alan Cox9492e132008-04-30 00:54:15 -07001531 for (i = 0; i < RC_NBOARD; i++)
Jiri Slaby9efda792008-03-13 12:32:39 -07001532 rc_board[i].base = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 }
1534
1535 if (iobase)
1536 rc_board[0].base = iobase;
1537 if (iobase1)
1538 rc_board[1].base = iobase1;
1539 if (iobase2)
1540 rc_board[2].base = iobase2;
1541 if (iobase3)
1542 rc_board[3].base = iobase3;
1543#endif /* MODULE */
1544
1545 return riscom8_init();
1546}
Alan Cox9492e132008-04-30 00:54:15 -07001547
1548static void __exit riscom8_exit_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549{
1550 int i;
Alan Cox9492e132008-04-30 00:54:15 -07001551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 rc_release_drivers();
Alan Cox9492e132008-04-30 00:54:15 -07001553 for (i = 0; i < RC_NBOARD; i++)
1554 if (rc_board[i].flags & RC_BOARD_PRESENT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 rc_release_io_range(&rc_board[i]);
Alan Cox9492e132008-04-30 00:54:15 -07001556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557}
1558
1559module_init(riscom8_init_module);
1560module_exit(riscom8_exit_module);