blob: 171711acf5cd33736ebb74d69a6f02983b15bdb3 [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>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040050#include <linux/smp_lock.h>
Jeff Garzikd9afa432008-02-06 01:36:11 -080051#include <linux/spinlock.h>
Scott James Remnant5c9f5802009-04-06 17:33:26 +010052#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Alan Cox9492e132008-04-30 00:54:15 -070054#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56#include "riscom8.h"
57#include "riscom8_reg.h"
58
59/* Am I paranoid or not ? ;-) */
60#define RISCOM_PARANOIA_CHECK
61
Alan Cox9492e132008-04-30 00:54:15 -070062/*
63 * Crazy InteliCom/8 boards sometimes have swapped CTS & DSR signals.
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 * You can slightly speed up things by #undefing the following option,
Alan Cox9492e132008-04-30 00:54:15 -070065 * if you are REALLY sure that your board is correct one.
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 */
67
68#define RISCOM_BRAIN_DAMAGED_CTS
69
Alan Cox9492e132008-04-30 00:54:15 -070070/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 * The following defines are mostly for testing purposes. But if you need
72 * some nice reporting in your syslog, you can define them also.
73 */
74#undef RC_REPORT_FIFO
75#undef RC_REPORT_OVERRUN
76
77
78#define RISCOM_LEGAL_FLAGS \
79 (ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \
80 ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \
81 ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static struct tty_driver *riscom_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Jeff Garzikd9afa432008-02-06 01:36:11 -080085static DEFINE_SPINLOCK(riscom_lock);
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static struct riscom_board rc_board[RC_NBOARD] = {
88 {
89 .base = RC_IOBASE1,
90 },
91 {
92 .base = RC_IOBASE2,
93 },
94 {
95 .base = RC_IOBASE3,
96 },
97 {
98 .base = RC_IOBASE4,
99 },
100};
101
102static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
103
104/* RISCom/8 I/O ports addresses (without address translation) */
105static unsigned short rc_ioport[] = {
Tobias Klauserfe971072006-01-09 20:54:02 -0800106#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c,
Tobias Klauserfe971072006-01-09 20:54:02 -0800108#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, 0x10,
110 0x11, 0x12, 0x18, 0x28, 0x31, 0x32, 0x39, 0x3a, 0x40, 0x41, 0x61, 0x62,
111 0x63, 0x64, 0x6b, 0x70, 0x71, 0x78, 0x7a, 0x7b, 0x7f, 0x100, 0x101
Tobias Klauserfe971072006-01-09 20:54:02 -0800112#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
Tobias Klauserfe971072006-01-09 20:54:02 -0800114#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116
Alan Cox9492e132008-04-30 00:54:15 -0700117static int rc_paranoia_check(struct riscom_port const *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 char *name, const char *routine)
119{
120#ifdef RISCOM_PARANOIA_CHECK
121 static const char badmagic[] = KERN_INFO
122 "rc: Warning: bad riscom port magic number for device %s in %s\n";
123 static const char badinfo[] = KERN_INFO
124 "rc: Warning: null riscom port for device %s in %s\n";
125
126 if (!port) {
127 printk(badinfo, name, routine);
128 return 1;
129 }
130 if (port->magic != RISCOM8_MAGIC) {
131 printk(badmagic, name, routine);
132 return 1;
133 }
134#endif
135 return 0;
136}
137
138/*
Alan Cox9492e132008-04-30 00:54:15 -0700139 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 * Service functions for RISCom/8 driver.
Alan Cox9492e132008-04-30 00:54:15 -0700141 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 */
143
144/* Get board number from pointer */
Alan Cox9492e132008-04-30 00:54:15 -0700145static inline int board_No(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 return bp - rc_board;
148}
149
150/* Get port number from pointer */
Alan Cox9492e132008-04-30 00:54:15 -0700151static inline int port_No(struct riscom_port const *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
Alan Cox9492e132008-04-30 00:54:15 -0700153 return RC_PORT(port - rc_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154}
155
156/* Get pointer to board from pointer to port */
Alan Cox9492e132008-04-30 00:54:15 -0700157static inline struct riscom_board *port_Board(struct riscom_port const *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
159 return &rc_board[RC_BOARD(port - rc_port)];
160}
161
162/* Input Byte from CL CD180 register */
Alan Cox9492e132008-04-30 00:54:15 -0700163static inline unsigned char rc_in(struct riscom_board const *bp,
164 unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
166 return inb(bp->base + RC_TO_ISA(reg));
167}
168
169/* Output Byte to CL CD180 register */
Alan Cox9492e132008-04-30 00:54:15 -0700170static inline void rc_out(struct riscom_board const *bp, unsigned short reg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 unsigned char val)
172{
173 outb(val, bp->base + RC_TO_ISA(reg));
174}
175
176/* Wait for Channel Command Register ready */
Alan Cox9492e132008-04-30 00:54:15 -0700177static void rc_wait_CCR(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178{
179 unsigned long delay;
180
181 /* FIXME: need something more descriptive then 100000 :) */
Alan Cox9492e132008-04-30 00:54:15 -0700182 for (delay = 100000; delay; delay--)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 if (!rc_in(bp, CD180_CCR))
184 return;
Alan Cox9492e132008-04-30 00:54:15 -0700185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
187}
188
189/*
190 * RISCom/8 probe functions.
191 */
192
Alan Cox9492e132008-04-30 00:54:15 -0700193static int rc_request_io_range(struct riscom_board * const bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194{
195 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700196
197 for (i = 0; i < RC_NIOPORT; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
199 "RISCom/8")) {
200 goto out_release;
201 }
202 return 0;
203out_release:
204 printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
205 board_No(bp), bp->base);
Alan Cox9492e132008-04-30 00:54:15 -0700206 while (--i >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
208 return 1;
209}
210
Alan Cox9492e132008-04-30 00:54:15 -0700211static void rc_release_io_range(struct riscom_board * const bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
213 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700214
215 for (i = 0; i < RC_NIOPORT; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
217}
Alan Cox9492e132008-04-30 00:54:15 -0700218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219/* Reset and setup CD180 chip */
Alan Cox9492e132008-04-30 00:54:15 -0700220static void __init rc_init_CD180(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
222 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700223
Jeff Garzikd9afa432008-02-06 01:36:11 -0800224 spin_lock_irqsave(&riscom_lock, flags);
225
Alan Cox9492e132008-04-30 00:54:15 -0700226 rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
227 rc_wait_CCR(bp); /* Wait for CCR ready */
228 rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800229 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -0700230 msleep(50); /* Delay 0.05 sec */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800231 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -0700232 rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
233 rc_out(bp, CD180_GICR, 0); /* Clear all bits */
234 rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
235 rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for tx intr */
236 rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for rx intr */
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 /* Setting up prescaler. We need 4 ticks per 1 ms */
239 rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
240 rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
Alan Cox9492e132008-04-30 00:54:15 -0700241
Jeff Garzikd9afa432008-02-06 01:36:11 -0800242 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245/* Main probing routine, also sets irq. */
246static int __init rc_probe(struct riscom_board *bp)
247{
248 unsigned char val1, val2;
249 int irqs = 0;
250 int retries;
Alan Cox9492e132008-04-30 00:54:15 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 bp->irq = 0;
253
254 if (rc_request_io_range(bp))
255 return 1;
Alan Cox9492e132008-04-30 00:54:15 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* Are the I/O ports here ? */
258 rc_out(bp, CD180_PPRL, 0x5a);
259 outb(0xff, 0x80);
260 val1 = rc_in(bp, CD180_PPRL);
261 rc_out(bp, CD180_PPRL, 0xa5);
262 outb(0x00, 0x80);
263 val2 = rc_in(bp, CD180_PPRL);
Alan Cox9492e132008-04-30 00:54:15 -0700264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 if ((val1 != 0x5a) || (val2 != 0xa5)) {
266 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
267 board_No(bp), bp->base);
268 goto out_release;
269 }
Alan Cox9492e132008-04-30 00:54:15 -0700270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /* It's time to find IRQ for this board */
Alan Cox9492e132008-04-30 00:54:15 -0700272 for (retries = 0; retries < 5 && irqs <= 0; retries++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 irqs = probe_irq_on();
Alan Cox9492e132008-04-30 00:54:15 -0700274 rc_init_CD180(bp); /* Reset CD180 chip */
275 rc_out(bp, CD180_CAR, 2); /* Select port 2 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 rc_wait_CCR(bp);
Alan Cox9492e132008-04-30 00:54:15 -0700277 rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
278 rc_out(bp, CD180_IER, IER_TXRDY);/* Enable tx empty intr */
Jiri Slabyc4ebd922007-07-17 04:05:20 -0700279 msleep(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 irqs = probe_irq_off(irqs);
Alan Cox9492e132008-04-30 00:54:15 -0700281 val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
282 val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
283 rc_init_CD180(bp); /* Reset CD180 again */
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
286 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
287 "found.\n", board_No(bp), bp->base);
288 goto out_release;
289 }
290 }
Alan Cox9492e132008-04-30 00:54:15 -0700291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if (irqs <= 0) {
293 printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
294 "at 0x%03x.\n", board_No(bp), bp->base);
295 goto out_release;
296 }
297 bp->irq = irqs;
298 bp->flags |= RC_BOARD_PRESENT;
Alan Cox9492e132008-04-30 00:54:15 -0700299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
301 "0x%03x, IRQ %d.\n",
302 board_No(bp),
303 (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
304 bp->base, bp->irq);
Alan Cox9492e132008-04-30 00:54:15 -0700305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 return 0;
307out_release:
308 rc_release_io_range(bp);
309 return 1;
310}
311
Alan Cox9492e132008-04-30 00:54:15 -0700312/*
313 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 * Interrupt processing routines.
Alan Cox9492e132008-04-30 00:54:15 -0700315 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 */
317
Alan Cox9492e132008-04-30 00:54:15 -0700318static struct riscom_port *rc_get_port(struct riscom_board const *bp,
319 unsigned char const *what)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 unsigned char channel;
Alan Cox9492e132008-04-30 00:54:15 -0700322 struct riscom_port *port;
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
325 if (channel < CD180_NCH) {
326 port = &rc_port[board_No(bp) * RC_NPORT + channel];
Alan Cox85f8f812008-07-16 21:55:29 +0100327 if (port->port.flags & ASYNC_INITIALIZED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 return port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
Alan Cox9492e132008-04-30 00:54:15 -0700330 printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 board_No(bp), what, channel);
332 return NULL;
333}
334
Alan Cox9492e132008-04-30 00:54:15 -0700335static void rc_receive_exc(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
337 struct riscom_port *port;
338 struct tty_struct *tty;
339 unsigned char status;
Alan Cox33f0f882006-01-09 20:54:13 -0800340 unsigned char ch, flag;
Alan Cox9492e132008-04-30 00:54:15 -0700341
342 port = rc_get_port(bp, "Receive");
343 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return;
345
Alan Cox85f8f812008-07-16 21:55:29 +0100346 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700347
348#ifdef RC_REPORT_OVERRUN
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 status = rc_in(bp, CD180_RCSR);
Alan Cox33f0f882006-01-09 20:54:13 -0800350 if (status & RCSR_OE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 port->overrun++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 status &= port->mark_mask;
Alan Cox9492e132008-04-30 00:54:15 -0700353#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 status = rc_in(bp, CD180_RCSR) & port->mark_mask;
Alan Cox9492e132008-04-30 00:54:15 -0700355#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 ch = rc_in(bp, CD180_RDR);
Alan Cox9492e132008-04-30 00:54:15 -0700357 if (!status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if (status & RCSR_TOUT) {
360 printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
Alan Cox9492e132008-04-30 00:54:15 -0700361 "Hardware problems ?\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 board_No(bp), port_No(port));
363 return;
Alan Cox9492e132008-04-30 00:54:15 -0700364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 } else if (status & RCSR_BREAK) {
366 printk(KERN_INFO "rc%d: port %d: Handling break...\n",
367 board_No(bp), port_No(port));
Alan Cox33f0f882006-01-09 20:54:13 -0800368 flag = TTY_BREAK;
Alan Cox85f8f812008-07-16 21:55:29 +0100369 if (port->port.flags & ASYNC_SAK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 do_SAK(tty);
Alan Cox9492e132008-04-30 00:54:15 -0700371
372 } else if (status & RCSR_PE)
Alan Cox33f0f882006-01-09 20:54:13 -0800373 flag = TTY_PARITY;
Alan Cox9492e132008-04-30 00:54:15 -0700374
375 else if (status & RCSR_FE)
Alan Cox33f0f882006-01-09 20:54:13 -0800376 flag = TTY_FRAME;
Alan Cox9492e132008-04-30 00:54:15 -0700377
378 else if (status & RCSR_OE)
Alan Cox33f0f882006-01-09 20:54:13 -0800379 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 else
Alan Cox33f0f882006-01-09 20:54:13 -0800381 flag = TTY_NORMAL;
Alan Cox9492e132008-04-30 00:54:15 -0700382
Alan Cox33f0f882006-01-09 20:54:13 -0800383 tty_insert_flip_char(tty, ch, flag);
384 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Alan Cox9492e132008-04-30 00:54:15 -0700387static void rc_receive(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
389 struct riscom_port *port;
390 struct tty_struct *tty;
391 unsigned char count;
Alan Cox9492e132008-04-30 00:54:15 -0700392
393 port = rc_get_port(bp, "Receive");
394 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return;
Alan Cox9492e132008-04-30 00:54:15 -0700396
Alan Cox85f8f812008-07-16 21:55:29 +0100397 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 count = rc_in(bp, CD180_RDCR);
Alan Cox9492e132008-04-30 00:54:15 -0700400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401#ifdef RC_REPORT_FIFO
402 port->hits[count > 8 ? 9 : count]++;
Alan Cox9492e132008-04-30 00:54:15 -0700403#endif
404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 while (count--) {
Alan Cox33f0f882006-01-09 20:54:13 -0800406 if (tty_buffer_request_room(tty, 1) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 printk(KERN_WARNING "rc%d: port %d: Working around "
408 "flip buffer overflow.\n",
409 board_No(bp), port_No(port));
410 break;
411 }
Alan Cox33f0f882006-01-09 20:54:13 -0800412 tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 }
Alan Cox33f0f882006-01-09 20:54:13 -0800414 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
Alan Cox9492e132008-04-30 00:54:15 -0700417static void rc_transmit(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
419 struct riscom_port *port;
420 struct tty_struct *tty;
421 unsigned char count;
Alan Cox9492e132008-04-30 00:54:15 -0700422
423 port = rc_get_port(bp, "Transmit");
424 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return;
Alan Cox9492e132008-04-30 00:54:15 -0700426
Alan Cox85f8f812008-07-16 21:55:29 +0100427 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700428
429 if (port->IER & IER_TXEMPTY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* FIFO drained */
431 rc_out(bp, CD180_CAR, port_No(port));
432 port->IER &= ~IER_TXEMPTY;
433 rc_out(bp, CD180_IER, port->IER);
434 return;
435 }
Alan Cox9492e132008-04-30 00:54:15 -0700436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if ((port->xmit_cnt <= 0 && !port->break_length)
438 || tty->stopped || tty->hw_stopped) {
439 rc_out(bp, CD180_CAR, port_No(port));
440 port->IER &= ~IER_TXRDY;
441 rc_out(bp, CD180_IER, port->IER);
442 return;
443 }
Alan Cox9492e132008-04-30 00:54:15 -0700444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 if (port->break_length) {
446 if (port->break_length > 0) {
447 if (port->COR2 & COR2_ETC) {
448 rc_out(bp, CD180_TDR, CD180_C_ESC);
449 rc_out(bp, CD180_TDR, CD180_C_SBRK);
450 port->COR2 &= ~COR2_ETC;
451 }
452 count = min_t(int, port->break_length, 0xff);
453 rc_out(bp, CD180_TDR, CD180_C_ESC);
454 rc_out(bp, CD180_TDR, CD180_C_DELAY);
455 rc_out(bp, CD180_TDR, count);
Alan Cox9492e132008-04-30 00:54:15 -0700456 port->break_length -= count;
457 if (port->break_length == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 port->break_length--;
459 } else {
460 rc_out(bp, CD180_TDR, CD180_C_ESC);
461 rc_out(bp, CD180_TDR, CD180_C_EBRK);
462 rc_out(bp, CD180_COR2, port->COR2);
463 rc_wait_CCR(bp);
464 rc_out(bp, CD180_CCR, CCR_CORCHG2);
465 port->break_length = 0;
466 }
467 return;
468 }
Alan Cox9492e132008-04-30 00:54:15 -0700469
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 count = CD180_NFIFO;
471 do {
Alan Cox85f8f812008-07-16 21:55:29 +0100472 rc_out(bp, CD180_TDR, port->port.xmit_buf[port->xmit_tail++]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
474 if (--port->xmit_cnt <= 0)
475 break;
476 } while (--count > 0);
Alan Cox9492e132008-04-30 00:54:15 -0700477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (port->xmit_cnt <= 0) {
479 rc_out(bp, CD180_CAR, port_No(port));
480 port->IER &= ~IER_TXRDY;
481 rc_out(bp, CD180_IER, port->IER);
482 }
483 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800484 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
Alan Cox9492e132008-04-30 00:54:15 -0700487static void rc_check_modem(struct riscom_board const *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
489 struct riscom_port *port;
490 struct tty_struct *tty;
491 unsigned char mcr;
Alan Cox9492e132008-04-30 00:54:15 -0700492
493 port = rc_get_port(bp, "Modem");
494 if (port == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return;
Alan Cox9492e132008-04-30 00:54:15 -0700496
Alan Cox85f8f812008-07-16 21:55:29 +0100497 tty = port->port.tty;
Alan Cox9492e132008-04-30 00:54:15 -0700498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 mcr = rc_in(bp, CD180_MCR);
Alan Cox9492e132008-04-30 00:54:15 -0700500 if (mcr & MCR_CDCHG) {
501 if (rc_in(bp, CD180_MSVR) & MSVR_CD)
Alan Cox85f8f812008-07-16 21:55:29 +0100502 wake_up_interruptible(&port->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 else
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800504 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
Alan Cox9492e132008-04-30 00:54:15 -0700506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507#ifdef RISCOM_BRAIN_DAMAGED_CTS
508 if (mcr & MCR_CTSCHG) {
509 if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
510 tty->hw_stopped = 0;
511 port->IER |= IER_TXRDY;
512 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800513 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 } else {
515 tty->hw_stopped = 1;
516 port->IER &= ~IER_TXRDY;
517 }
518 rc_out(bp, CD180_IER, port->IER);
519 }
520 if (mcr & MCR_DSRCHG) {
521 if (rc_in(bp, CD180_MSVR) & MSVR_DSR) {
522 tty->hw_stopped = 0;
523 port->IER |= IER_TXRDY;
524 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800525 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 } else {
527 tty->hw_stopped = 1;
528 port->IER &= ~IER_TXRDY;
529 }
530 rc_out(bp, CD180_IER, port->IER);
531 }
532#endif /* RISCOM_BRAIN_DAMAGED_CTS */
Alan Cox9492e132008-04-30 00:54:15 -0700533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 /* Clear change bits */
535 rc_out(bp, CD180_MCR, 0);
536}
537
538/* The main interrupt processing routine */
Alan Cox9492e132008-04-30 00:54:15 -0700539static irqreturn_t rc_interrupt(int dummy, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 unsigned char status;
542 unsigned char ack;
Jeff Garzikf07ef392007-10-23 19:12:11 -0400543 struct riscom_board *bp = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 unsigned long loop = 0;
545 int handled = 0;
546
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400547 if (!(bp->flags & RC_BOARD_ACTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 return IRQ_NONE;
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
551 (RC_BSR_TOUT | RC_BSR_TINT |
552 RC_BSR_MINT | RC_BSR_RINT))) {
553 handled = 1;
Alan Cox9492e132008-04-30 00:54:15 -0700554 if (status & RC_BSR_TOUT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 printk(KERN_WARNING "rc%d: Got timeout. Hardware "
556 "error?\n", board_No(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 else if (status & RC_BSR_RINT) {
558 ack = rc_in(bp, RC_ACK_RINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (ack == (RC_ID | GIVR_IT_RCV))
560 rc_receive(bp);
561 else if (ack == (RC_ID | GIVR_IT_REXC))
562 rc_receive_exc(bp);
563 else
564 printk(KERN_WARNING "rc%d: Bad receive ack "
565 "0x%02x.\n",
566 board_No(bp), ack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 } else if (status & RC_BSR_TINT) {
568 ack = rc_in(bp, RC_ACK_TINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (ack == (RC_ID | GIVR_IT_TX))
570 rc_transmit(bp);
571 else
572 printk(KERN_WARNING "rc%d: Bad transmit ack "
573 "0x%02x.\n",
574 board_No(bp), ack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 } else /* if (status & RC_BSR_MINT) */ {
576 ack = rc_in(bp, RC_ACK_MINT);
Alan Cox9492e132008-04-30 00:54:15 -0700577 if (ack == (RC_ID | GIVR_IT_MODEM))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 rc_check_modem(bp);
579 else
580 printk(KERN_WARNING "rc%d: Bad modem ack "
581 "0x%02x.\n",
582 board_No(bp), ack);
Alan Cox9492e132008-04-30 00:54:15 -0700583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
585 rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
586 }
587 return IRQ_RETVAL(handled);
588}
589
590/*
591 * Routines for open & close processing.
592 */
593
594/* Called with disabled interrupts */
Alan Cox9492e132008-04-30 00:54:15 -0700595static int rc_setup_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 int error;
598
Alan Cox9492e132008-04-30 00:54:15 -0700599 if (bp->flags & RC_BOARD_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700601
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700602 error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
Jeff Garzikf07ef392007-10-23 19:12:11 -0400603 "RISCom/8", bp);
Alan Cox9492e132008-04-30 00:54:15 -0700604 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 return error;
Alan Cox9492e132008-04-30 00:54:15 -0700606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 rc_out(bp, RC_CTOUT, 0); /* Just in case */
608 bp->DTR = ~0;
609 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
Alan Cox9492e132008-04-30 00:54:15 -0700610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 bp->flags |= RC_BOARD_ACTIVE;
Alan Cox9492e132008-04-30 00:54:15 -0700612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
614}
615
616/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400617static void rc_shutdown_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 if (!(bp->flags & RC_BOARD_ACTIVE))
620 return;
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 free_irq(bp->irq, NULL);
Alan Cox9492e132008-04-30 00:54:15 -0700625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 bp->DTR = ~0;
627 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
Alan Cox9492e132008-04-30 00:54:15 -0700628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630
631/*
Alan Cox9492e132008-04-30 00:54:15 -0700632 * Setting up port characteristics.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 * Must be called with disabled interrupts
634 */
635static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
636{
Alan Cox85f8f812008-07-16 21:55:29 +0100637 struct tty_struct *tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 unsigned long baud;
639 long tmp;
640 unsigned char cor1 = 0, cor3 = 0;
641 unsigned char mcor1 = 0, mcor2 = 0;
Alan Cox9492e132008-04-30 00:54:15 -0700642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 port->IER = 0;
644 port->COR2 = 0;
645 port->MSVR = MSVR_RTS;
Alan Cox9492e132008-04-30 00:54:15 -0700646
Alan Coxc7bce302006-09-30 23:27:24 -0700647 baud = tty_get_baud_rate(tty);
Alan Cox9492e132008-04-30 00:54:15 -0700648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 /* Select port on the board */
650 rc_out(bp, CD180_CAR, port_No(port));
Alan Cox9492e132008-04-30 00:54:15 -0700651
Alan Coxc7bce302006-09-30 23:27:24 -0700652 if (!baud) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 /* Drop DTR & exit */
654 bp->DTR |= (1u << port_No(port));
655 rc_out(bp, RC_DTR, bp->DTR);
656 return;
657 } else {
658 /* Set DTR on */
659 bp->DTR &= ~(1u << port_No(port));
660 rc_out(bp, RC_DTR, bp->DTR);
661 }
Alan Cox9492e132008-04-30 00:54:15 -0700662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 /*
Alan Cox9492e132008-04-30 00:54:15 -0700664 * Now we must calculate some speed depended things
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 */
Alan Cox9492e132008-04-30 00:54:15 -0700666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 /* Set baud rate for port */
Alan Coxc7bce302006-09-30 23:27:24 -0700668 tmp = (((RC_OSCFREQ + baud/2) / baud +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 CD180_TPC/2) / CD180_TPC);
670
Alan Cox9492e132008-04-30 00:54:15 -0700671 rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
672 rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
673 rc_out(bp, CD180_RBPRL, tmp & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 rc_out(bp, CD180_TBPRL, tmp & 0xff);
Alan Cox9492e132008-04-30 00:54:15 -0700675
Alan Coxc7bce302006-09-30 23:27:24 -0700676 baud = (baud + 5) / 10; /* Estimated CPS */
Alan Cox9492e132008-04-30 00:54:15 -0700677
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 /* Two timer ticks seems enough to wakeup something like SLIP driver */
Alan Cox9492e132008-04-30 00:54:15 -0700679 tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
681 SERIAL_XMIT_SIZE - 1 : tmp);
Alan Cox9492e132008-04-30 00:54:15 -0700682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 /* Receiver timeout will be transmission time for 1.5 chars */
684 tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
685 tmp = (tmp > 0xff) ? 0xff : tmp;
686 rc_out(bp, CD180_RTPR, tmp);
Alan Cox9492e132008-04-30 00:54:15 -0700687
688 switch (C_CSIZE(tty)) {
689 case CS5:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 cor1 |= COR1_5BITS;
691 break;
Alan Cox9492e132008-04-30 00:54:15 -0700692 case CS6:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 cor1 |= COR1_6BITS;
694 break;
Alan Cox9492e132008-04-30 00:54:15 -0700695 case CS7:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 cor1 |= COR1_7BITS;
697 break;
Alan Cox9492e132008-04-30 00:54:15 -0700698 case CS8:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 cor1 |= COR1_8BITS;
700 break;
701 }
Alan Cox9492e132008-04-30 00:54:15 -0700702 if (C_CSTOPB(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 cor1 |= COR1_2SB;
Alan Cox9492e132008-04-30 00:54:15 -0700704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 cor1 |= COR1_IGNORE;
Alan Cox9492e132008-04-30 00:54:15 -0700706 if (C_PARENB(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 cor1 |= COR1_NORMPAR;
Alan Cox9492e132008-04-30 00:54:15 -0700708 if (C_PARODD(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 cor1 |= COR1_ODDP;
Alan Cox9492e132008-04-30 00:54:15 -0700710 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 cor1 &= ~COR1_IGNORE;
712 }
713 /* Set marking of some errors */
714 port->mark_mask = RCSR_OE | RCSR_TOUT;
Alan Cox9492e132008-04-30 00:54:15 -0700715 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 port->mark_mask |= RCSR_FE | RCSR_PE;
Alan Cox9492e132008-04-30 00:54:15 -0700717 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 port->mark_mask |= RCSR_BREAK;
Alan Cox9492e132008-04-30 00:54:15 -0700719 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
Alan Cox9492e132008-04-30 00:54:15 -0700721 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 port->mark_mask &= ~RCSR_BREAK;
Alan Cox9492e132008-04-30 00:54:15 -0700723 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 /* Real raw mode. Ignore all */
725 port->mark_mask &= ~RCSR_OE;
726 }
727 /* Enable Hardware Flow Control */
728 if (C_CRTSCTS(tty)) {
729#ifdef RISCOM_BRAIN_DAMAGED_CTS
730 port->IER |= IER_DSR | IER_CTS;
731 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
732 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
Alan Cox9492e132008-04-30 00:54:15 -0700733 tty->hw_stopped = !(rc_in(bp, CD180_MSVR) &
734 (MSVR_CTS|MSVR_DSR));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735#else
736 port->COR2 |= COR2_CTSAE;
737#endif
738 }
739 /* Enable Software Flow Control. FIXME: I'm not sure about this */
740 /* Some people reported that it works, but I still doubt */
741 if (I_IXON(tty)) {
742 port->COR2 |= COR2_TXIBE;
743 cor3 |= (COR3_FCT | COR3_SCDE);
744 if (I_IXANY(tty))
745 port->COR2 |= COR2_IXM;
746 rc_out(bp, CD180_SCHR1, START_CHAR(tty));
747 rc_out(bp, CD180_SCHR2, STOP_CHAR(tty));
748 rc_out(bp, CD180_SCHR3, START_CHAR(tty));
749 rc_out(bp, CD180_SCHR4, STOP_CHAR(tty));
750 }
751 if (!C_CLOCAL(tty)) {
752 /* Enable CD check */
753 port->IER |= IER_CD;
754 mcor1 |= MCOR1_CDZD;
755 mcor2 |= MCOR2_CDOD;
756 }
Alan Cox9492e132008-04-30 00:54:15 -0700757
758 if (C_CREAD(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 /* Enable receiver */
760 port->IER |= IER_RXD;
Alan Cox9492e132008-04-30 00:54:15 -0700761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 /* Set input FIFO size (1-8 bytes) */
Alan Cox9492e132008-04-30 00:54:15 -0700763 cor3 |= RISCOM_RXFIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 /* Setting up CD180 channel registers */
765 rc_out(bp, CD180_COR1, cor1);
766 rc_out(bp, CD180_COR2, port->COR2);
767 rc_out(bp, CD180_COR3, cor3);
768 /* Make CD180 know about registers change */
769 rc_wait_CCR(bp);
770 rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
771 /* Setting up modem option registers */
772 rc_out(bp, CD180_MCOR1, mcor1);
773 rc_out(bp, CD180_MCOR2, mcor2);
774 /* Enable CD180 transmitter & receiver */
775 rc_wait_CCR(bp);
776 rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
777 /* Enable interrupts */
778 rc_out(bp, CD180_IER, port->IER);
779 /* And finally set RTS on */
780 rc_out(bp, CD180_MSVR, port->MSVR);
781}
782
783/* Must be called with interrupts enabled */
784static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
785{
786 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700787
Alan Cox85f8f812008-07-16 21:55:29 +0100788 if (port->port.flags & ASYNC_INITIALIZED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700790
Alan Cox85f8f812008-07-16 21:55:29 +0100791 if (tty_port_alloc_xmit_buf(&port->port) < 0)
792 return -ENOMEM;
793
Jeff Garzikd9afa432008-02-06 01:36:11 -0800794 spin_lock_irqsave(&riscom_lock, flags);
795
Alan Coxd99101f2008-07-16 21:55:37 +0100796 clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
Alan Cox85f8f812008-07-16 21:55:29 +0100797 if (port->port.count == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 bp->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
800 rc_change_speed(bp, port);
Alan Cox85f8f812008-07-16 21:55:29 +0100801 port->port.flags |= ASYNC_INITIALIZED;
Alan Cox9492e132008-04-30 00:54:15 -0700802
Jeff Garzikd9afa432008-02-06 01:36:11 -0800803 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return 0;
805}
806
807/* Must be called with interrupts disabled */
Alan Coxd99101f2008-07-16 21:55:37 +0100808static void rc_shutdown_port(struct tty_struct *tty,
809 struct riscom_board *bp, struct riscom_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
Alan Cox85f8f812008-07-16 21:55:29 +0100811 if (!(port->port.flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 return;
Alan Cox9492e132008-04-30 00:54:15 -0700813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814#ifdef RC_REPORT_OVERRUN
815 printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
816 board_No(bp), port_No(port), port->overrun);
Alan Cox9492e132008-04-30 00:54:15 -0700817#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818#ifdef RC_REPORT_FIFO
819 {
820 int i;
Alan Cox9492e132008-04-30 00:54:15 -0700821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
823 board_No(bp), port_No(port));
Alan Cox9492e132008-04-30 00:54:15 -0700824 for (i = 0; i < 10; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 printk("%ld ", port->hits[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 printk("].\n");
827 }
Alan Cox9492e132008-04-30 00:54:15 -0700828#endif
Alan Cox85f8f812008-07-16 21:55:29 +0100829 tty_port_free_xmit_buf(&port->port);
Alan Coxd99101f2008-07-16 21:55:37 +0100830 if (C_HUPCL(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 /* Drop DTR */
832 bp->DTR |= (1u << port_No(port));
833 rc_out(bp, RC_DTR, bp->DTR);
834 }
Alan Cox9492e132008-04-30 00:54:15 -0700835
836 /* Select port */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 rc_out(bp, CD180_CAR, port_No(port));
838 /* Reset port */
839 rc_wait_CCR(bp);
840 rc_out(bp, CD180_CCR, CCR_SOFTRESET);
841 /* Disable all interrupts from this port */
842 port->IER = 0;
843 rc_out(bp, CD180_IER, port->IER);
Alan Cox9492e132008-04-30 00:54:15 -0700844
Alan Coxd99101f2008-07-16 21:55:37 +0100845 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox85f8f812008-07-16 21:55:29 +0100846 port->port.flags &= ~ASYNC_INITIALIZED;
Alan Cox9492e132008-04-30 00:54:15 -0700847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (--bp->count < 0) {
849 printk(KERN_INFO "rc%d: rc_shutdown_port: "
850 "bad board count: %d\n",
851 board_No(bp), bp->count);
852 bp->count = 0;
853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 /*
855 * If this is the last opened port on the board
856 * shutdown whole board
857 */
Alan Cox9492e132008-04-30 00:54:15 -0700858 if (!bp->count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 rc_shutdown_board(bp);
860}
861
Alan Cox31f35932009-01-02 13:45:05 +0000862static int carrier_raised(struct tty_port *port)
863{
864 struct riscom_port *p = container_of(port, struct riscom_port, port);
865 struct riscom_board *bp = port_Board(p);
866 unsigned long flags;
867 int CD;
868
869 spin_lock_irqsave(&riscom_lock, flags);
870 rc_out(bp, CD180_CAR, port_No(p));
871 CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
872 rc_out(bp, CD180_MSVR, MSVR_RTS);
873 bp->DTR &= ~(1u << port_No(p));
874 rc_out(bp, RC_DTR, bp->DTR);
875 spin_unlock_irqrestore(&riscom_lock, flags);
876 return CD;
877}
878
Alan Cox9492e132008-04-30 00:54:15 -0700879static int rc_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
881 int board;
882 int error;
Alan Cox9492e132008-04-30 00:54:15 -0700883 struct riscom_port *port;
884 struct riscom_board *bp;
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 board = RC_BOARD(tty->index);
887 if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
888 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -0700889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 bp = &rc_board[board];
891 port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
892 if (rc_paranoia_check(port, tty->name, "rc_open"))
893 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -0700894
895 error = rc_setup_board(bp);
896 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return error;
Alan Cox9492e132008-04-30 00:54:15 -0700898
Alan Cox85f8f812008-07-16 21:55:29 +0100899 port->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 tty->driver_data = port;
Alan Cox85f8f812008-07-16 21:55:29 +0100901 port->port.tty = tty;
Alan Cox9492e132008-04-30 00:54:15 -0700902
903 error = rc_setup_port(bp, port);
904 if (error == 0)
Alan Cox36c621d2009-01-02 13:46:10 +0000905 error = tty_port_block_til_ready(&port->port, tty, filp);
Alan Cox9492e132008-04-30 00:54:15 -0700906 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908
Alan Cox978e5952008-04-30 00:53:59 -0700909static void rc_flush_buffer(struct tty_struct *tty)
910{
Alan Coxc9f19e92009-01-02 13:47:26 +0000911 struct riscom_port *port = tty->driver_data;
Alan Cox978e5952008-04-30 00:53:59 -0700912 unsigned long flags;
913
914 if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
915 return;
916
917 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox978e5952008-04-30 00:53:59 -0700918 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
Alan Cox978e5952008-04-30 00:53:59 -0700919 spin_unlock_irqrestore(&riscom_lock, flags);
920
921 tty_wakeup(tty);
922}
923
Alan Cox9492e132008-04-30 00:54:15 -0700924static void rc_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Alan Coxc9f19e92009-01-02 13:47:26 +0000926 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 struct riscom_board *bp;
928 unsigned long flags;
929 unsigned long timeout;
Alan Cox9492e132008-04-30 00:54:15 -0700930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if (!port || rc_paranoia_check(port, tty->name, "close"))
932 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 bp = port_Board(port);
Alan Coxa6614992009-01-02 13:46:50 +0000935
936 if (tty_port_close_start(&port->port, tty, filp) == 0)
937 return;
938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /*
940 * At this point we stop accepting input. To do this, we
941 * disable the receive line status interrupts, and tell the
942 * interrupt driver to stop checking the data ready bit in the
943 * line status register.
944 */
Alan Coxc2ba38c2009-01-02 13:45:50 +0000945
946 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 port->IER &= ~IER_RXD;
Alan Cox85f8f812008-07-16 21:55:29 +0100948 if (port->port.flags & ASYNC_INITIALIZED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 port->IER &= ~IER_TXRDY;
950 port->IER |= IER_TXEMPTY;
951 rc_out(bp, CD180_CAR, port_No(port));
952 rc_out(bp, CD180_IER, port->IER);
953 /*
954 * Before we drop DTR, make sure the UART transmitter
955 * has completely drained; this is especially
956 * important if there is a transmit FIFO!
957 */
Alan Cox9492e132008-04-30 00:54:15 -0700958 timeout = jiffies + HZ;
959 while (port->IER & IER_TXEMPTY) {
Alan Coxc2ba38c2009-01-02 13:45:50 +0000960 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 msleep_interruptible(jiffies_to_msecs(port->timeout));
Alan Coxc2ba38c2009-01-02 13:45:50 +0000962 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 if (time_after(jiffies, timeout))
964 break;
965 }
966 }
Alan Coxd99101f2008-07-16 21:55:37 +0100967 rc_shutdown_port(tty, bp, port);
Alan Cox978e5952008-04-30 00:53:59 -0700968 rc_flush_buffer(tty);
Alan Coxc2ba38c2009-01-02 13:45:50 +0000969 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Alan Coxa6614992009-01-02 13:46:50 +0000971 tty_port_close_end(&port->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972}
973
Alan Cox9492e132008-04-30 00:54:15 -0700974static int rc_write(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 const unsigned char *buf, int count)
976{
Alan Coxc9f19e92009-01-02 13:47:26 +0000977 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 struct riscom_board *bp;
979 int c, total = 0;
980 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (rc_paranoia_check(port, tty->name, "rc_write"))
983 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 bp = port_Board(port);
986
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -0800988 spin_lock_irqsave(&riscom_lock, flags);
989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
991 SERIAL_XMIT_SIZE - port->xmit_head));
Jeff Garzikd9afa432008-02-06 01:36:11 -0800992 if (c <= 0)
993 break; /* lock continues to be held */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Alan Cox85f8f812008-07-16 21:55:29 +0100995 memcpy(port->port.xmit_buf + port->xmit_head, buf, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
997 port->xmit_cnt += c;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800998
999 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001 buf += c;
1002 count -= c;
1003 total += c;
1004 }
1005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1007 !(port->IER & IER_TXRDY)) {
1008 port->IER |= IER_TXRDY;
1009 rc_out(bp, CD180_CAR, port_No(port));
1010 rc_out(bp, CD180_IER, port->IER);
1011 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001012
1013 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 return total;
1016}
1017
Alan Cox9492e132008-04-30 00:54:15 -07001018static int rc_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
Alan Coxc9f19e92009-01-02 13:47:26 +00001020 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 unsigned long flags;
Alan Coxbbbbb962008-04-30 00:54:05 -07001022 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 if (rc_paranoia_check(port, tty->name, "rc_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001025 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Jeff Garzikd9afa432008-02-06 01:36:11 -08001027 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -07001028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
1030 goto out;
1031
Alan Cox85f8f812008-07-16 21:55:29 +01001032 port->port.xmit_buf[port->xmit_head++] = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1034 port->xmit_cnt++;
Alan Coxbbbbb962008-04-30 00:54:05 -07001035 ret = 1;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001036
1037out:
1038 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxbbbbb962008-04-30 00:54:05 -07001039 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040}
1041
Alan Cox9492e132008-04-30 00:54:15 -07001042static void rc_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
Alan Coxc9f19e92009-01-02 13:47:26 +00001044 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
1048 return;
Alan Cox9492e132008-04-30 00:54:15 -07001049
Alan Coxd99101f2008-07-16 21:55:37 +01001050 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 return;
1052
Jeff Garzikd9afa432008-02-06 01:36:11 -08001053 spin_lock_irqsave(&riscom_lock, flags);
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 port->IER |= IER_TXRDY;
1056 rc_out(port_Board(port), CD180_CAR, port_No(port));
1057 rc_out(port_Board(port), CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001058
1059 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060}
1061
Alan Cox9492e132008-04-30 00:54:15 -07001062static int rc_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063{
Alan Coxc9f19e92009-01-02 13:47:26 +00001064 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 int ret;
Alan Cox9492e132008-04-30 00:54:15 -07001066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 if (rc_paranoia_check(port, tty->name, "rc_write_room"))
1068 return 0;
1069
1070 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1071 if (ret < 0)
1072 ret = 0;
1073 return ret;
1074}
1075
1076static int rc_chars_in_buffer(struct tty_struct *tty)
1077{
Alan Coxc9f19e92009-01-02 13:47:26 +00001078 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001079
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
1081 return 0;
Alan Cox9492e132008-04-30 00:54:15 -07001082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return port->xmit_cnt;
1084}
1085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086static int rc_tiocmget(struct tty_struct *tty, struct file *file)
1087{
Alan Coxc9f19e92009-01-02 13:47:26 +00001088 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001089 struct riscom_board *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 unsigned char status;
1091 unsigned int result;
1092 unsigned long flags;
1093
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001094 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return -ENODEV;
1096
1097 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001098
1099 spin_lock_irqsave(&riscom_lock, flags);
1100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 rc_out(bp, CD180_CAR, port_No(port));
1102 status = rc_in(bp, CD180_MSVR);
1103 result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001104
1105 spin_unlock_irqrestore(&riscom_lock, flags);
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
1108 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1109 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
1110 | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
1111 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1112 return result;
1113}
1114
1115static int rc_tiocmset(struct tty_struct *tty, struct file *file,
1116 unsigned int set, unsigned int clear)
1117{
Alan Coxc9f19e92009-01-02 13:47:26 +00001118 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 unsigned long flags;
1120 struct riscom_board *bp;
1121
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001122 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 return -ENODEV;
1124
1125 bp = port_Board(port);
1126
Jeff Garzikd9afa432008-02-06 01:36:11 -08001127 spin_lock_irqsave(&riscom_lock, flags);
1128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (set & TIOCM_RTS)
1130 port->MSVR |= MSVR_RTS;
1131 if (set & TIOCM_DTR)
1132 bp->DTR &= ~(1u << port_No(port));
1133
1134 if (clear & TIOCM_RTS)
1135 port->MSVR &= ~MSVR_RTS;
1136 if (clear & TIOCM_DTR)
1137 bp->DTR |= (1u << port_No(port));
1138
1139 rc_out(bp, CD180_CAR, port_No(port));
1140 rc_out(bp, CD180_MSVR, port->MSVR);
1141 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001142
1143 spin_unlock_irqrestore(&riscom_lock, flags);
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return 0;
1146}
1147
Alan Cox781cff52008-07-22 11:18:30 +01001148static int rc_send_break(struct tty_struct *tty, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149{
Alan Coxc9f19e92009-01-02 13:47:26 +00001150 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 struct riscom_board *bp = port_Board(port);
1152 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001153
Alan Cox781cff52008-07-22 11:18:30 +01001154 if (length == 0 || length == -1)
1155 return -EOPNOTSUPP;
1156
Jeff Garzikd9afa432008-02-06 01:36:11 -08001157 spin_lock_irqsave(&riscom_lock, flags);
1158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 port->break_length = RISCOM_TPS / HZ * length;
1160 port->COR2 |= COR2_ETC;
1161 port->IER |= IER_TXRDY;
1162 rc_out(bp, CD180_CAR, port_No(port));
1163 rc_out(bp, CD180_COR2, port->COR2);
1164 rc_out(bp, CD180_IER, port->IER);
1165 rc_wait_CCR(bp);
1166 rc_out(bp, CD180_CCR, CCR_CORCHG2);
1167 rc_wait_CCR(bp);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001168
1169 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Cox781cff52008-07-22 11:18:30 +01001170 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171}
1172
Alan Cox9492e132008-04-30 00:54:15 -07001173static int rc_set_serial_info(struct riscom_port *port,
1174 struct serial_struct __user *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
1176 struct serial_struct tmp;
1177 struct riscom_board *bp = port_Board(port);
1178 int change_speed;
Alan Cox9492e132008-04-30 00:54:15 -07001179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
1181 return -EFAULT;
Alan Cox9492e132008-04-30 00:54:15 -07001182
1183#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if ((tmp.irq != bp->irq) ||
1185 (tmp.port != bp->base) ||
1186 (tmp.type != PORT_CIRRUS) ||
1187 (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
1188 (tmp.custom_divisor != 0) ||
1189 (tmp.xmit_fifo_size != CD180_NFIFO) ||
1190 (tmp.flags & ~RISCOM_LEGAL_FLAGS))
1191 return -EINVAL;
Alan Cox9492e132008-04-30 00:54:15 -07001192#endif
1193
Alan Cox85f8f812008-07-16 21:55:29 +01001194 change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 (tmp.flags & ASYNC_SPD_MASK));
Alan Cox9492e132008-04-30 00:54:15 -07001196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01001198 if ((tmp.close_delay != port->port.close_delay) ||
1199 (tmp.closing_wait != port->port.closing_wait) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 ((tmp.flags & ~ASYNC_USR_MASK) !=
Alan Cox85f8f812008-07-16 21:55:29 +01001201 (port->port.flags & ~ASYNC_USR_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 return -EPERM;
Alan Cox85f8f812008-07-16 21:55:29 +01001203 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 (tmp.flags & ASYNC_USR_MASK));
1205 } else {
Alan Cox85f8f812008-07-16 21:55:29 +01001206 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 (tmp.flags & ASYNC_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001208 port->port.close_delay = tmp.close_delay;
1209 port->port.closing_wait = tmp.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 }
1211 if (change_speed) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001212 unsigned long flags;
1213
1214 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 rc_change_speed(bp, port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001216 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218 return 0;
1219}
1220
Alan Cox9492e132008-04-30 00:54:15 -07001221static int rc_get_serial_info(struct riscom_port *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 struct serial_struct __user *retinfo)
1223{
1224 struct serial_struct tmp;
1225 struct riscom_board *bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 memset(&tmp, 0, sizeof(tmp));
1228 tmp.type = PORT_CIRRUS;
1229 tmp.line = port - rc_port;
1230 tmp.port = bp->base;
1231 tmp.irq = bp->irq;
Alan Cox85f8f812008-07-16 21:55:29 +01001232 tmp.flags = port->port.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001234 tmp.close_delay = port->port.close_delay * HZ/100;
1235 tmp.closing_wait = port->port.closing_wait * HZ/100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 tmp.xmit_fifo_size = CD180_NFIFO;
1237 return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
1238}
1239
Alan Cox9492e132008-04-30 00:54:15 -07001240static int rc_ioctl(struct tty_struct *tty, struct file *filp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
Alan Coxc9f19e92009-01-02 13:47:26 +00001243 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 void __user *argp = (void __user *)arg;
Alan Cox781cff52008-07-22 11:18:30 +01001245 int retval;
Alan Cox9492e132008-04-30 00:54:15 -07001246
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
1248 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -07001249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 switch (cmd) {
Alan Cox9492e132008-04-30 00:54:15 -07001251 case TIOCGSERIAL:
1252 lock_kernel();
Alan Coxeb174552008-04-30 00:53:21 -07001253 retval = rc_get_serial_info(port, argp);
1254 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 break;
Alan Cox9492e132008-04-30 00:54:15 -07001256 case TIOCSSERIAL:
1257 lock_kernel();
Alan Coxeb174552008-04-30 00:53:21 -07001258 retval = rc_set_serial_info(port, argp);
1259 unlock_kernel();
1260 break;
Alan Cox9492e132008-04-30 00:54:15 -07001261 default:
Alan Coxeb174552008-04-30 00:53:21 -07001262 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
Alan Coxeb174552008-04-30 00:53:21 -07001264 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265}
1266
Alan Cox9492e132008-04-30 00:54:15 -07001267static void rc_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268{
Alan Coxc9f19e92009-01-02 13:47:26 +00001269 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 struct riscom_board *bp;
1271 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (rc_paranoia_check(port, tty->name, "rc_throttle"))
1274 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001276
1277 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 port->MSVR &= ~MSVR_RTS;
1279 rc_out(bp, CD180_CAR, port_No(port));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001280 if (I_IXOFF(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 rc_wait_CCR(bp);
1282 rc_out(bp, CD180_CCR, CCR_SSCH2);
1283 rc_wait_CCR(bp);
1284 }
1285 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001286 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287}
1288
Alan Cox9492e132008-04-30 00:54:15 -07001289static void rc_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
Alan Coxc9f19e92009-01-02 13:47:26 +00001291 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 struct riscom_board *bp;
1293 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001294
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
1296 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001298
Alan Cox9492e132008-04-30 00:54:15 -07001299 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 port->MSVR |= MSVR_RTS;
1301 rc_out(bp, CD180_CAR, port_No(port));
1302 if (I_IXOFF(tty)) {
1303 rc_wait_CCR(bp);
1304 rc_out(bp, CD180_CCR, CCR_SSCH1);
1305 rc_wait_CCR(bp);
1306 }
1307 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001308 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309}
1310
Alan Cox9492e132008-04-30 00:54:15 -07001311static void rc_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
Alan Coxc9f19e92009-01-02 13:47:26 +00001313 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 struct riscom_board *bp;
1315 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001316
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (rc_paranoia_check(port, tty->name, "rc_stop"))
1318 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001319
Alan Cox9492e132008-04-30 00:54:15 -07001320 bp = port_Board(port);
1321
1322 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 port->IER &= ~IER_TXRDY;
1324 rc_out(bp, CD180_CAR, port_No(port));
1325 rc_out(bp, CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001326 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327}
1328
Alan Cox9492e132008-04-30 00:54:15 -07001329static void rc_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330{
Alan Coxc9f19e92009-01-02 13:47:26 +00001331 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 struct riscom_board *bp;
1333 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 if (rc_paranoia_check(port, tty->name, "rc_start"))
1336 return;
Alan Cox9492e132008-04-30 00:54:15 -07001337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001339
Jeff Garzikd9afa432008-02-06 01:36:11 -08001340 spin_lock_irqsave(&riscom_lock, flags);
1341
Alan Cox85f8f812008-07-16 21:55:29 +01001342 if (port->xmit_cnt && port->port.xmit_buf && !(port->IER & IER_TXRDY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 port->IER |= IER_TXRDY;
1344 rc_out(bp, CD180_CAR, port_No(port));
1345 rc_out(bp, CD180_IER, port->IER);
1346 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001347 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348}
1349
Alan Cox9492e132008-04-30 00:54:15 -07001350static void rc_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
Alan Coxc9f19e92009-01-02 13:47:26 +00001352 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 struct riscom_board *bp;
Alan Coxc2ba38c2009-01-02 13:45:50 +00001354 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (rc_paranoia_check(port, tty->name, "rc_hangup"))
1357 return;
Alan Cox9492e132008-04-30 00:54:15 -07001358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001360
Alan Coxd99101f2008-07-16 21:55:37 +01001361 rc_shutdown_port(tty, bp, port);
Alan Coxc2ba38c2009-01-02 13:45:50 +00001362 spin_lock_irqsave(&port->port.lock, flags);
Alan Cox85f8f812008-07-16 21:55:29 +01001363 port->port.count = 0;
1364 port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
1365 port->port.tty = NULL;
1366 wake_up_interruptible(&port->port.open_wait);
Alan Coxc2ba38c2009-01-02 13:45:50 +00001367 spin_unlock_irqrestore(&port->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368}
1369
Alan Cox9492e132008-04-30 00:54:15 -07001370static void rc_set_termios(struct tty_struct *tty,
1371 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372{
Alan Coxc9f19e92009-01-02 13:47:26 +00001373 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
1377 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Jeff Garzikd9afa432008-02-06 01:36:11 -08001379 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 rc_change_speed(port_Board(port), port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001381 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 if ((old_termios->c_cflag & CRTSCTS) &&
1384 !(tty->termios->c_cflag & CRTSCTS)) {
1385 tty->hw_stopped = 0;
1386 rc_start(tty);
1387 }
1388}
1389
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001390static const struct tty_operations riscom_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 .open = rc_open,
1392 .close = rc_close,
1393 .write = rc_write,
1394 .put_char = rc_put_char,
1395 .flush_chars = rc_flush_chars,
1396 .write_room = rc_write_room,
1397 .chars_in_buffer = rc_chars_in_buffer,
1398 .flush_buffer = rc_flush_buffer,
1399 .ioctl = rc_ioctl,
1400 .throttle = rc_throttle,
1401 .unthrottle = rc_unthrottle,
1402 .set_termios = rc_set_termios,
1403 .stop = rc_stop,
1404 .start = rc_start,
1405 .hangup = rc_hangup,
1406 .tiocmget = rc_tiocmget,
1407 .tiocmset = rc_tiocmset,
Alan Cox781cff52008-07-22 11:18:30 +01001408 .break_ctl = rc_send_break,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409};
1410
Alan Cox31f35932009-01-02 13:45:05 +00001411static const struct tty_port_operations riscom_port_ops = {
1412 .carrier_raised = carrier_raised,
1413};
1414
1415
Jiri Slaby1386a822008-02-07 00:16:36 -08001416static int __init rc_init_drivers(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417{
1418 int error;
1419 int i;
1420
1421 riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
Alan Cox9492e132008-04-30 00:54:15 -07001422 if (!riscom_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 return -ENOMEM;
Alan Cox9492e132008-04-30 00:54:15 -07001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 riscom_driver->owner = THIS_MODULE;
1426 riscom_driver->name = "ttyL";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 riscom_driver->major = RISCOM8_NORMAL_MAJOR;
1428 riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
1429 riscom_driver->subtype = SERIAL_TYPE_NORMAL;
1430 riscom_driver->init_termios = tty_std_termios;
1431 riscom_driver->init_termios.c_cflag =
1432 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08001433 riscom_driver->init_termios.c_ispeed = 9600;
1434 riscom_driver->init_termios.c_ospeed = 9600;
Alan Cox781cff52008-07-22 11:18:30 +01001435 riscom_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 tty_set_operations(riscom_driver, &riscom_ops);
Alan Cox9492e132008-04-30 00:54:15 -07001437 error = tty_register_driver(riscom_driver);
1438 if (error != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 put_tty_driver(riscom_driver);
1440 printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
Alan Cox9492e132008-04-30 00:54:15 -07001441 "error = %d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 return 1;
1443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 memset(rc_port, 0, sizeof(rc_port));
1445 for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
Alan Cox85f8f812008-07-16 21:55:29 +01001446 tty_port_init(&rc_port[i].port);
Alan Cox31f35932009-01-02 13:45:05 +00001447 rc_port[i].port.ops = &riscom_port_ops;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001448 rc_port[i].magic = RISCOM8_MAGIC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 return 0;
1451}
1452
1453static void rc_release_drivers(void)
1454{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 tty_unregister_driver(riscom_driver);
1456 put_tty_driver(riscom_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457}
1458
1459#ifndef MODULE
1460/*
1461 * Called at boot time.
Alan Cox9492e132008-04-30 00:54:15 -07001462 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 * You can specify IO base for up to RC_NBOARD cards,
1464 * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
1465 * Note that there will be no probing at default
1466 * addresses in this case.
1467 *
Alan Cox9492e132008-04-30 00:54:15 -07001468 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469static int __init riscom8_setup(char *str)
1470{
1471 int ints[RC_NBOARD];
1472 int i;
1473
1474 str = get_options(str, ARRAY_SIZE(ints), ints);
1475
1476 for (i = 0; i < RC_NBOARD; i++) {
1477 if (i < ints[0])
1478 rc_board[i].base = ints[i+1];
Alan Cox9492e132008-04-30 00:54:15 -07001479 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 rc_board[i].base = 0;
1481 }
1482 return 1;
1483}
1484
1485__setup("riscom8=", riscom8_setup);
1486#endif
1487
1488static char banner[] __initdata =
1489 KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
1490 "1994-1996.\n";
1491static char no_boards_msg[] __initdata =
1492 KERN_INFO "rc: No RISCom/8 boards detected.\n";
1493
Alan Cox9492e132008-04-30 00:54:15 -07001494/*
1495 * This routine must be called by kernel at boot time
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 */
1497static int __init riscom8_init(void)
1498{
1499 int i;
1500 int found = 0;
1501
1502 printk(banner);
1503
Alan Cox9492e132008-04-30 00:54:15 -07001504 if (rc_init_drivers())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return -EIO;
1506
Alan Cox9492e132008-04-30 00:54:15 -07001507 for (i = 0; i < RC_NBOARD; i++)
1508 if (rc_board[i].base && !rc_probe(&rc_board[i]))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 found++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if (!found) {
1511 rc_release_drivers();
1512 printk(no_boards_msg);
1513 return -EIO;
1514 }
1515 return 0;
1516}
1517
1518#ifdef MODULE
1519static int iobase;
1520static int iobase1;
1521static int iobase2;
1522static int iobase3;
Rusty Russell8d3b33f2006-03-25 03:07:05 -08001523module_param(iobase, int, 0);
1524module_param(iobase1, int, 0);
1525module_param(iobase2, int, 0);
1526module_param(iobase3, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528MODULE_LICENSE("GPL");
Scott James Remnant5c9f5802009-04-06 17:33:26 +01001529MODULE_ALIAS_CHARDEV_MAJOR(RISCOM8_NORMAL_MAJOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530#endif /* MODULE */
1531
1532/*
1533 * You can setup up to 4 boards (current value of RC_NBOARD)
1534 * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
1535 *
1536 */
Alan Cox9492e132008-04-30 00:54:15 -07001537static int __init riscom8_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538{
1539#ifdef MODULE
1540 int i;
1541
1542 if (iobase || iobase1 || iobase2 || iobase3) {
Alan Cox9492e132008-04-30 00:54:15 -07001543 for (i = 0; i < RC_NBOARD; i++)
Jiri Slaby9efda792008-03-13 12:32:39 -07001544 rc_board[i].base = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 }
1546
1547 if (iobase)
1548 rc_board[0].base = iobase;
1549 if (iobase1)
1550 rc_board[1].base = iobase1;
1551 if (iobase2)
1552 rc_board[2].base = iobase2;
1553 if (iobase3)
1554 rc_board[3].base = iobase3;
1555#endif /* MODULE */
1556
1557 return riscom8_init();
1558}
Alan Cox9492e132008-04-30 00:54:15 -07001559
1560static void __exit riscom8_exit_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561{
1562 int i;
Alan Cox9492e132008-04-30 00:54:15 -07001563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 rc_release_drivers();
Alan Cox9492e132008-04-30 00:54:15 -07001565 for (i = 0; i < RC_NBOARD; i++)
1566 if (rc_board[i].flags & RC_BOARD_PRESENT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 rc_release_io_range(&rc_board[i]);
Alan Cox9492e132008-04-30 00:54:15 -07001568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569}
1570
1571module_init(riscom8_init_module);
1572module_exit(riscom8_exit_module);