blob: 217660451237a79c7cd186d38697bad07f9dbcf8 [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 Cox85f8f812008-07-16 21:55:29 +0100345 tty = port->port.tty;
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)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return;
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));
362 return;
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 Cox85f8f812008-07-16 21:55:29 +0100368 if (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 Cox33f0f882006-01-09 20:54:13 -0800382 tty_insert_flip_char(tty, ch, flag);
383 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384}
385
Alan Cox9492e132008-04-30 00:54:15 -0700386static void rc_receive(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
388 struct riscom_port *port;
389 struct tty_struct *tty;
390 unsigned char count;
Alan Cox9492e132008-04-30 00:54:15 -0700391
392 port = rc_get_port(bp, "Receive");
393 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return;
Alan Cox9492e132008-04-30 00:54:15 -0700395
Alan Cox85f8f812008-07-16 21:55:29 +0100396 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 count = rc_in(bp, CD180_RDCR);
Alan Cox9492e132008-04-30 00:54:15 -0700399
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400#ifdef RC_REPORT_FIFO
401 port->hits[count > 8 ? 9 : count]++;
Alan Cox9492e132008-04-30 00:54:15 -0700402#endif
403
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 while (count--) {
Alan Cox33f0f882006-01-09 20:54:13 -0800405 if (tty_buffer_request_room(tty, 1) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 printk(KERN_WARNING "rc%d: port %d: Working around "
407 "flip buffer overflow.\n",
408 board_No(bp), port_No(port));
409 break;
410 }
Alan Cox33f0f882006-01-09 20:54:13 -0800411 tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 }
Alan Cox33f0f882006-01-09 20:54:13 -0800413 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Alan Cox9492e132008-04-30 00:54:15 -0700416static void rc_transmit(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 struct riscom_port *port;
419 struct tty_struct *tty;
420 unsigned char count;
Alan Cox9492e132008-04-30 00:54:15 -0700421
422 port = rc_get_port(bp, "Transmit");
423 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return;
Alan Cox9492e132008-04-30 00:54:15 -0700425
Alan Cox85f8f812008-07-16 21:55:29 +0100426 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700427
428 if (port->IER & IER_TXEMPTY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 /* FIFO drained */
430 rc_out(bp, CD180_CAR, port_No(port));
431 port->IER &= ~IER_TXEMPTY;
432 rc_out(bp, CD180_IER, port->IER);
433 return;
434 }
Alan Cox9492e132008-04-30 00:54:15 -0700435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if ((port->xmit_cnt <= 0 && !port->break_length)
437 || tty->stopped || tty->hw_stopped) {
438 rc_out(bp, CD180_CAR, port_No(port));
439 port->IER &= ~IER_TXRDY;
440 rc_out(bp, CD180_IER, port->IER);
441 return;
442 }
Alan Cox9492e132008-04-30 00:54:15 -0700443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 if (port->break_length) {
445 if (port->break_length > 0) {
446 if (port->COR2 & COR2_ETC) {
447 rc_out(bp, CD180_TDR, CD180_C_ESC);
448 rc_out(bp, CD180_TDR, CD180_C_SBRK);
449 port->COR2 &= ~COR2_ETC;
450 }
451 count = min_t(int, port->break_length, 0xff);
452 rc_out(bp, CD180_TDR, CD180_C_ESC);
453 rc_out(bp, CD180_TDR, CD180_C_DELAY);
454 rc_out(bp, CD180_TDR, count);
Alan Cox9492e132008-04-30 00:54:15 -0700455 port->break_length -= count;
456 if (port->break_length == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 port->break_length--;
458 } else {
459 rc_out(bp, CD180_TDR, CD180_C_ESC);
460 rc_out(bp, CD180_TDR, CD180_C_EBRK);
461 rc_out(bp, CD180_COR2, port->COR2);
462 rc_wait_CCR(bp);
463 rc_out(bp, CD180_CCR, CCR_CORCHG2);
464 port->break_length = 0;
465 }
466 return;
467 }
Alan Cox9492e132008-04-30 00:54:15 -0700468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 count = CD180_NFIFO;
470 do {
Alan Cox85f8f812008-07-16 21:55:29 +0100471 rc_out(bp, CD180_TDR, port->port.xmit_buf[port->xmit_tail++]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
473 if (--port->xmit_cnt <= 0)
474 break;
475 } while (--count > 0);
Alan Cox9492e132008-04-30 00:54:15 -0700476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (port->xmit_cnt <= 0) {
478 rc_out(bp, CD180_CAR, port_No(port));
479 port->IER &= ~IER_TXRDY;
480 rc_out(bp, CD180_IER, port->IER);
481 }
482 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800483 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
Alan Cox9492e132008-04-30 00:54:15 -0700486static void rc_check_modem(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 struct riscom_port *port;
489 struct tty_struct *tty;
490 unsigned char mcr;
Alan Cox9492e132008-04-30 00:54:15 -0700491
492 port = rc_get_port(bp, "Modem");
493 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 return;
Alan Cox9492e132008-04-30 00:54:15 -0700495
Alan Cox85f8f812008-07-16 21:55:29 +0100496 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 mcr = rc_in(bp, CD180_MCR);
Alan Cox9492e132008-04-30 00:54:15 -0700499 if (mcr & MCR_CDCHG) {
500 if (rc_in(bp, CD180_MSVR) & MSVR_CD)
Alan Cox85f8f812008-07-16 21:55:29 +0100501 wake_up_interruptible(&port->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 else
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800503 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
Alan Cox9492e132008-04-30 00:54:15 -0700505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506#ifdef RISCOM_BRAIN_DAMAGED_CTS
507 if (mcr & MCR_CTSCHG) {
508 if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
509 tty->hw_stopped = 0;
510 port->IER |= IER_TXRDY;
511 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800512 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 } else {
514 tty->hw_stopped = 1;
515 port->IER &= ~IER_TXRDY;
516 }
517 rc_out(bp, CD180_IER, port->IER);
518 }
519 if (mcr & MCR_DSRCHG) {
520 if (rc_in(bp, CD180_MSVR) & MSVR_DSR) {
521 tty->hw_stopped = 0;
522 port->IER |= IER_TXRDY;
523 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800524 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 } else {
526 tty->hw_stopped = 1;
527 port->IER &= ~IER_TXRDY;
528 }
529 rc_out(bp, CD180_IER, port->IER);
530 }
531#endif /* RISCOM_BRAIN_DAMAGED_CTS */
Alan Cox9492e132008-04-30 00:54:15 -0700532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 /* Clear change bits */
534 rc_out(bp, CD180_MCR, 0);
535}
536
537/* The main interrupt processing routine */
Alan Cox9492e132008-04-30 00:54:15 -0700538static irqreturn_t rc_interrupt(int dummy, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
540 unsigned char status;
541 unsigned char ack;
Jeff Garzikf07ef392007-10-23 19:12:11 -0400542 struct riscom_board *bp = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 unsigned long loop = 0;
544 int handled = 0;
545
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400546 if (!(bp->flags & RC_BOARD_ACTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return IRQ_NONE;
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
550 (RC_BSR_TOUT | RC_BSR_TINT |
551 RC_BSR_MINT | RC_BSR_RINT))) {
552 handled = 1;
Alan Cox9492e132008-04-30 00:54:15 -0700553 if (status & RC_BSR_TOUT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 printk(KERN_WARNING "rc%d: Got timeout. Hardware "
555 "error?\n", board_No(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 else if (status & RC_BSR_RINT) {
557 ack = rc_in(bp, RC_ACK_RINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (ack == (RC_ID | GIVR_IT_RCV))
559 rc_receive(bp);
560 else if (ack == (RC_ID | GIVR_IT_REXC))
561 rc_receive_exc(bp);
562 else
563 printk(KERN_WARNING "rc%d: Bad receive ack "
564 "0x%02x.\n",
565 board_No(bp), ack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 } else if (status & RC_BSR_TINT) {
567 ack = rc_in(bp, RC_ACK_TINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (ack == (RC_ID | GIVR_IT_TX))
569 rc_transmit(bp);
570 else
571 printk(KERN_WARNING "rc%d: Bad transmit ack "
572 "0x%02x.\n",
573 board_No(bp), ack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 } else /* if (status & RC_BSR_MINT) */ {
575 ack = rc_in(bp, RC_ACK_MINT);
Alan Cox9492e132008-04-30 00:54:15 -0700576 if (ack == (RC_ID | GIVR_IT_MODEM))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 rc_check_modem(bp);
578 else
579 printk(KERN_WARNING "rc%d: Bad modem ack "
580 "0x%02x.\n",
581 board_No(bp), ack);
Alan Cox9492e132008-04-30 00:54:15 -0700582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
584 rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
585 }
586 return IRQ_RETVAL(handled);
587}
588
589/*
590 * Routines for open & close processing.
591 */
592
593/* Called with disabled interrupts */
Alan Cox9492e132008-04-30 00:54:15 -0700594static int rc_setup_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595{
596 int error;
597
Alan Cox9492e132008-04-30 00:54:15 -0700598 if (bp->flags & RC_BOARD_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700600
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700601 error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
Jeff Garzikf07ef392007-10-23 19:12:11 -0400602 "RISCom/8", bp);
Alan Cox9492e132008-04-30 00:54:15 -0700603 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 return error;
Alan Cox9492e132008-04-30 00:54:15 -0700605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 rc_out(bp, RC_CTOUT, 0); /* Just in case */
607 bp->DTR = ~0;
608 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
Alan Cox9492e132008-04-30 00:54:15 -0700609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 bp->flags |= RC_BOARD_ACTIVE;
Alan Cox9492e132008-04-30 00:54:15 -0700611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return 0;
613}
614
615/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400616static void rc_shutdown_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 if (!(bp->flags & RC_BOARD_ACTIVE))
619 return;
Alan Cox9492e132008-04-30 00:54:15 -0700620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 bp->flags &= ~RC_BOARD_ACTIVE;
Alan Cox9492e132008-04-30 00:54:15 -0700622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 free_irq(bp->irq, NULL);
Alan Cox9492e132008-04-30 00:54:15 -0700624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 bp->DTR = ~0;
626 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
Alan Cox9492e132008-04-30 00:54:15 -0700627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629
630/*
Alan Cox9492e132008-04-30 00:54:15 -0700631 * Setting up port characteristics.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 * Must be called with disabled interrupts
633 */
634static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
635{
Alan Cox85f8f812008-07-16 21:55:29 +0100636 struct tty_struct *tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 unsigned long baud;
638 long tmp;
639 unsigned char cor1 = 0, cor3 = 0;
640 unsigned char mcor1 = 0, mcor2 = 0;
Alan Cox9492e132008-04-30 00:54:15 -0700641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 port->IER = 0;
643 port->COR2 = 0;
644 port->MSVR = MSVR_RTS;
Alan Cox9492e132008-04-30 00:54:15 -0700645
Alan Coxc7bce302006-09-30 23:27:24 -0700646 baud = tty_get_baud_rate(tty);
Alan Cox9492e132008-04-30 00:54:15 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 /* Select port on the board */
649 rc_out(bp, CD180_CAR, port_No(port));
Alan Cox9492e132008-04-30 00:54:15 -0700650
Alan Coxc7bce302006-09-30 23:27:24 -0700651 if (!baud) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 /* Drop DTR & exit */
653 bp->DTR |= (1u << port_No(port));
654 rc_out(bp, RC_DTR, bp->DTR);
655 return;
656 } else {
657 /* Set DTR on */
658 bp->DTR &= ~(1u << port_No(port));
659 rc_out(bp, RC_DTR, bp->DTR);
660 }
Alan Cox9492e132008-04-30 00:54:15 -0700661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 /*
Alan Cox9492e132008-04-30 00:54:15 -0700663 * Now we must calculate some speed depended things
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 */
Alan Cox9492e132008-04-30 00:54:15 -0700665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /* Set baud rate for port */
Alan Coxc7bce302006-09-30 23:27:24 -0700667 tmp = (((RC_OSCFREQ + baud/2) / baud +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 CD180_TPC/2) / CD180_TPC);
669
Alan Cox9492e132008-04-30 00:54:15 -0700670 rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
671 rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
672 rc_out(bp, CD180_RBPRL, tmp & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 rc_out(bp, CD180_TBPRL, tmp & 0xff);
Alan Cox9492e132008-04-30 00:54:15 -0700674
Alan Coxc7bce302006-09-30 23:27:24 -0700675 baud = (baud + 5) / 10; /* Estimated CPS */
Alan Cox9492e132008-04-30 00:54:15 -0700676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 /* Two timer ticks seems enough to wakeup something like SLIP driver */
Alan Cox9492e132008-04-30 00:54:15 -0700678 tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
680 SERIAL_XMIT_SIZE - 1 : tmp);
Alan Cox9492e132008-04-30 00:54:15 -0700681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 /* Receiver timeout will be transmission time for 1.5 chars */
683 tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
684 tmp = (tmp > 0xff) ? 0xff : tmp;
685 rc_out(bp, CD180_RTPR, tmp);
Alan Cox9492e132008-04-30 00:54:15 -0700686
687 switch (C_CSIZE(tty)) {
688 case CS5:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 cor1 |= COR1_5BITS;
690 break;
Alan Cox9492e132008-04-30 00:54:15 -0700691 case CS6:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 cor1 |= COR1_6BITS;
693 break;
Alan Cox9492e132008-04-30 00:54:15 -0700694 case CS7:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 cor1 |= COR1_7BITS;
696 break;
Alan Cox9492e132008-04-30 00:54:15 -0700697 case CS8:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 cor1 |= COR1_8BITS;
699 break;
700 }
Alan Cox9492e132008-04-30 00:54:15 -0700701 if (C_CSTOPB(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 cor1 |= COR1_2SB;
Alan Cox9492e132008-04-30 00:54:15 -0700703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 cor1 |= COR1_IGNORE;
Alan Cox9492e132008-04-30 00:54:15 -0700705 if (C_PARENB(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 cor1 |= COR1_NORMPAR;
Alan Cox9492e132008-04-30 00:54:15 -0700707 if (C_PARODD(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 cor1 |= COR1_ODDP;
Alan Cox9492e132008-04-30 00:54:15 -0700709 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 cor1 &= ~COR1_IGNORE;
711 }
712 /* Set marking of some errors */
713 port->mark_mask = RCSR_OE | RCSR_TOUT;
Alan Cox9492e132008-04-30 00:54:15 -0700714 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 port->mark_mask |= RCSR_FE | RCSR_PE;
Alan Cox9492e132008-04-30 00:54:15 -0700716 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 port->mark_mask |= RCSR_BREAK;
Alan Cox9492e132008-04-30 00:54:15 -0700718 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
Alan Cox9492e132008-04-30 00:54:15 -0700720 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 port->mark_mask &= ~RCSR_BREAK;
Alan Cox9492e132008-04-30 00:54:15 -0700722 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 /* Real raw mode. Ignore all */
724 port->mark_mask &= ~RCSR_OE;
725 }
726 /* Enable Hardware Flow Control */
727 if (C_CRTSCTS(tty)) {
728#ifdef RISCOM_BRAIN_DAMAGED_CTS
729 port->IER |= IER_DSR | IER_CTS;
730 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
731 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
Alan Cox9492e132008-04-30 00:54:15 -0700732 tty->hw_stopped = !(rc_in(bp, CD180_MSVR) &
733 (MSVR_CTS|MSVR_DSR));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734#else
735 port->COR2 |= COR2_CTSAE;
736#endif
737 }
738 /* Enable Software Flow Control. FIXME: I'm not sure about this */
739 /* Some people reported that it works, but I still doubt */
740 if (I_IXON(tty)) {
741 port->COR2 |= COR2_TXIBE;
742 cor3 |= (COR3_FCT | COR3_SCDE);
743 if (I_IXANY(tty))
744 port->COR2 |= COR2_IXM;
745 rc_out(bp, CD180_SCHR1, START_CHAR(tty));
746 rc_out(bp, CD180_SCHR2, STOP_CHAR(tty));
747 rc_out(bp, CD180_SCHR3, START_CHAR(tty));
748 rc_out(bp, CD180_SCHR4, STOP_CHAR(tty));
749 }
750 if (!C_CLOCAL(tty)) {
751 /* Enable CD check */
752 port->IER |= IER_CD;
753 mcor1 |= MCOR1_CDZD;
754 mcor2 |= MCOR2_CDOD;
755 }
Alan Cox9492e132008-04-30 00:54:15 -0700756
757 if (C_CREAD(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 /* Enable receiver */
759 port->IER |= IER_RXD;
Alan Cox9492e132008-04-30 00:54:15 -0700760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 /* Set input FIFO size (1-8 bytes) */
Alan Cox9492e132008-04-30 00:54:15 -0700762 cor3 |= RISCOM_RXFIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 /* Setting up CD180 channel registers */
764 rc_out(bp, CD180_COR1, cor1);
765 rc_out(bp, CD180_COR2, port->COR2);
766 rc_out(bp, CD180_COR3, cor3);
767 /* Make CD180 know about registers change */
768 rc_wait_CCR(bp);
769 rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
770 /* Setting up modem option registers */
771 rc_out(bp, CD180_MCOR1, mcor1);
772 rc_out(bp, CD180_MCOR2, mcor2);
773 /* Enable CD180 transmitter & receiver */
774 rc_wait_CCR(bp);
775 rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
776 /* Enable interrupts */
777 rc_out(bp, CD180_IER, port->IER);
778 /* And finally set RTS on */
779 rc_out(bp, CD180_MSVR, port->MSVR);
780}
781
782/* Must be called with interrupts enabled */
783static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
784{
785 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700786
Alan Cox85f8f812008-07-16 21:55:29 +0100787 if (port->port.flags & ASYNC_INITIALIZED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700789
Alan Cox85f8f812008-07-16 21:55:29 +0100790 if (tty_port_alloc_xmit_buf(&port->port) < 0)
791 return -ENOMEM;
792
Jeff Garzikd9afa432008-02-06 01:36:11 -0800793 spin_lock_irqsave(&riscom_lock, flags);
794
Alan Coxd99101f2008-07-16 21:55:37 +0100795 clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
Alan Cox85f8f812008-07-16 21:55:29 +0100796 if (port->port.count == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 bp->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
799 rc_change_speed(bp, port);
Alan Cox85f8f812008-07-16 21:55:29 +0100800 port->port.flags |= ASYNC_INITIALIZED;
Alan Cox9492e132008-04-30 00:54:15 -0700801
Jeff Garzikd9afa432008-02-06 01:36:11 -0800802 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return 0;
804}
805
806/* Must be called with interrupts disabled */
Alan Coxd99101f2008-07-16 21:55:37 +0100807static void rc_shutdown_port(struct tty_struct *tty,
808 struct riscom_board *bp, struct riscom_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
Alan Cox85f8f812008-07-16 21:55:29 +0100810 if (!(port->port.flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return;
Alan Cox9492e132008-04-30 00:54:15 -0700812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813#ifdef RC_REPORT_OVERRUN
814 printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
815 board_No(bp), port_No(port), port->overrun);
Alan Cox9492e132008-04-30 00:54:15 -0700816#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817#ifdef RC_REPORT_FIFO
818 {
819 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
822 board_No(bp), port_No(port));
Alan Cox9492e132008-04-30 00:54:15 -0700823 for (i = 0; i < 10; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 printk("%ld ", port->hits[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 printk("].\n");
826 }
Alan Cox9492e132008-04-30 00:54:15 -0700827#endif
Alan Cox85f8f812008-07-16 21:55:29 +0100828 tty_port_free_xmit_buf(&port->port);
Alan Coxd99101f2008-07-16 21:55:37 +0100829 if (C_HUPCL(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 /* Drop DTR */
831 bp->DTR |= (1u << port_No(port));
832 rc_out(bp, RC_DTR, bp->DTR);
833 }
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 Cox85f8f812008-07-16 21:55:29 +0100845 port->port.flags &= ~ASYNC_INITIALIZED;
Alan Cox9492e132008-04-30 00:54:15 -0700846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (--bp->count < 0) {
848 printk(KERN_INFO "rc%d: rc_shutdown_port: "
849 "bad board count: %d\n",
850 board_No(bp), bp->count);
851 bp->count = 0;
852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 /*
854 * If this is the last opened port on the board
855 * shutdown whole board
856 */
Alan Cox9492e132008-04-30 00:54:15 -0700857 if (!bp->count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 rc_shutdown_board(bp);
859}
860
Alan Cox31f35932009-01-02 13:45:05 +0000861static int carrier_raised(struct tty_port *port)
862{
863 struct riscom_port *p = container_of(port, struct riscom_port, port);
864 struct riscom_board *bp = port_Board(p);
865 unsigned long flags;
866 int CD;
867
868 spin_lock_irqsave(&riscom_lock, flags);
869 rc_out(bp, CD180_CAR, port_No(p));
870 CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
871 rc_out(bp, CD180_MSVR, MSVR_RTS);
872 bp->DTR &= ~(1u << port_No(p));
873 rc_out(bp, RC_DTR, bp->DTR);
874 spin_unlock_irqrestore(&riscom_lock, flags);
875 return CD;
876}
877
Alan Cox9492e132008-04-30 00:54:15 -0700878static int rc_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 int board;
881 int error;
Alan Cox9492e132008-04-30 00:54:15 -0700882 struct riscom_port *port;
883 struct riscom_board *bp;
884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 board = RC_BOARD(tty->index);
886 if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
887 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -0700888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 bp = &rc_board[board];
890 port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
891 if (rc_paranoia_check(port, tty->name, "rc_open"))
892 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -0700893
894 error = rc_setup_board(bp);
895 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return error;
Alan Cox9492e132008-04-30 00:54:15 -0700897
Alan Cox85f8f812008-07-16 21:55:29 +0100898 port->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 tty->driver_data = port;
Alan Cox85f8f812008-07-16 21:55:29 +0100900 port->port.tty = tty;
Alan Cox9492e132008-04-30 00:54:15 -0700901
902 error = rc_setup_port(bp, port);
903 if (error == 0)
Alan Cox36c621d2009-01-02 13:46:10 +0000904 error = tty_port_block_til_ready(&port->port, tty, filp);
Alan Cox9492e132008-04-30 00:54:15 -0700905 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907
Alan Cox978e5952008-04-30 00:53:59 -0700908static void rc_flush_buffer(struct tty_struct *tty)
909{
Alan Coxc9f19e92009-01-02 13:47:26 +0000910 struct riscom_port *port = tty->driver_data;
Alan Cox978e5952008-04-30 00:53:59 -0700911 unsigned long flags;
912
913 if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
914 return;
915
916 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox978e5952008-04-30 00:53:59 -0700917 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
Alan Cox978e5952008-04-30 00:53:59 -0700918 spin_unlock_irqrestore(&riscom_lock, flags);
919
920 tty_wakeup(tty);
921}
922
Alan Cox9492e132008-04-30 00:54:15 -0700923static void rc_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
Alan Coxc9f19e92009-01-02 13:47:26 +0000925 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 struct riscom_board *bp;
927 unsigned long flags;
928 unsigned long timeout;
Alan Cox9492e132008-04-30 00:54:15 -0700929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 if (!port || rc_paranoia_check(port, tty->name, "close"))
931 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 bp = port_Board(port);
Alan Coxa6614992009-01-02 13:46:50 +0000934
935 if (tty_port_close_start(&port->port, tty, filp) == 0)
936 return;
937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /*
939 * At this point we stop accepting input. To do this, we
940 * disable the receive line status interrupts, and tell the
941 * interrupt driver to stop checking the data ready bit in the
942 * line status register.
943 */
Alan Coxc2ba38c2009-01-02 13:45:50 +0000944
945 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 port->IER &= ~IER_RXD;
Alan Cox85f8f812008-07-16 21:55:29 +0100947 if (port->port.flags & ASYNC_INITIALIZED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 port->IER &= ~IER_TXRDY;
949 port->IER |= IER_TXEMPTY;
950 rc_out(bp, CD180_CAR, port_No(port));
951 rc_out(bp, CD180_IER, port->IER);
952 /*
953 * Before we drop DTR, make sure the UART transmitter
954 * has completely drained; this is especially
955 * important if there is a transmit FIFO!
956 */
Alan Cox9492e132008-04-30 00:54:15 -0700957 timeout = jiffies + HZ;
958 while (port->IER & IER_TXEMPTY) {
Alan Coxc2ba38c2009-01-02 13:45:50 +0000959 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 msleep_interruptible(jiffies_to_msecs(port->timeout));
Alan Coxc2ba38c2009-01-02 13:45:50 +0000961 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 if (time_after(jiffies, timeout))
963 break;
964 }
965 }
Alan Coxd99101f2008-07-16 21:55:37 +0100966 rc_shutdown_port(tty, bp, port);
Alan Cox978e5952008-04-30 00:53:59 -0700967 rc_flush_buffer(tty);
Alan Coxc2ba38c2009-01-02 13:45:50 +0000968 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Alan Coxa6614992009-01-02 13:46:50 +0000970 tty_port_close_end(&port->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Alan Cox9492e132008-04-30 00:54:15 -0700973static int rc_write(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 const unsigned char *buf, int count)
975{
Alan Coxc9f19e92009-01-02 13:47:26 +0000976 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 struct riscom_board *bp;
978 int c, total = 0;
979 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (rc_paranoia_check(port, tty->name, "rc_write"))
982 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 bp = port_Board(port);
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -0800987 spin_lock_irqsave(&riscom_lock, flags);
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
990 SERIAL_XMIT_SIZE - port->xmit_head));
Jeff Garzikd9afa432008-02-06 01:36:11 -0800991 if (c <= 0)
992 break; /* lock continues to be held */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Alan Cox85f8f812008-07-16 21:55:29 +0100994 memcpy(port->port.xmit_buf + port->xmit_head, buf, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
996 port->xmit_cnt += c;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800997
998 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000 buf += c;
1001 count -= c;
1002 total += c;
1003 }
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1006 !(port->IER & IER_TXRDY)) {
1007 port->IER |= IER_TXRDY;
1008 rc_out(bp, CD180_CAR, port_No(port));
1009 rc_out(bp, CD180_IER, port->IER);
1010 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001011
1012 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 return total;
1015}
1016
Alan Cox9492e132008-04-30 00:54:15 -07001017static int rc_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Alan Coxc9f19e92009-01-02 13:47:26 +00001019 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 unsigned long flags;
Alan Coxbbbbb962008-04-30 00:54:05 -07001021 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 if (rc_paranoia_check(port, tty->name, "rc_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001024 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Jeff Garzikd9afa432008-02-06 01:36:11 -08001026 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -07001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
1029 goto out;
1030
Alan Cox85f8f812008-07-16 21:55:29 +01001031 port->port.xmit_buf[port->xmit_head++] = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1033 port->xmit_cnt++;
Alan Coxbbbbb962008-04-30 00:54:05 -07001034 ret = 1;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001035
1036out:
1037 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxbbbbb962008-04-30 00:54:05 -07001038 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039}
1040
Alan Cox9492e132008-04-30 00:54:15 -07001041static void rc_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
Alan Coxc9f19e92009-01-02 13:47:26 +00001043 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
1047 return;
Alan Cox9492e132008-04-30 00:54:15 -07001048
Alan Coxd99101f2008-07-16 21:55:37 +01001049 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return;
1051
Jeff Garzikd9afa432008-02-06 01:36:11 -08001052 spin_lock_irqsave(&riscom_lock, flags);
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 port->IER |= IER_TXRDY;
1055 rc_out(port_Board(port), CD180_CAR, port_No(port));
1056 rc_out(port_Board(port), CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001057
1058 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
Alan Cox9492e132008-04-30 00:54:15 -07001061static int rc_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062{
Alan Coxc9f19e92009-01-02 13:47:26 +00001063 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 int ret;
Alan Cox9492e132008-04-30 00:54:15 -07001065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 if (rc_paranoia_check(port, tty->name, "rc_write_room"))
1067 return 0;
1068
1069 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1070 if (ret < 0)
1071 ret = 0;
1072 return ret;
1073}
1074
1075static int rc_chars_in_buffer(struct tty_struct *tty)
1076{
Alan Coxc9f19e92009-01-02 13:47:26 +00001077 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
1080 return 0;
Alan Cox9492e132008-04-30 00:54:15 -07001081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return port->xmit_cnt;
1083}
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085static int rc_tiocmget(struct tty_struct *tty, struct file *file)
1086{
Alan Coxc9f19e92009-01-02 13:47:26 +00001087 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001088 struct riscom_board *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 unsigned char status;
1090 unsigned int result;
1091 unsigned long flags;
1092
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001093 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return -ENODEV;
1095
1096 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001097
1098 spin_lock_irqsave(&riscom_lock, flags);
1099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 rc_out(bp, CD180_CAR, port_No(port));
1101 status = rc_in(bp, CD180_MSVR);
1102 result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001103
1104 spin_unlock_irqrestore(&riscom_lock, flags);
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
1107 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1108 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
1109 | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
1110 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1111 return result;
1112}
1113
1114static int rc_tiocmset(struct tty_struct *tty, struct file *file,
1115 unsigned int set, unsigned int clear)
1116{
Alan Coxc9f19e92009-01-02 13:47:26 +00001117 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 unsigned long flags;
1119 struct riscom_board *bp;
1120
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001121 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return -ENODEV;
1123
1124 bp = port_Board(port);
1125
Jeff Garzikd9afa432008-02-06 01:36:11 -08001126 spin_lock_irqsave(&riscom_lock, flags);
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 if (set & TIOCM_RTS)
1129 port->MSVR |= MSVR_RTS;
1130 if (set & TIOCM_DTR)
1131 bp->DTR &= ~(1u << port_No(port));
1132
1133 if (clear & TIOCM_RTS)
1134 port->MSVR &= ~MSVR_RTS;
1135 if (clear & TIOCM_DTR)
1136 bp->DTR |= (1u << port_No(port));
1137
1138 rc_out(bp, CD180_CAR, port_No(port));
1139 rc_out(bp, CD180_MSVR, port->MSVR);
1140 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001141
1142 spin_unlock_irqrestore(&riscom_lock, flags);
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return 0;
1145}
1146
Alan Cox781cff52008-07-22 11:18:30 +01001147static int rc_send_break(struct tty_struct *tty, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148{
Alan Coxc9f19e92009-01-02 13:47:26 +00001149 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 struct riscom_board *bp = port_Board(port);
1151 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001152
Alan Cox781cff52008-07-22 11:18:30 +01001153 if (length == 0 || length == -1)
1154 return -EOPNOTSUPP;
1155
Jeff Garzikd9afa432008-02-06 01:36:11 -08001156 spin_lock_irqsave(&riscom_lock, flags);
1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 port->break_length = RISCOM_TPS / HZ * length;
1159 port->COR2 |= COR2_ETC;
1160 port->IER |= IER_TXRDY;
1161 rc_out(bp, CD180_CAR, port_No(port));
1162 rc_out(bp, CD180_COR2, port->COR2);
1163 rc_out(bp, CD180_IER, port->IER);
1164 rc_wait_CCR(bp);
1165 rc_out(bp, CD180_CCR, CCR_CORCHG2);
1166 rc_wait_CCR(bp);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001167
1168 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Cox781cff52008-07-22 11:18:30 +01001169 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170}
1171
Alan Cox9492e132008-04-30 00:54:15 -07001172static int rc_set_serial_info(struct riscom_port *port,
1173 struct serial_struct __user *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174{
1175 struct serial_struct tmp;
1176 struct riscom_board *bp = port_Board(port);
1177 int change_speed;
Alan Cox9492e132008-04-30 00:54:15 -07001178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
1180 return -EFAULT;
Alan Cox9492e132008-04-30 00:54:15 -07001181
1182#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if ((tmp.irq != bp->irq) ||
1184 (tmp.port != bp->base) ||
1185 (tmp.type != PORT_CIRRUS) ||
1186 (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
1187 (tmp.custom_divisor != 0) ||
1188 (tmp.xmit_fifo_size != CD180_NFIFO) ||
1189 (tmp.flags & ~RISCOM_LEGAL_FLAGS))
1190 return -EINVAL;
Alan Cox9492e132008-04-30 00:54:15 -07001191#endif
1192
Alan Cox85f8f812008-07-16 21:55:29 +01001193 change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 (tmp.flags & ASYNC_SPD_MASK));
Alan Cox9492e132008-04-30 00:54:15 -07001195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01001197 if ((tmp.close_delay != port->port.close_delay) ||
1198 (tmp.closing_wait != port->port.closing_wait) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 ((tmp.flags & ~ASYNC_USR_MASK) !=
Alan Cox85f8f812008-07-16 21:55:29 +01001200 (port->port.flags & ~ASYNC_USR_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return -EPERM;
Alan Cox85f8f812008-07-16 21:55:29 +01001202 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 (tmp.flags & ASYNC_USR_MASK));
1204 } else {
Alan Cox85f8f812008-07-16 21:55:29 +01001205 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 (tmp.flags & ASYNC_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001207 port->port.close_delay = tmp.close_delay;
1208 port->port.closing_wait = tmp.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 }
1210 if (change_speed) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001211 unsigned long flags;
1212
1213 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 rc_change_speed(bp, port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001215 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217 return 0;
1218}
1219
Alan Cox9492e132008-04-30 00:54:15 -07001220static int rc_get_serial_info(struct riscom_port *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 struct serial_struct __user *retinfo)
1222{
1223 struct serial_struct tmp;
1224 struct riscom_board *bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 memset(&tmp, 0, sizeof(tmp));
1227 tmp.type = PORT_CIRRUS;
1228 tmp.line = port - rc_port;
1229 tmp.port = bp->base;
1230 tmp.irq = bp->irq;
Alan Cox85f8f812008-07-16 21:55:29 +01001231 tmp.flags = port->port.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001233 tmp.close_delay = port->port.close_delay * HZ/100;
1234 tmp.closing_wait = port->port.closing_wait * HZ/100;
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:
1251 lock_kernel();
Alan Coxeb174552008-04-30 00:53:21 -07001252 retval = rc_get_serial_info(port, argp);
1253 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 break;
Alan Cox9492e132008-04-30 00:54:15 -07001255 case TIOCSSERIAL:
1256 lock_kernel();
Alan Coxeb174552008-04-30 00:53:21 -07001257 retval = rc_set_serial_info(port, argp);
1258 unlock_kernel();
1259 break;
Alan Cox9492e132008-04-30 00:54:15 -07001260 default:
Alan Coxeb174552008-04-30 00:53:21 -07001261 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 }
Alan Coxeb174552008-04-30 00:53:21 -07001263 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264}
1265
Alan Cox9492e132008-04-30 00:54:15 -07001266static void rc_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267{
Alan Coxc9f19e92009-01-02 13:47:26 +00001268 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 struct riscom_board *bp;
1270 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if (rc_paranoia_check(port, tty->name, "rc_throttle"))
1273 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001275
1276 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 port->MSVR &= ~MSVR_RTS;
1278 rc_out(bp, CD180_CAR, port_No(port));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001279 if (I_IXOFF(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 rc_wait_CCR(bp);
1281 rc_out(bp, CD180_CCR, CCR_SSCH2);
1282 rc_wait_CCR(bp);
1283 }
1284 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001285 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286}
1287
Alan Cox9492e132008-04-30 00:54:15 -07001288static void rc_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
Alan Coxc9f19e92009-01-02 13:47:26 +00001290 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 struct riscom_board *bp;
1292 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
1295 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001297
Alan Cox9492e132008-04-30 00:54:15 -07001298 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 port->MSVR |= MSVR_RTS;
1300 rc_out(bp, CD180_CAR, port_No(port));
1301 if (I_IXOFF(tty)) {
1302 rc_wait_CCR(bp);
1303 rc_out(bp, CD180_CCR, CCR_SSCH1);
1304 rc_wait_CCR(bp);
1305 }
1306 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001307 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308}
1309
Alan Cox9492e132008-04-30 00:54:15 -07001310static void rc_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
Alan Coxc9f19e92009-01-02 13:47:26 +00001312 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 struct riscom_board *bp;
1314 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (rc_paranoia_check(port, tty->name, "rc_stop"))
1317 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001318
Alan Cox9492e132008-04-30 00:54:15 -07001319 bp = port_Board(port);
1320
1321 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 port->IER &= ~IER_TXRDY;
1323 rc_out(bp, CD180_CAR, port_No(port));
1324 rc_out(bp, CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001325 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326}
1327
Alan Cox9492e132008-04-30 00:54:15 -07001328static void rc_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
Alan Coxc9f19e92009-01-02 13:47:26 +00001330 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 struct riscom_board *bp;
1332 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001333
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (rc_paranoia_check(port, tty->name, "rc_start"))
1335 return;
Alan Cox9492e132008-04-30 00:54:15 -07001336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001338
Jeff Garzikd9afa432008-02-06 01:36:11 -08001339 spin_lock_irqsave(&riscom_lock, flags);
1340
Alan Cox85f8f812008-07-16 21:55:29 +01001341 if (port->xmit_cnt && port->port.xmit_buf && !(port->IER & IER_TXRDY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 port->IER |= IER_TXRDY;
1343 rc_out(bp, CD180_CAR, port_No(port));
1344 rc_out(bp, CD180_IER, port->IER);
1345 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001346 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347}
1348
Alan Cox9492e132008-04-30 00:54:15 -07001349static void rc_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350{
Alan Coxc9f19e92009-01-02 13:47:26 +00001351 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 struct riscom_board *bp;
Alan Coxc2ba38c2009-01-02 13:45:50 +00001353 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (rc_paranoia_check(port, tty->name, "rc_hangup"))
1356 return;
Alan Cox9492e132008-04-30 00:54:15 -07001357
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001359
Alan Coxd99101f2008-07-16 21:55:37 +01001360 rc_shutdown_port(tty, bp, port);
Alan Coxc2ba38c2009-01-02 13:45:50 +00001361 spin_lock_irqsave(&port->port.lock, flags);
Alan Cox85f8f812008-07-16 21:55:29 +01001362 port->port.count = 0;
1363 port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
1364 port->port.tty = NULL;
1365 wake_up_interruptible(&port->port.open_wait);
Alan Coxc2ba38c2009-01-02 13:45:50 +00001366 spin_unlock_irqrestore(&port->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367}
1368
Alan Cox9492e132008-04-30 00:54:15 -07001369static void rc_set_termios(struct tty_struct *tty,
1370 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
Alan Coxc9f19e92009-01-02 13:47:26 +00001372 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
1376 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Jeff Garzikd9afa432008-02-06 01:36:11 -08001378 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 rc_change_speed(port_Board(port), port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001380 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
1382 if ((old_termios->c_cflag & CRTSCTS) &&
1383 !(tty->termios->c_cflag & CRTSCTS)) {
1384 tty->hw_stopped = 0;
1385 rc_start(tty);
1386 }
1387}
1388
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001389static const struct tty_operations riscom_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 .open = rc_open,
1391 .close = rc_close,
1392 .write = rc_write,
1393 .put_char = rc_put_char,
1394 .flush_chars = rc_flush_chars,
1395 .write_room = rc_write_room,
1396 .chars_in_buffer = rc_chars_in_buffer,
1397 .flush_buffer = rc_flush_buffer,
1398 .ioctl = rc_ioctl,
1399 .throttle = rc_throttle,
1400 .unthrottle = rc_unthrottle,
1401 .set_termios = rc_set_termios,
1402 .stop = rc_stop,
1403 .start = rc_start,
1404 .hangup = rc_hangup,
1405 .tiocmget = rc_tiocmget,
1406 .tiocmset = rc_tiocmset,
Alan Cox781cff52008-07-22 11:18:30 +01001407 .break_ctl = rc_send_break,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408};
1409
Alan Cox31f35932009-01-02 13:45:05 +00001410static const struct tty_port_operations riscom_port_ops = {
1411 .carrier_raised = carrier_raised,
1412};
1413
1414
Jiri Slaby1386a822008-02-07 00:16:36 -08001415static int __init rc_init_drivers(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416{
1417 int error;
1418 int i;
1419
1420 riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
Alan Cox9492e132008-04-30 00:54:15 -07001421 if (!riscom_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 return -ENOMEM;
Alan Cox9492e132008-04-30 00:54:15 -07001423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 riscom_driver->owner = THIS_MODULE;
1425 riscom_driver->name = "ttyL";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 riscom_driver->major = RISCOM8_NORMAL_MAJOR;
1427 riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
1428 riscom_driver->subtype = SERIAL_TYPE_NORMAL;
1429 riscom_driver->init_termios = tty_std_termios;
1430 riscom_driver->init_termios.c_cflag =
1431 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08001432 riscom_driver->init_termios.c_ispeed = 9600;
1433 riscom_driver->init_termios.c_ospeed = 9600;
Alan Cox781cff52008-07-22 11:18:30 +01001434 riscom_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 tty_set_operations(riscom_driver, &riscom_ops);
Alan Cox9492e132008-04-30 00:54:15 -07001436 error = tty_register_driver(riscom_driver);
1437 if (error != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 put_tty_driver(riscom_driver);
1439 printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
Alan Cox9492e132008-04-30 00:54:15 -07001440 "error = %d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 return 1;
1442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 memset(rc_port, 0, sizeof(rc_port));
1444 for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
Alan Cox85f8f812008-07-16 21:55:29 +01001445 tty_port_init(&rc_port[i].port);
Alan Cox31f35932009-01-02 13:45:05 +00001446 rc_port[i].port.ops = &riscom_port_ops;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001447 rc_port[i].magic = RISCOM8_MAGIC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 return 0;
1450}
1451
1452static void rc_release_drivers(void)
1453{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 tty_unregister_driver(riscom_driver);
1455 put_tty_driver(riscom_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456}
1457
1458#ifndef MODULE
1459/*
1460 * Called at boot time.
Alan Cox9492e132008-04-30 00:54:15 -07001461 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 * You can specify IO base for up to RC_NBOARD cards,
1463 * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
1464 * Note that there will be no probing at default
1465 * addresses in this case.
1466 *
Alan Cox9492e132008-04-30 00:54:15 -07001467 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468static int __init riscom8_setup(char *str)
1469{
1470 int ints[RC_NBOARD];
1471 int i;
1472
1473 str = get_options(str, ARRAY_SIZE(ints), ints);
1474
1475 for (i = 0; i < RC_NBOARD; i++) {
1476 if (i < ints[0])
1477 rc_board[i].base = ints[i+1];
Alan Cox9492e132008-04-30 00:54:15 -07001478 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 rc_board[i].base = 0;
1480 }
1481 return 1;
1482}
1483
1484__setup("riscom8=", riscom8_setup);
1485#endif
1486
1487static char banner[] __initdata =
1488 KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
1489 "1994-1996.\n";
1490static char no_boards_msg[] __initdata =
1491 KERN_INFO "rc: No RISCom/8 boards detected.\n";
1492
Alan Cox9492e132008-04-30 00:54:15 -07001493/*
1494 * This routine must be called by kernel at boot time
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 */
1496static int __init riscom8_init(void)
1497{
1498 int i;
1499 int found = 0;
1500
1501 printk(banner);
1502
Alan Cox9492e132008-04-30 00:54:15 -07001503 if (rc_init_drivers())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 return -EIO;
1505
Alan Cox9492e132008-04-30 00:54:15 -07001506 for (i = 0; i < RC_NBOARD; i++)
1507 if (rc_board[i].base && !rc_probe(&rc_board[i]))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 found++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 if (!found) {
1510 rc_release_drivers();
1511 printk(no_boards_msg);
1512 return -EIO;
1513 }
1514 return 0;
1515}
1516
1517#ifdef MODULE
1518static int iobase;
1519static int iobase1;
1520static int iobase2;
1521static int iobase3;
Rusty Russell8d3b33f2006-03-25 03:07:05 -08001522module_param(iobase, int, 0);
1523module_param(iobase1, int, 0);
1524module_param(iobase2, int, 0);
1525module_param(iobase3, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527MODULE_LICENSE("GPL");
Scott James Remnant5c9f5802009-04-06 17:33:26 +01001528MODULE_ALIAS_CHARDEV_MAJOR(RISCOM8_NORMAL_MAJOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529#endif /* MODULE */
1530
1531/*
1532 * You can setup up to 4 boards (current value of RC_NBOARD)
1533 * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
1534 *
1535 */
Alan Cox9492e132008-04-30 00:54:15 -07001536static int __init riscom8_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
1538#ifdef MODULE
1539 int i;
1540
1541 if (iobase || iobase1 || iobase2 || iobase3) {
Alan Cox9492e132008-04-30 00:54:15 -07001542 for (i = 0; i < RC_NBOARD; i++)
Jiri Slaby9efda792008-03-13 12:32:39 -07001543 rc_board[i].base = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 }
1545
1546 if (iobase)
1547 rc_board[0].base = iobase;
1548 if (iobase1)
1549 rc_board[1].base = iobase1;
1550 if (iobase2)
1551 rc_board[2].base = iobase2;
1552 if (iobase3)
1553 rc_board[3].base = iobase3;
1554#endif /* MODULE */
1555
1556 return riscom8_init();
1557}
Alan Cox9492e132008-04-30 00:54:15 -07001558
1559static void __exit riscom8_exit_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
1561 int i;
Alan Cox9492e132008-04-30 00:54:15 -07001562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 rc_release_drivers();
Alan Cox9492e132008-04-30 00:54:15 -07001564 for (i = 0; i < RC_NBOARD; i++)
1565 if (rc_board[i].flags & RC_BOARD_PRESENT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 rc_release_io_range(&rc_board[i]);
Alan Cox9492e132008-04-30 00:54:15 -07001567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568}
1569
1570module_init(riscom8_init_module);
1571module_exit(riscom8_exit_module);