blob: 9499991202581d03e569c889edad69ca936a8421 [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 Coxc1469422009-09-19 13:13:21 -0700924static void rc_close_port(struct tty_struct *tty, struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 unsigned long flags;
Alan Coxc1469422009-09-19 13:13:21 -0700927 struct riscom_port *rp = container_of(port, struct riscom_port, port);
928 struct riscom_board *bp = port_Board(rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 unsigned long timeout;
Alan Coxa6614992009-01-02 13:46:50 +0000930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 /*
932 * At this point we stop accepting input. To do this, we
933 * disable the receive line status interrupts, and tell the
934 * interrupt driver to stop checking the data ready bit in the
935 * line status register.
936 */
Alan Coxc2ba38c2009-01-02 13:45:50 +0000937
938 spin_lock_irqsave(&riscom_lock, flags);
Alan Coxc1469422009-09-19 13:13:21 -0700939 rp->IER &= ~IER_RXD;
940 if (port->flags & ASYNC_INITIALIZED) {
941 rp->IER &= ~IER_TXRDY;
942 rp->IER |= IER_TXEMPTY;
943 rc_out(bp, CD180_CAR, port_No(rp));
944 rc_out(bp, CD180_IER, rp->IER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 /*
946 * Before we drop DTR, make sure the UART transmitter
947 * has completely drained; this is especially
948 * important if there is a transmit FIFO!
949 */
Alan Cox9492e132008-04-30 00:54:15 -0700950 timeout = jiffies + HZ;
Alan Coxc1469422009-09-19 13:13:21 -0700951 while (rp->IER & IER_TXEMPTY) {
Alan Coxc2ba38c2009-01-02 13:45:50 +0000952 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxc1469422009-09-19 13:13:21 -0700953 msleep_interruptible(jiffies_to_msecs(rp->timeout));
Alan Coxc2ba38c2009-01-02 13:45:50 +0000954 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 if (time_after(jiffies, timeout))
956 break;
957 }
958 }
Alan Coxc1469422009-09-19 13:13:21 -0700959 rc_shutdown_port(tty, bp, rp);
Alan Coxc2ba38c2009-01-02 13:45:50 +0000960 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxc1469422009-09-19 13:13:21 -0700961}
962
963static void rc_close(struct tty_struct *tty, struct file *filp)
964{
965 struct riscom_port *port = tty->driver_data;
966
967 if (!port || rc_paranoia_check(port, tty->name, "close"))
968 return;
969
970 if (tty_port_close_start(&port->port, tty, filp) == 0)
971 return;
972
973 rc_close_port(tty, &port->port);
974 rc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Alan Coxa6614992009-01-02 13:46:50 +0000976 tty_port_close_end(&port->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977}
978
Alan Cox9492e132008-04-30 00:54:15 -0700979static int rc_write(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 const unsigned char *buf, int count)
981{
Alan Coxc9f19e92009-01-02 13:47:26 +0000982 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 struct riscom_board *bp;
984 int c, total = 0;
985 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -0700986
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (rc_paranoia_check(port, tty->name, "rc_write"))
988 return 0;
Alan Cox9492e132008-04-30 00:54:15 -0700989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 bp = port_Board(port);
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -0800993 spin_lock_irqsave(&riscom_lock, flags);
994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
996 SERIAL_XMIT_SIZE - port->xmit_head));
Jeff Garzikd9afa432008-02-06 01:36:11 -0800997 if (c <= 0)
998 break; /* lock continues to be held */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Alan Cox85f8f812008-07-16 21:55:29 +01001000 memcpy(port->port.xmit_buf + port->xmit_head, buf, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
1002 port->xmit_cnt += c;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001003
1004 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006 buf += c;
1007 count -= c;
1008 total += c;
1009 }
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1012 !(port->IER & IER_TXRDY)) {
1013 port->IER |= IER_TXRDY;
1014 rc_out(bp, CD180_CAR, port_No(port));
1015 rc_out(bp, CD180_IER, port->IER);
1016 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001017
1018 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 return total;
1021}
1022
Alan Cox9492e132008-04-30 00:54:15 -07001023static int rc_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
Alan Coxc9f19e92009-01-02 13:47:26 +00001025 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 unsigned long flags;
Alan Coxbbbbb962008-04-30 00:54:05 -07001027 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
1029 if (rc_paranoia_check(port, tty->name, "rc_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001030 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Jeff Garzikd9afa432008-02-06 01:36:11 -08001032 spin_lock_irqsave(&riscom_lock, flags);
Alan Cox9492e132008-04-30 00:54:15 -07001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
1035 goto out;
1036
Alan Cox85f8f812008-07-16 21:55:29 +01001037 port->port.xmit_buf[port->xmit_head++] = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1039 port->xmit_cnt++;
Alan Coxbbbbb962008-04-30 00:54:05 -07001040 ret = 1;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001041
1042out:
1043 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Coxbbbbb962008-04-30 00:54:05 -07001044 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045}
1046
Alan Cox9492e132008-04-30 00:54:15 -07001047static void rc_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048{
Alan Coxc9f19e92009-01-02 13:47:26 +00001049 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
1053 return;
Alan Cox9492e132008-04-30 00:54:15 -07001054
Alan Coxd99101f2008-07-16 21:55:37 +01001055 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return;
1057
Jeff Garzikd9afa432008-02-06 01:36:11 -08001058 spin_lock_irqsave(&riscom_lock, flags);
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 port->IER |= IER_TXRDY;
1061 rc_out(port_Board(port), CD180_CAR, port_No(port));
1062 rc_out(port_Board(port), CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001063
1064 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065}
1066
Alan Cox9492e132008-04-30 00:54:15 -07001067static int rc_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
Alan Coxc9f19e92009-01-02 13:47:26 +00001069 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 int ret;
Alan Cox9492e132008-04-30 00:54:15 -07001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 if (rc_paranoia_check(port, tty->name, "rc_write_room"))
1073 return 0;
1074
1075 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1076 if (ret < 0)
1077 ret = 0;
1078 return ret;
1079}
1080
1081static int rc_chars_in_buffer(struct tty_struct *tty)
1082{
Alan Coxc9f19e92009-01-02 13:47:26 +00001083 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
1086 return 0;
Alan Cox9492e132008-04-30 00:54:15 -07001087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return port->xmit_cnt;
1089}
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091static int rc_tiocmget(struct tty_struct *tty, struct file *file)
1092{
Alan Coxc9f19e92009-01-02 13:47:26 +00001093 struct riscom_port *port = tty->driver_data;
Alan Cox9492e132008-04-30 00:54:15 -07001094 struct riscom_board *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 unsigned char status;
1096 unsigned int result;
1097 unsigned long flags;
1098
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001099 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 return -ENODEV;
1101
1102 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001103
1104 spin_lock_irqsave(&riscom_lock, flags);
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 rc_out(bp, CD180_CAR, port_No(port));
1107 status = rc_in(bp, CD180_MSVR);
1108 result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001109
1110 spin_unlock_irqrestore(&riscom_lock, flags);
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
1113 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1114 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
1115 | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
1116 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1117 return result;
1118}
1119
1120static int rc_tiocmset(struct tty_struct *tty, struct file *file,
1121 unsigned int set, unsigned int clear)
1122{
Alan Coxc9f19e92009-01-02 13:47:26 +00001123 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 unsigned long flags;
1125 struct riscom_board *bp;
1126
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07001127 if (rc_paranoia_check(port, tty->name, __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 return -ENODEV;
1129
1130 bp = port_Board(port);
1131
Jeff Garzikd9afa432008-02-06 01:36:11 -08001132 spin_lock_irqsave(&riscom_lock, flags);
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 if (set & TIOCM_RTS)
1135 port->MSVR |= MSVR_RTS;
1136 if (set & TIOCM_DTR)
1137 bp->DTR &= ~(1u << port_No(port));
1138
1139 if (clear & TIOCM_RTS)
1140 port->MSVR &= ~MSVR_RTS;
1141 if (clear & TIOCM_DTR)
1142 bp->DTR |= (1u << port_No(port));
1143
1144 rc_out(bp, CD180_CAR, port_No(port));
1145 rc_out(bp, CD180_MSVR, port->MSVR);
1146 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001147
1148 spin_unlock_irqrestore(&riscom_lock, flags);
1149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 return 0;
1151}
1152
Alan Cox781cff52008-07-22 11:18:30 +01001153static int rc_send_break(struct tty_struct *tty, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
Alan Coxc9f19e92009-01-02 13:47:26 +00001155 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 struct riscom_board *bp = port_Board(port);
1157 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001158
Alan Cox781cff52008-07-22 11:18:30 +01001159 if (length == 0 || length == -1)
1160 return -EOPNOTSUPP;
1161
Jeff Garzikd9afa432008-02-06 01:36:11 -08001162 spin_lock_irqsave(&riscom_lock, flags);
1163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 port->break_length = RISCOM_TPS / HZ * length;
1165 port->COR2 |= COR2_ETC;
1166 port->IER |= IER_TXRDY;
1167 rc_out(bp, CD180_CAR, port_No(port));
1168 rc_out(bp, CD180_COR2, port->COR2);
1169 rc_out(bp, CD180_IER, port->IER);
1170 rc_wait_CCR(bp);
1171 rc_out(bp, CD180_CCR, CCR_CORCHG2);
1172 rc_wait_CCR(bp);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001173
1174 spin_unlock_irqrestore(&riscom_lock, flags);
Alan Cox781cff52008-07-22 11:18:30 +01001175 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176}
1177
Alan Cox9492e132008-04-30 00:54:15 -07001178static int rc_set_serial_info(struct riscom_port *port,
1179 struct serial_struct __user *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
1181 struct serial_struct tmp;
1182 struct riscom_board *bp = port_Board(port);
1183 int change_speed;
Alan Cox9492e132008-04-30 00:54:15 -07001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
1186 return -EFAULT;
Alan Cox9492e132008-04-30 00:54:15 -07001187
1188#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 if ((tmp.irq != bp->irq) ||
1190 (tmp.port != bp->base) ||
1191 (tmp.type != PORT_CIRRUS) ||
1192 (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
1193 (tmp.custom_divisor != 0) ||
1194 (tmp.xmit_fifo_size != CD180_NFIFO) ||
1195 (tmp.flags & ~RISCOM_LEGAL_FLAGS))
1196 return -EINVAL;
Alan Cox9492e132008-04-30 00:54:15 -07001197#endif
1198
Alan Cox85f8f812008-07-16 21:55:29 +01001199 change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 (tmp.flags & ASYNC_SPD_MASK));
Alan Cox9492e132008-04-30 00:54:15 -07001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01001203 if ((tmp.close_delay != port->port.close_delay) ||
1204 (tmp.closing_wait != port->port.closing_wait) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 ((tmp.flags & ~ASYNC_USR_MASK) !=
Alan Cox85f8f812008-07-16 21:55:29 +01001206 (port->port.flags & ~ASYNC_USR_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 return -EPERM;
Alan Cox85f8f812008-07-16 21:55:29 +01001208 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 (tmp.flags & ASYNC_USR_MASK));
1210 } else {
Alan Cox85f8f812008-07-16 21:55:29 +01001211 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 (tmp.flags & ASYNC_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001213 port->port.close_delay = tmp.close_delay;
1214 port->port.closing_wait = tmp.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 }
1216 if (change_speed) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001217 unsigned long flags;
1218
1219 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 rc_change_speed(bp, port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001221 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 }
1223 return 0;
1224}
1225
Alan Cox9492e132008-04-30 00:54:15 -07001226static int rc_get_serial_info(struct riscom_port *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 struct serial_struct __user *retinfo)
1228{
1229 struct serial_struct tmp;
1230 struct riscom_board *bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 memset(&tmp, 0, sizeof(tmp));
1233 tmp.type = PORT_CIRRUS;
1234 tmp.line = port - rc_port;
1235 tmp.port = bp->base;
1236 tmp.irq = bp->irq;
Alan Cox85f8f812008-07-16 21:55:29 +01001237 tmp.flags = port->port.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001239 tmp.close_delay = port->port.close_delay * HZ/100;
1240 tmp.closing_wait = port->port.closing_wait * HZ/100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 tmp.xmit_fifo_size = CD180_NFIFO;
1242 return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
1243}
1244
Alan Cox9492e132008-04-30 00:54:15 -07001245static int rc_ioctl(struct tty_struct *tty, struct file *filp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247{
Alan Coxc9f19e92009-01-02 13:47:26 +00001248 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 void __user *argp = (void __user *)arg;
Alan Cox781cff52008-07-22 11:18:30 +01001250 int retval;
Alan Cox9492e132008-04-30 00:54:15 -07001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
1253 return -ENODEV;
Alan Cox9492e132008-04-30 00:54:15 -07001254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 switch (cmd) {
Alan Cox9492e132008-04-30 00:54:15 -07001256 case TIOCGSERIAL:
1257 lock_kernel();
Alan Coxeb174552008-04-30 00:53:21 -07001258 retval = rc_get_serial_info(port, argp);
1259 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 break;
Alan Cox9492e132008-04-30 00:54:15 -07001261 case TIOCSSERIAL:
1262 lock_kernel();
Alan Coxeb174552008-04-30 00:53:21 -07001263 retval = rc_set_serial_info(port, argp);
1264 unlock_kernel();
1265 break;
Alan Cox9492e132008-04-30 00:54:15 -07001266 default:
Alan Coxeb174552008-04-30 00:53:21 -07001267 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 }
Alan Coxeb174552008-04-30 00:53:21 -07001269 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270}
1271
Alan Cox9492e132008-04-30 00:54:15 -07001272static void rc_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
Alan Coxc9f19e92009-01-02 13:47:26 +00001274 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 struct riscom_board *bp;
1276 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 if (rc_paranoia_check(port, tty->name, "rc_throttle"))
1279 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001281
1282 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 port->MSVR &= ~MSVR_RTS;
1284 rc_out(bp, CD180_CAR, port_No(port));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001285 if (I_IXOFF(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 rc_wait_CCR(bp);
1287 rc_out(bp, CD180_CCR, CCR_SSCH2);
1288 rc_wait_CCR(bp);
1289 }
1290 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001291 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292}
1293
Alan Cox9492e132008-04-30 00:54:15 -07001294static void rc_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
Alan Coxc9f19e92009-01-02 13:47:26 +00001296 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 struct riscom_board *bp;
1298 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
1301 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001303
Alan Cox9492e132008-04-30 00:54:15 -07001304 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 port->MSVR |= MSVR_RTS;
1306 rc_out(bp, CD180_CAR, port_No(port));
1307 if (I_IXOFF(tty)) {
1308 rc_wait_CCR(bp);
1309 rc_out(bp, CD180_CCR, CCR_SSCH1);
1310 rc_wait_CCR(bp);
1311 }
1312 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001313 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314}
1315
Alan Cox9492e132008-04-30 00:54:15 -07001316static void rc_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
Alan Coxc9f19e92009-01-02 13:47:26 +00001318 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 struct riscom_board *bp;
1320 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001321
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (rc_paranoia_check(port, tty->name, "rc_stop"))
1323 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001324
Alan Cox9492e132008-04-30 00:54:15 -07001325 bp = port_Board(port);
1326
1327 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 port->IER &= ~IER_TXRDY;
1329 rc_out(bp, CD180_CAR, port_No(port));
1330 rc_out(bp, CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001331 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332}
1333
Alan Cox9492e132008-04-30 00:54:15 -07001334static void rc_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335{
Alan Coxc9f19e92009-01-02 13:47:26 +00001336 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 struct riscom_board *bp;
1338 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (rc_paranoia_check(port, tty->name, "rc_start"))
1341 return;
Alan Cox9492e132008-04-30 00:54:15 -07001342
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001344
Jeff Garzikd9afa432008-02-06 01:36:11 -08001345 spin_lock_irqsave(&riscom_lock, flags);
1346
Alan Cox85f8f812008-07-16 21:55:29 +01001347 if (port->xmit_cnt && port->port.xmit_buf && !(port->IER & IER_TXRDY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 port->IER |= IER_TXRDY;
1349 rc_out(bp, CD180_CAR, port_No(port));
1350 rc_out(bp, CD180_IER, port->IER);
1351 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001352 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353}
1354
Alan Cox9492e132008-04-30 00:54:15 -07001355static void rc_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356{
Alan Coxc9f19e92009-01-02 13:47:26 +00001357 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 struct riscom_board *bp;
Alan Coxc2ba38c2009-01-02 13:45:50 +00001359 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc_paranoia_check(port, tty->name, "rc_hangup"))
1362 return;
Alan Cox9492e132008-04-30 00:54:15 -07001363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 bp = port_Board(port);
Alan Cox9492e132008-04-30 00:54:15 -07001365
Alan Coxd99101f2008-07-16 21:55:37 +01001366 rc_shutdown_port(tty, bp, port);
Alan Coxc2ba38c2009-01-02 13:45:50 +00001367 spin_lock_irqsave(&port->port.lock, flags);
Alan Cox85f8f812008-07-16 21:55:29 +01001368 port->port.count = 0;
1369 port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
1370 port->port.tty = NULL;
1371 wake_up_interruptible(&port->port.open_wait);
Alan Coxc2ba38c2009-01-02 13:45:50 +00001372 spin_unlock_irqrestore(&port->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373}
1374
Alan Cox9492e132008-04-30 00:54:15 -07001375static void rc_set_termios(struct tty_struct *tty,
1376 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377{
Alan Coxc9f19e92009-01-02 13:47:26 +00001378 struct riscom_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 unsigned long flags;
Alan Cox9492e132008-04-30 00:54:15 -07001380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
1382 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Jeff Garzikd9afa432008-02-06 01:36:11 -08001384 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 rc_change_speed(port_Board(port), port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001386 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 if ((old_termios->c_cflag & CRTSCTS) &&
1389 !(tty->termios->c_cflag & CRTSCTS)) {
1390 tty->hw_stopped = 0;
1391 rc_start(tty);
1392 }
1393}
1394
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001395static const struct tty_operations riscom_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 .open = rc_open,
1397 .close = rc_close,
1398 .write = rc_write,
1399 .put_char = rc_put_char,
1400 .flush_chars = rc_flush_chars,
1401 .write_room = rc_write_room,
1402 .chars_in_buffer = rc_chars_in_buffer,
1403 .flush_buffer = rc_flush_buffer,
1404 .ioctl = rc_ioctl,
1405 .throttle = rc_throttle,
1406 .unthrottle = rc_unthrottle,
1407 .set_termios = rc_set_termios,
1408 .stop = rc_stop,
1409 .start = rc_start,
1410 .hangup = rc_hangup,
1411 .tiocmget = rc_tiocmget,
1412 .tiocmset = rc_tiocmset,
Alan Cox781cff52008-07-22 11:18:30 +01001413 .break_ctl = rc_send_break,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414};
1415
Alan Cox31f35932009-01-02 13:45:05 +00001416static const struct tty_port_operations riscom_port_ops = {
1417 .carrier_raised = carrier_raised,
1418};
1419
1420
Jiri Slaby1386a822008-02-07 00:16:36 -08001421static int __init rc_init_drivers(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422{
1423 int error;
1424 int i;
1425
1426 riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
Alan Cox9492e132008-04-30 00:54:15 -07001427 if (!riscom_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 return -ENOMEM;
Alan Cox9492e132008-04-30 00:54:15 -07001429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 riscom_driver->owner = THIS_MODULE;
1431 riscom_driver->name = "ttyL";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 riscom_driver->major = RISCOM8_NORMAL_MAJOR;
1433 riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
1434 riscom_driver->subtype = SERIAL_TYPE_NORMAL;
1435 riscom_driver->init_termios = tty_std_termios;
1436 riscom_driver->init_termios.c_cflag =
1437 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08001438 riscom_driver->init_termios.c_ispeed = 9600;
1439 riscom_driver->init_termios.c_ospeed = 9600;
Alan Cox781cff52008-07-22 11:18:30 +01001440 riscom_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 tty_set_operations(riscom_driver, &riscom_ops);
Alan Cox9492e132008-04-30 00:54:15 -07001442 error = tty_register_driver(riscom_driver);
1443 if (error != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 put_tty_driver(riscom_driver);
1445 printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
Alan Cox9492e132008-04-30 00:54:15 -07001446 "error = %d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 return 1;
1448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 memset(rc_port, 0, sizeof(rc_port));
1450 for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
Alan Cox85f8f812008-07-16 21:55:29 +01001451 tty_port_init(&rc_port[i].port);
Alan Cox31f35932009-01-02 13:45:05 +00001452 rc_port[i].port.ops = &riscom_port_ops;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001453 rc_port[i].magic = RISCOM8_MAGIC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 return 0;
1456}
1457
1458static void rc_release_drivers(void)
1459{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 tty_unregister_driver(riscom_driver);
1461 put_tty_driver(riscom_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462}
1463
1464#ifndef MODULE
1465/*
1466 * Called at boot time.
Alan Cox9492e132008-04-30 00:54:15 -07001467 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 * You can specify IO base for up to RC_NBOARD cards,
1469 * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
1470 * Note that there will be no probing at default
1471 * addresses in this case.
1472 *
Alan Cox9492e132008-04-30 00:54:15 -07001473 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474static int __init riscom8_setup(char *str)
1475{
1476 int ints[RC_NBOARD];
1477 int i;
1478
1479 str = get_options(str, ARRAY_SIZE(ints), ints);
1480
1481 for (i = 0; i < RC_NBOARD; i++) {
1482 if (i < ints[0])
1483 rc_board[i].base = ints[i+1];
Alan Cox9492e132008-04-30 00:54:15 -07001484 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 rc_board[i].base = 0;
1486 }
1487 return 1;
1488}
1489
1490__setup("riscom8=", riscom8_setup);
1491#endif
1492
1493static char banner[] __initdata =
1494 KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
1495 "1994-1996.\n";
1496static char no_boards_msg[] __initdata =
1497 KERN_INFO "rc: No RISCom/8 boards detected.\n";
1498
Alan Cox9492e132008-04-30 00:54:15 -07001499/*
1500 * This routine must be called by kernel at boot time
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 */
1502static int __init riscom8_init(void)
1503{
1504 int i;
1505 int found = 0;
1506
1507 printk(banner);
1508
Alan Cox9492e132008-04-30 00:54:15 -07001509 if (rc_init_drivers())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 return -EIO;
1511
Alan Cox9492e132008-04-30 00:54:15 -07001512 for (i = 0; i < RC_NBOARD; i++)
1513 if (rc_board[i].base && !rc_probe(&rc_board[i]))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 found++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 if (!found) {
1516 rc_release_drivers();
1517 printk(no_boards_msg);
1518 return -EIO;
1519 }
1520 return 0;
1521}
1522
1523#ifdef MODULE
1524static int iobase;
1525static int iobase1;
1526static int iobase2;
1527static int iobase3;
Rusty Russell8d3b33f2006-03-25 03:07:05 -08001528module_param(iobase, int, 0);
1529module_param(iobase1, int, 0);
1530module_param(iobase2, int, 0);
1531module_param(iobase3, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
1533MODULE_LICENSE("GPL");
Scott James Remnant5c9f5802009-04-06 17:33:26 +01001534MODULE_ALIAS_CHARDEV_MAJOR(RISCOM8_NORMAL_MAJOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535#endif /* MODULE */
1536
1537/*
1538 * You can setup up to 4 boards (current value of RC_NBOARD)
1539 * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
1540 *
1541 */
Alan Cox9492e132008-04-30 00:54:15 -07001542static int __init riscom8_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
1544#ifdef MODULE
1545 int i;
1546
1547 if (iobase || iobase1 || iobase2 || iobase3) {
Alan Cox9492e132008-04-30 00:54:15 -07001548 for (i = 0; i < RC_NBOARD; i++)
Jiri Slaby9efda792008-03-13 12:32:39 -07001549 rc_board[i].base = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 }
1551
1552 if (iobase)
1553 rc_board[0].base = iobase;
1554 if (iobase1)
1555 rc_board[1].base = iobase1;
1556 if (iobase2)
1557 rc_board[2].base = iobase2;
1558 if (iobase3)
1559 rc_board[3].base = iobase3;
1560#endif /* MODULE */
1561
1562 return riscom8_init();
1563}
Alan Cox9492e132008-04-30 00:54:15 -07001564
1565static void __exit riscom8_exit_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566{
1567 int i;
Alan Cox9492e132008-04-30 00:54:15 -07001568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 rc_release_drivers();
Alan Cox9492e132008-04-30 00:54:15 -07001570 for (i = 0; i < RC_NBOARD; i++)
1571 if (rc_board[i].flags & RC_BOARD_PRESENT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 rc_release_io_range(&rc_board[i]);
Alan Cox9492e132008-04-30 00:54:15 -07001573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574}
1575
1576module_init(riscom8_init_module);
1577module_exit(riscom8_exit_module);