blob: b56e0e04cb4a16afbe4144e95f8db2665a3aa59c [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
7 * 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
10 * 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
36#include <asm/io.h>
37#include <linux/kernel.h>
38#include <linux/sched.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
41#include <linux/errno.h>
42#include <linux/tty.h>
43#include <linux/mm.h>
44#include <linux/serial.h>
45#include <linux/fcntl.h>
46#include <linux/major.h>
47#include <linux/init.h>
48#include <linux/delay.h>
Alan Cox33f0f882006-01-09 20:54:13 -080049#include <linux/tty_flip.h>
Jeff Garzikd9afa432008-02-06 01:36:11 -080050#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include <asm/uaccess.h>
53
54#include "riscom8.h"
55#include "riscom8_reg.h"
56
57/* Am I paranoid or not ? ;-) */
58#define RISCOM_PARANOIA_CHECK
59
60/*
61 * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals.
62 * You can slightly speed up things by #undefing the following option,
63 * if you are REALLY sure that your board is correct one.
64 */
65
66#define RISCOM_BRAIN_DAMAGED_CTS
67
68/*
69 * The following defines are mostly for testing purposes. But if you need
70 * some nice reporting in your syslog, you can define them also.
71 */
72#undef RC_REPORT_FIFO
73#undef RC_REPORT_OVERRUN
74
75
76#define RISCOM_LEGAL_FLAGS \
77 (ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \
78 ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \
79 ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static struct tty_driver *riscom_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Jeff Garzikd9afa432008-02-06 01:36:11 -080083static DEFINE_SPINLOCK(riscom_lock);
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static struct riscom_board rc_board[RC_NBOARD] = {
86 {
87 .base = RC_IOBASE1,
88 },
89 {
90 .base = RC_IOBASE2,
91 },
92 {
93 .base = RC_IOBASE3,
94 },
95 {
96 .base = RC_IOBASE4,
97 },
98};
99
100static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
101
102/* RISCom/8 I/O ports addresses (without address translation) */
103static unsigned short rc_ioport[] = {
Tobias Klauserfe971072006-01-09 20:54:02 -0800104#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c,
Tobias Klauserfe971072006-01-09 20:54:02 -0800106#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, 0x10,
108 0x11, 0x12, 0x18, 0x28, 0x31, 0x32, 0x39, 0x3a, 0x40, 0x41, 0x61, 0x62,
109 0x63, 0x64, 0x6b, 0x70, 0x71, 0x78, 0x7a, 0x7b, 0x7f, 0x100, 0x101
Tobias Klauserfe971072006-01-09 20:54:02 -0800110#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
Tobias Klauserfe971072006-01-09 20:54:02 -0800112#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114
115static inline int rc_paranoia_check(struct riscom_port const * port,
116 char *name, const char *routine)
117{
118#ifdef RISCOM_PARANOIA_CHECK
119 static const char badmagic[] = KERN_INFO
120 "rc: Warning: bad riscom port magic number for device %s in %s\n";
121 static const char badinfo[] = KERN_INFO
122 "rc: Warning: null riscom port for device %s in %s\n";
123
124 if (!port) {
125 printk(badinfo, name, routine);
126 return 1;
127 }
128 if (port->magic != RISCOM8_MAGIC) {
129 printk(badmagic, name, routine);
130 return 1;
131 }
132#endif
133 return 0;
134}
135
136/*
137 *
138 * Service functions for RISCom/8 driver.
139 *
140 */
141
142/* Get board number from pointer */
143static inline int board_No (struct riscom_board const * bp)
144{
145 return bp - rc_board;
146}
147
148/* Get port number from pointer */
149static inline int port_No (struct riscom_port const * port)
150{
151 return RC_PORT(port - rc_port);
152}
153
154/* Get pointer to board from pointer to port */
155static inline struct riscom_board * port_Board(struct riscom_port const * port)
156{
157 return &rc_board[RC_BOARD(port - rc_port)];
158}
159
160/* Input Byte from CL CD180 register */
161static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg)
162{
163 return inb(bp->base + RC_TO_ISA(reg));
164}
165
166/* Output Byte to CL CD180 register */
167static inline void rc_out(struct riscom_board const * bp, unsigned short reg,
168 unsigned char val)
169{
170 outb(val, bp->base + RC_TO_ISA(reg));
171}
172
173/* Wait for Channel Command Register ready */
174static inline void rc_wait_CCR(struct riscom_board const * bp)
175{
176 unsigned long delay;
177
178 /* FIXME: need something more descriptive then 100000 :) */
179 for (delay = 100000; delay; delay--)
180 if (!rc_in(bp, CD180_CCR))
181 return;
182
183 printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
184}
185
186/*
187 * RISCom/8 probe functions.
188 */
189
190static inline int rc_request_io_range(struct riscom_board * const bp)
191{
192 int i;
193
194 for (i = 0; i < RC_NIOPORT; i++)
195 if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
196 "RISCom/8")) {
197 goto out_release;
198 }
199 return 0;
200out_release:
201 printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
202 board_No(bp), bp->base);
203 while(--i >= 0)
204 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
205 return 1;
206}
207
208static inline void rc_release_io_range(struct riscom_board * const bp)
209{
210 int i;
211
212 for (i = 0; i < RC_NIOPORT; i++)
213 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
214}
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216/* Reset and setup CD180 chip */
217static void __init rc_init_CD180(struct riscom_board const * bp)
218{
219 unsigned long flags;
220
Jeff Garzikd9afa432008-02-06 01:36:11 -0800221 spin_lock_irqsave(&riscom_lock, flags);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
224 rc_wait_CCR(bp); /* Wait for CCR ready */
225 rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800226 spin_unlock_irqrestore(&riscom_lock, flags);
Jiri Slabyc4ebd922007-07-17 04:05:20 -0700227 msleep(50); /* Delay 0.05 sec */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800228 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
230 rc_out(bp, CD180_GICR, 0); /* Clear all bits */
231 rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
232 rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */
233 rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */
234
235 /* Setting up prescaler. We need 4 ticks per 1 ms */
236 rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
237 rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
238
Jeff Garzikd9afa432008-02-06 01:36:11 -0800239 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240}
241
242/* Main probing routine, also sets irq. */
243static int __init rc_probe(struct riscom_board *bp)
244{
245 unsigned char val1, val2;
246 int irqs = 0;
247 int retries;
248
249 bp->irq = 0;
250
251 if (rc_request_io_range(bp))
252 return 1;
253
254 /* Are the I/O ports here ? */
255 rc_out(bp, CD180_PPRL, 0x5a);
256 outb(0xff, 0x80);
257 val1 = rc_in(bp, CD180_PPRL);
258 rc_out(bp, CD180_PPRL, 0xa5);
259 outb(0x00, 0x80);
260 val2 = rc_in(bp, CD180_PPRL);
261
262 if ((val1 != 0x5a) || (val2 != 0xa5)) {
263 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
264 board_No(bp), bp->base);
265 goto out_release;
266 }
267
268 /* It's time to find IRQ for this board */
269 for (retries = 0; retries < 5 && irqs <= 0; retries++) {
270 irqs = probe_irq_on();
271 rc_init_CD180(bp); /* Reset CD180 chip */
272 rc_out(bp, CD180_CAR, 2); /* Select port 2 */
273 rc_wait_CCR(bp);
274 rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
275 rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */
Jiri Slabyc4ebd922007-07-17 04:05:20 -0700276 msleep(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 irqs = probe_irq_off(irqs);
278 val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
279 val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
280 rc_init_CD180(bp); /* Reset CD180 again */
281
282 if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
283 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
284 "found.\n", board_No(bp), bp->base);
285 goto out_release;
286 }
287 }
288
289 if (irqs <= 0) {
290 printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
291 "at 0x%03x.\n", board_No(bp), bp->base);
292 goto out_release;
293 }
294 bp->irq = irqs;
295 bp->flags |= RC_BOARD_PRESENT;
296
297 printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
298 "0x%03x, IRQ %d.\n",
299 board_No(bp),
300 (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
301 bp->base, bp->irq);
302
303 return 0;
304out_release:
305 rc_release_io_range(bp);
306 return 1;
307}
308
309/*
310 *
311 * Interrupt processing routines.
312 *
313 */
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
316 unsigned char const * what)
317{
318 unsigned char channel;
319 struct riscom_port * port;
320
321 channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
322 if (channel < CD180_NCH) {
323 port = &rc_port[board_No(bp) * RC_NPORT + channel];
324 if (port->flags & ASYNC_INITIALIZED) {
325 return port;
326 }
327 }
328 printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
329 board_No(bp), what, channel);
330 return NULL;
331}
332
333static inline void rc_receive_exc(struct riscom_board const * bp)
334{
335 struct riscom_port *port;
336 struct tty_struct *tty;
337 unsigned char status;
Alan Cox33f0f882006-01-09 20:54:13 -0800338 unsigned char ch, flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 if (!(port = rc_get_port(bp, "Receive")))
341 return;
342
343 tty = port->tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345#ifdef RC_REPORT_OVERRUN
346 status = rc_in(bp, CD180_RCSR);
Alan Cox33f0f882006-01-09 20:54:13 -0800347 if (status & RCSR_OE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 port->overrun++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 status &= port->mark_mask;
350#else
351 status = rc_in(bp, CD180_RCSR) & port->mark_mask;
352#endif
353 ch = rc_in(bp, CD180_RDR);
354 if (!status) {
355 return;
356 }
357 if (status & RCSR_TOUT) {
358 printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
359 "Hardware problems ?\n",
360 board_No(bp), port_No(port));
361 return;
362
363 } else if (status & RCSR_BREAK) {
364 printk(KERN_INFO "rc%d: port %d: Handling break...\n",
365 board_No(bp), port_No(port));
Alan Cox33f0f882006-01-09 20:54:13 -0800366 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 if (port->flags & ASYNC_SAK)
368 do_SAK(tty);
369
370 } else if (status & RCSR_PE)
Alan Cox33f0f882006-01-09 20:54:13 -0800371 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 else if (status & RCSR_FE)
Alan Cox33f0f882006-01-09 20:54:13 -0800374 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 else if (status & RCSR_OE)
Alan Cox33f0f882006-01-09 20:54:13 -0800377 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 else
Alan Cox33f0f882006-01-09 20:54:13 -0800380 flag = TTY_NORMAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Alan Cox33f0f882006-01-09 20:54:13 -0800382 tty_insert_flip_char(tty, ch, flag);
383 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384}
385
386static inline void rc_receive(struct riscom_board const * bp)
387{
388 struct riscom_port *port;
389 struct tty_struct *tty;
390 unsigned char count;
391
392 if (!(port = rc_get_port(bp, "Receive")))
393 return;
394
395 tty = port->tty;
396
397 count = rc_in(bp, CD180_RDCR);
398
399#ifdef RC_REPORT_FIFO
400 port->hits[count > 8 ? 9 : count]++;
401#endif
402
403 while (count--) {
Alan Cox33f0f882006-01-09 20:54:13 -0800404 if (tty_buffer_request_room(tty, 1) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 printk(KERN_WARNING "rc%d: port %d: Working around "
406 "flip buffer overflow.\n",
407 board_No(bp), port_No(port));
408 break;
409 }
Alan Cox33f0f882006-01-09 20:54:13 -0800410 tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 }
Alan Cox33f0f882006-01-09 20:54:13 -0800412 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415static inline void rc_transmit(struct riscom_board const * bp)
416{
417 struct riscom_port *port;
418 struct tty_struct *tty;
419 unsigned char count;
420
421
422 if (!(port = rc_get_port(bp, "Transmit")))
423 return;
424
425 tty = port->tty;
426
427 if (port->IER & IER_TXEMPTY) {
428 /* FIFO drained */
429 rc_out(bp, CD180_CAR, port_No(port));
430 port->IER &= ~IER_TXEMPTY;
431 rc_out(bp, CD180_IER, port->IER);
432 return;
433 }
434
435 if ((port->xmit_cnt <= 0 && !port->break_length)
436 || tty->stopped || tty->hw_stopped) {
437 rc_out(bp, CD180_CAR, port_No(port));
438 port->IER &= ~IER_TXRDY;
439 rc_out(bp, CD180_IER, port->IER);
440 return;
441 }
442
443 if (port->break_length) {
444 if (port->break_length > 0) {
445 if (port->COR2 & COR2_ETC) {
446 rc_out(bp, CD180_TDR, CD180_C_ESC);
447 rc_out(bp, CD180_TDR, CD180_C_SBRK);
448 port->COR2 &= ~COR2_ETC;
449 }
450 count = min_t(int, port->break_length, 0xff);
451 rc_out(bp, CD180_TDR, CD180_C_ESC);
452 rc_out(bp, CD180_TDR, CD180_C_DELAY);
453 rc_out(bp, CD180_TDR, count);
454 if (!(port->break_length -= count))
455 port->break_length--;
456 } else {
457 rc_out(bp, CD180_TDR, CD180_C_ESC);
458 rc_out(bp, CD180_TDR, CD180_C_EBRK);
459 rc_out(bp, CD180_COR2, port->COR2);
460 rc_wait_CCR(bp);
461 rc_out(bp, CD180_CCR, CCR_CORCHG2);
462 port->break_length = 0;
463 }
464 return;
465 }
466
467 count = CD180_NFIFO;
468 do {
469 rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
470 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
471 if (--port->xmit_cnt <= 0)
472 break;
473 } while (--count > 0);
474
475 if (port->xmit_cnt <= 0) {
476 rc_out(bp, CD180_CAR, port_No(port));
477 port->IER &= ~IER_TXRDY;
478 rc_out(bp, CD180_IER, port->IER);
479 }
480 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800481 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482}
483
484static inline void rc_check_modem(struct riscom_board const * bp)
485{
486 struct riscom_port *port;
487 struct tty_struct *tty;
488 unsigned char mcr;
489
490 if (!(port = rc_get_port(bp, "Modem")))
491 return;
492
493 tty = port->tty;
494
495 mcr = rc_in(bp, CD180_MCR);
496 if (mcr & MCR_CDCHG) {
497 if (rc_in(bp, CD180_MSVR) & MSVR_CD)
498 wake_up_interruptible(&port->open_wait);
499 else
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800500 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502
503#ifdef RISCOM_BRAIN_DAMAGED_CTS
504 if (mcr & MCR_CTSCHG) {
505 if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
506 tty->hw_stopped = 0;
507 port->IER |= IER_TXRDY;
508 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800509 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 } else {
511 tty->hw_stopped = 1;
512 port->IER &= ~IER_TXRDY;
513 }
514 rc_out(bp, CD180_IER, port->IER);
515 }
516 if (mcr & MCR_DSRCHG) {
517 if (rc_in(bp, CD180_MSVR) & MSVR_DSR) {
518 tty->hw_stopped = 0;
519 port->IER |= IER_TXRDY;
520 if (port->xmit_cnt <= port->wakeup_chars)
Jiri Slabyb98e70d2008-02-07 00:16:41 -0800521 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 } else {
523 tty->hw_stopped = 1;
524 port->IER &= ~IER_TXRDY;
525 }
526 rc_out(bp, CD180_IER, port->IER);
527 }
528#endif /* RISCOM_BRAIN_DAMAGED_CTS */
529
530 /* Clear change bits */
531 rc_out(bp, CD180_MCR, 0);
532}
533
534/* The main interrupt processing routine */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400535static irqreturn_t rc_interrupt(int dummy, void * dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 unsigned char status;
538 unsigned char ack;
Jeff Garzikf07ef392007-10-23 19:12:11 -0400539 struct riscom_board *bp = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 unsigned long loop = 0;
541 int handled = 0;
542
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400543 if (!(bp->flags & RC_BOARD_ACTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 return IRQ_NONE;
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
547 (RC_BSR_TOUT | RC_BSR_TINT |
548 RC_BSR_MINT | RC_BSR_RINT))) {
549 handled = 1;
550 if (status & RC_BSR_TOUT)
551 printk(KERN_WARNING "rc%d: Got timeout. Hardware "
552 "error?\n", board_No(bp));
553
554 else if (status & RC_BSR_RINT) {
555 ack = rc_in(bp, RC_ACK_RINT);
556
557 if (ack == (RC_ID | GIVR_IT_RCV))
558 rc_receive(bp);
559 else if (ack == (RC_ID | GIVR_IT_REXC))
560 rc_receive_exc(bp);
561 else
562 printk(KERN_WARNING "rc%d: Bad receive ack "
563 "0x%02x.\n",
564 board_No(bp), ack);
565
566 } else if (status & RC_BSR_TINT) {
567 ack = rc_in(bp, RC_ACK_TINT);
568
569 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);
575
576 } else /* if (status & RC_BSR_MINT) */ {
577 ack = rc_in(bp, RC_ACK_MINT);
578
579 if (ack == (RC_ID | GIVR_IT_MODEM))
580 rc_check_modem(bp);
581 else
582 printk(KERN_WARNING "rc%d: Bad modem ack "
583 "0x%02x.\n",
584 board_No(bp), ack);
585
586 }
587
588 rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
589 rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
590 }
591 return IRQ_RETVAL(handled);
592}
593
594/*
595 * Routines for open & close processing.
596 */
597
598/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400599static int rc_setup_board(struct riscom_board * bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
601 int error;
602
603 if (bp->flags & RC_BOARD_ACTIVE)
604 return 0;
605
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700606 error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
Jeff Garzikf07ef392007-10-23 19:12:11 -0400607 "RISCom/8", bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 if (error)
609 return error;
610
611 rc_out(bp, RC_CTOUT, 0); /* Just in case */
612 bp->DTR = ~0;
613 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 bp->flags |= RC_BOARD_ACTIVE;
616
617 return 0;
618}
619
620/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400621static void rc_shutdown_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 if (!(bp->flags & RC_BOARD_ACTIVE))
624 return;
625
626 bp->flags &= ~RC_BOARD_ACTIVE;
627
628 free_irq(bp->irq, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 bp->DTR = ~0;
631 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
632
633}
634
635/*
636 * Setting up port characteristics.
637 * Must be called with disabled interrupts
638 */
639static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
640{
641 struct tty_struct *tty;
642 unsigned long baud;
643 long tmp;
644 unsigned char cor1 = 0, cor3 = 0;
645 unsigned char mcor1 = 0, mcor2 = 0;
646
647 if (!(tty = port->tty) || !tty->termios)
648 return;
649
650 port->IER = 0;
651 port->COR2 = 0;
652 port->MSVR = MSVR_RTS;
653
Alan Coxc7bce302006-09-30 23:27:24 -0700654 baud = tty_get_baud_rate(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 /* Select port on the board */
657 rc_out(bp, CD180_CAR, port_No(port));
658
Alan Coxc7bce302006-09-30 23:27:24 -0700659 if (!baud) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 /* Drop DTR & exit */
661 bp->DTR |= (1u << port_No(port));
662 rc_out(bp, RC_DTR, bp->DTR);
663 return;
664 } else {
665 /* Set DTR on */
666 bp->DTR &= ~(1u << port_No(port));
667 rc_out(bp, RC_DTR, bp->DTR);
668 }
669
670 /*
671 * Now we must calculate some speed depended things
672 */
673
674 /* Set baud rate for port */
Alan Coxc7bce302006-09-30 23:27:24 -0700675 tmp = (((RC_OSCFREQ + baud/2) / baud +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 CD180_TPC/2) / CD180_TPC);
677
678 rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
679 rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
680 rc_out(bp, CD180_RBPRL, tmp & 0xff);
681 rc_out(bp, CD180_TBPRL, tmp & 0xff);
682
Alan Coxc7bce302006-09-30 23:27:24 -0700683 baud = (baud + 5) / 10; /* Estimated CPS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 /* Two timer ticks seems enough to wakeup something like SLIP driver */
686 tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
687 port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
688 SERIAL_XMIT_SIZE - 1 : tmp);
689
690 /* Receiver timeout will be transmission time for 1.5 chars */
691 tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
692 tmp = (tmp > 0xff) ? 0xff : tmp;
693 rc_out(bp, CD180_RTPR, tmp);
694
695 switch (C_CSIZE(tty)) {
696 case CS5:
697 cor1 |= COR1_5BITS;
698 break;
699 case CS6:
700 cor1 |= COR1_6BITS;
701 break;
702 case CS7:
703 cor1 |= COR1_7BITS;
704 break;
705 case CS8:
706 cor1 |= COR1_8BITS;
707 break;
708 }
709
710 if (C_CSTOPB(tty))
711 cor1 |= COR1_2SB;
712
713 cor1 |= COR1_IGNORE;
714 if (C_PARENB(tty)) {
715 cor1 |= COR1_NORMPAR;
716 if (C_PARODD(tty))
717 cor1 |= COR1_ODDP;
718 if (I_INPCK(tty))
719 cor1 &= ~COR1_IGNORE;
720 }
721 /* Set marking of some errors */
722 port->mark_mask = RCSR_OE | RCSR_TOUT;
723 if (I_INPCK(tty))
724 port->mark_mask |= RCSR_FE | RCSR_PE;
725 if (I_BRKINT(tty) || I_PARMRK(tty))
726 port->mark_mask |= RCSR_BREAK;
727 if (I_IGNPAR(tty))
728 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
729 if (I_IGNBRK(tty)) {
730 port->mark_mask &= ~RCSR_BREAK;
731 if (I_IGNPAR(tty))
732 /* Real raw mode. Ignore all */
733 port->mark_mask &= ~RCSR_OE;
734 }
735 /* Enable Hardware Flow Control */
736 if (C_CRTSCTS(tty)) {
737#ifdef RISCOM_BRAIN_DAMAGED_CTS
738 port->IER |= IER_DSR | IER_CTS;
739 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
740 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
741 tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
742#else
743 port->COR2 |= COR2_CTSAE;
744#endif
745 }
746 /* Enable Software Flow Control. FIXME: I'm not sure about this */
747 /* Some people reported that it works, but I still doubt */
748 if (I_IXON(tty)) {
749 port->COR2 |= COR2_TXIBE;
750 cor3 |= (COR3_FCT | COR3_SCDE);
751 if (I_IXANY(tty))
752 port->COR2 |= COR2_IXM;
753 rc_out(bp, CD180_SCHR1, START_CHAR(tty));
754 rc_out(bp, CD180_SCHR2, STOP_CHAR(tty));
755 rc_out(bp, CD180_SCHR3, START_CHAR(tty));
756 rc_out(bp, CD180_SCHR4, STOP_CHAR(tty));
757 }
758 if (!C_CLOCAL(tty)) {
759 /* Enable CD check */
760 port->IER |= IER_CD;
761 mcor1 |= MCOR1_CDZD;
762 mcor2 |= MCOR2_CDOD;
763 }
764
765 if (C_CREAD(tty))
766 /* Enable receiver */
767 port->IER |= IER_RXD;
768
769 /* Set input FIFO size (1-8 bytes) */
770 cor3 |= RISCOM_RXFIFO;
771 /* Setting up CD180 channel registers */
772 rc_out(bp, CD180_COR1, cor1);
773 rc_out(bp, CD180_COR2, port->COR2);
774 rc_out(bp, CD180_COR3, cor3);
775 /* Make CD180 know about registers change */
776 rc_wait_CCR(bp);
777 rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
778 /* Setting up modem option registers */
779 rc_out(bp, CD180_MCOR1, mcor1);
780 rc_out(bp, CD180_MCOR2, mcor2);
781 /* Enable CD180 transmitter & receiver */
782 rc_wait_CCR(bp);
783 rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
784 /* Enable interrupts */
785 rc_out(bp, CD180_IER, port->IER);
786 /* And finally set RTS on */
787 rc_out(bp, CD180_MSVR, port->MSVR);
788}
789
790/* Must be called with interrupts enabled */
791static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
792{
793 unsigned long flags;
794
795 if (port->flags & ASYNC_INITIALIZED)
796 return 0;
797
798 if (!port->xmit_buf) {
799 /* We may sleep in get_zeroed_page() */
800 unsigned long tmp;
801
802 if (!(tmp = get_zeroed_page(GFP_KERNEL)))
803 return -ENOMEM;
804
805 if (port->xmit_buf) {
806 free_page(tmp);
807 return -ERESTARTSYS;
808 }
809 port->xmit_buf = (unsigned char *) tmp;
810 }
Jeff Garzikd9afa432008-02-06 01:36:11 -0800811
812 spin_lock_irqsave(&riscom_lock, flags);
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (port->tty)
815 clear_bit(TTY_IO_ERROR, &port->tty->flags);
816
817 if (port->count == 1)
818 bp->count++;
819
820 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
821 rc_change_speed(bp, port);
822 port->flags |= ASYNC_INITIALIZED;
823
Jeff Garzikd9afa432008-02-06 01:36:11 -0800824 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 return 0;
826}
827
828/* Must be called with interrupts disabled */
829static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
830{
831 struct tty_struct *tty;
832
833 if (!(port->flags & ASYNC_INITIALIZED))
834 return;
835
836#ifdef RC_REPORT_OVERRUN
837 printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
838 board_No(bp), port_No(port), port->overrun);
839#endif
840#ifdef RC_REPORT_FIFO
841 {
842 int i;
843
844 printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
845 board_No(bp), port_No(port));
846 for (i = 0; i < 10; i++) {
847 printk("%ld ", port->hits[i]);
848 }
849 printk("].\n");
850 }
851#endif
852 if (port->xmit_buf) {
853 free_page((unsigned long) port->xmit_buf);
854 port->xmit_buf = NULL;
855 }
856
857 if (!(tty = port->tty) || C_HUPCL(tty)) {
858 /* Drop DTR */
859 bp->DTR |= (1u << port_No(port));
860 rc_out(bp, RC_DTR, bp->DTR);
861 }
862
863 /* Select port */
864 rc_out(bp, CD180_CAR, port_No(port));
865 /* Reset port */
866 rc_wait_CCR(bp);
867 rc_out(bp, CD180_CCR, CCR_SOFTRESET);
868 /* Disable all interrupts from this port */
869 port->IER = 0;
870 rc_out(bp, CD180_IER, port->IER);
871
872 if (tty)
873 set_bit(TTY_IO_ERROR, &tty->flags);
874 port->flags &= ~ASYNC_INITIALIZED;
875
876 if (--bp->count < 0) {
877 printk(KERN_INFO "rc%d: rc_shutdown_port: "
878 "bad board count: %d\n",
879 board_No(bp), bp->count);
880 bp->count = 0;
881 }
882
883 /*
884 * If this is the last opened port on the board
885 * shutdown whole board
886 */
887 if (!bp->count)
888 rc_shutdown_board(bp);
889}
890
891
892static int block_til_ready(struct tty_struct *tty, struct file * filp,
893 struct riscom_port *port)
894{
895 DECLARE_WAITQUEUE(wait, current);
896 struct riscom_board *bp = port_Board(port);
897 int retval;
898 int do_clocal = 0;
899 int CD;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800900 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 /*
903 * If the device is in the middle of being closed, then block
904 * until it's done, and then try again.
905 */
906 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
907 interruptible_sleep_on(&port->close_wait);
908 if (port->flags & ASYNC_HUP_NOTIFY)
909 return -EAGAIN;
910 else
911 return -ERESTARTSYS;
912 }
913
914 /*
915 * If non-blocking mode is set, or the port is not enabled,
916 * then make the check up front and then exit.
917 */
918 if ((filp->f_flags & O_NONBLOCK) ||
919 (tty->flags & (1 << TTY_IO_ERROR))) {
920 port->flags |= ASYNC_NORMAL_ACTIVE;
921 return 0;
922 }
923
924 if (C_CLOCAL(tty))
925 do_clocal = 1;
926
927 /*
928 * Block waiting for the carrier detect and the line to become
929 * free (i.e., not in use by the callout). While we are in
930 * this loop, info->count is dropped by one, so that
931 * rs_close() knows when to free things. We restore it upon
932 * exit, either normal or abnormal.
933 */
934 retval = 0;
935 add_wait_queue(&port->open_wait, &wait);
Jeff Garzikd9afa432008-02-06 01:36:11 -0800936
937 spin_lock_irqsave(&riscom_lock, flags);
938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if (!tty_hung_up_p(filp))
940 port->count--;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800941
942 spin_unlock_irqrestore(&riscom_lock, flags);
943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 port->blocked_open++;
945 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -0800946 spin_lock_irqsave(&riscom_lock, flags);
947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 rc_out(bp, CD180_CAR, port_No(port));
949 CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
950 rc_out(bp, CD180_MSVR, MSVR_RTS);
951 bp->DTR &= ~(1u << port_No(port));
952 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -0800953
954 spin_unlock_irqrestore(&riscom_lock, flags);
955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 set_current_state(TASK_INTERRUPTIBLE);
957 if (tty_hung_up_p(filp) ||
958 !(port->flags & ASYNC_INITIALIZED)) {
959 if (port->flags & ASYNC_HUP_NOTIFY)
960 retval = -EAGAIN;
961 else
962 retval = -ERESTARTSYS;
963 break;
964 }
965 if (!(port->flags & ASYNC_CLOSING) &&
966 (do_clocal || CD))
967 break;
968 if (signal_pending(current)) {
969 retval = -ERESTARTSYS;
970 break;
971 }
972 schedule();
973 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700974 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 remove_wait_queue(&port->open_wait, &wait);
976 if (!tty_hung_up_p(filp))
977 port->count++;
978 port->blocked_open--;
979 if (retval)
980 return retval;
981
982 port->flags |= ASYNC_NORMAL_ACTIVE;
983 return 0;
984}
985
986static int rc_open(struct tty_struct * tty, struct file * filp)
987{
988 int board;
989 int error;
990 struct riscom_port * port;
991 struct riscom_board * bp;
992
993 board = RC_BOARD(tty->index);
994 if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
995 return -ENODEV;
996
997 bp = &rc_board[board];
998 port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
999 if (rc_paranoia_check(port, tty->name, "rc_open"))
1000 return -ENODEV;
1001
1002 if ((error = rc_setup_board(bp)))
1003 return error;
1004
1005 port->count++;
1006 tty->driver_data = port;
1007 port->tty = tty;
1008
1009 if ((error = rc_setup_port(bp, port)))
1010 return error;
1011
1012 if ((error = block_til_ready(tty, filp, port)))
1013 return error;
1014
1015 return 0;
1016}
1017
1018static void rc_close(struct tty_struct * tty, struct file * filp)
1019{
1020 struct riscom_port *port = (struct riscom_port *) tty->driver_data;
1021 struct riscom_board *bp;
1022 unsigned long flags;
1023 unsigned long timeout;
1024
1025 if (!port || rc_paranoia_check(port, tty->name, "close"))
1026 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001027
1028 spin_lock_irqsave(&riscom_lock, flags);
1029
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (tty_hung_up_p(filp))
1031 goto out;
1032
1033 bp = port_Board(port);
1034 if ((tty->count == 1) && (port->count != 1)) {
1035 printk(KERN_INFO "rc%d: rc_close: bad port count;"
1036 " tty->count is 1, port count is %d\n",
1037 board_No(bp), port->count);
1038 port->count = 1;
1039 }
1040 if (--port->count < 0) {
1041 printk(KERN_INFO "rc%d: rc_close: bad port count "
1042 "for tty%d: %d\n",
1043 board_No(bp), port_No(port), port->count);
1044 port->count = 0;
1045 }
1046 if (port->count)
1047 goto out;
1048 port->flags |= ASYNC_CLOSING;
1049 /*
1050 * Now we wait for the transmit buffer to clear; and we notify
1051 * the line discipline to only process XON/XOFF characters.
1052 */
1053 tty->closing = 1;
1054 if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
1055 tty_wait_until_sent(tty, port->closing_wait);
1056 /*
1057 * At this point we stop accepting input. To do this, we
1058 * disable the receive line status interrupts, and tell the
1059 * interrupt driver to stop checking the data ready bit in the
1060 * line status register.
1061 */
1062 port->IER &= ~IER_RXD;
1063 if (port->flags & ASYNC_INITIALIZED) {
1064 port->IER &= ~IER_TXRDY;
1065 port->IER |= IER_TXEMPTY;
1066 rc_out(bp, CD180_CAR, port_No(port));
1067 rc_out(bp, CD180_IER, port->IER);
1068 /*
1069 * Before we drop DTR, make sure the UART transmitter
1070 * has completely drained; this is especially
1071 * important if there is a transmit FIFO!
1072 */
1073 timeout = jiffies+HZ;
1074 while(port->IER & IER_TXEMPTY) {
1075 msleep_interruptible(jiffies_to_msecs(port->timeout));
1076 if (time_after(jiffies, timeout))
1077 break;
1078 }
1079 }
1080 rc_shutdown_port(bp, port);
1081 if (tty->driver->flush_buffer)
1082 tty->driver->flush_buffer(tty);
1083 tty_ldisc_flush(tty);
1084
1085 tty->closing = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 port->tty = NULL;
1087 if (port->blocked_open) {
1088 if (port->close_delay) {
1089 msleep_interruptible(jiffies_to_msecs(port->close_delay));
1090 }
1091 wake_up_interruptible(&port->open_wait);
1092 }
1093 port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1094 wake_up_interruptible(&port->close_wait);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001095
1096out:
1097 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100static int rc_write(struct tty_struct * tty,
1101 const unsigned char *buf, int count)
1102{
1103 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1104 struct riscom_board *bp;
1105 int c, total = 0;
1106 unsigned long flags;
1107
1108 if (rc_paranoia_check(port, tty->name, "rc_write"))
1109 return 0;
1110
1111 bp = port_Board(port);
1112
Jiri Slabyb3218a72006-10-04 02:15:27 -07001113 if (!tty || !port->xmit_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 return 0;
1115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001117 spin_lock_irqsave(&riscom_lock, flags);
1118
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
1120 SERIAL_XMIT_SIZE - port->xmit_head));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001121 if (c <= 0)
1122 break; /* lock continues to be held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 memcpy(port->xmit_buf + port->xmit_head, buf, c);
1125 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
1126 port->xmit_cnt += c;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001127
1128 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 buf += c;
1131 count -= c;
1132 total += c;
1133 }
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1136 !(port->IER & IER_TXRDY)) {
1137 port->IER |= IER_TXRDY;
1138 rc_out(bp, CD180_CAR, port_No(port));
1139 rc_out(bp, CD180_IER, port->IER);
1140 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001141
1142 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 return total;
1145}
1146
1147static void rc_put_char(struct tty_struct * tty, unsigned char ch)
1148{
1149 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1150 unsigned long flags;
1151
1152 if (rc_paranoia_check(port, tty->name, "rc_put_char"))
1153 return;
1154
1155 if (!tty || !port->xmit_buf)
1156 return;
1157
Jeff Garzikd9afa432008-02-06 01:36:11 -08001158 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
1161 goto out;
1162
1163 port->xmit_buf[port->xmit_head++] = ch;
1164 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1165 port->xmit_cnt++;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001166
1167out:
1168 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169}
1170
1171static void rc_flush_chars(struct tty_struct * tty)
1172{
1173 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1174 unsigned long flags;
1175
1176 if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
1177 return;
1178
1179 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1180 !port->xmit_buf)
1181 return;
1182
Jeff Garzikd9afa432008-02-06 01:36:11 -08001183 spin_lock_irqsave(&riscom_lock, flags);
1184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 port->IER |= IER_TXRDY;
1186 rc_out(port_Board(port), CD180_CAR, port_No(port));
1187 rc_out(port_Board(port), CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001188
1189 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190}
1191
1192static int rc_write_room(struct tty_struct * tty)
1193{
1194 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1195 int ret;
1196
1197 if (rc_paranoia_check(port, tty->name, "rc_write_room"))
1198 return 0;
1199
1200 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1201 if (ret < 0)
1202 ret = 0;
1203 return ret;
1204}
1205
1206static int rc_chars_in_buffer(struct tty_struct *tty)
1207{
1208 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1209
1210 if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
1211 return 0;
1212
1213 return port->xmit_cnt;
1214}
1215
1216static void rc_flush_buffer(struct tty_struct *tty)
1217{
1218 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1219 unsigned long flags;
1220
1221 if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
1222 return;
1223
Jeff Garzikd9afa432008-02-06 01:36:11 -08001224 spin_lock_irqsave(&riscom_lock, flags);
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001227
1228 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 tty_wakeup(tty);
1231}
1232
1233static int rc_tiocmget(struct tty_struct *tty, struct file *file)
1234{
1235 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1236 struct riscom_board * bp;
1237 unsigned char status;
1238 unsigned int result;
1239 unsigned long flags;
1240
1241 if (rc_paranoia_check(port, tty->name, __FUNCTION__))
1242 return -ENODEV;
1243
1244 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001245
1246 spin_lock_irqsave(&riscom_lock, flags);
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 rc_out(bp, CD180_CAR, port_No(port));
1249 status = rc_in(bp, CD180_MSVR);
1250 result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001251
1252 spin_unlock_irqrestore(&riscom_lock, flags);
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
1255 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1256 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
1257 | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
1258 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1259 return result;
1260}
1261
1262static int rc_tiocmset(struct tty_struct *tty, struct file *file,
1263 unsigned int set, unsigned int clear)
1264{
1265 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1266 unsigned long flags;
1267 struct riscom_board *bp;
1268
1269 if (rc_paranoia_check(port, tty->name, __FUNCTION__))
1270 return -ENODEV;
1271
1272 bp = port_Board(port);
1273
Jeff Garzikd9afa432008-02-06 01:36:11 -08001274 spin_lock_irqsave(&riscom_lock, flags);
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 if (set & TIOCM_RTS)
1277 port->MSVR |= MSVR_RTS;
1278 if (set & TIOCM_DTR)
1279 bp->DTR &= ~(1u << port_No(port));
1280
1281 if (clear & TIOCM_RTS)
1282 port->MSVR &= ~MSVR_RTS;
1283 if (clear & TIOCM_DTR)
1284 bp->DTR |= (1u << port_No(port));
1285
1286 rc_out(bp, CD180_CAR, port_No(port));
1287 rc_out(bp, CD180_MSVR, port->MSVR);
1288 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001289
1290 spin_unlock_irqrestore(&riscom_lock, flags);
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 return 0;
1293}
1294
1295static inline void rc_send_break(struct riscom_port * port, unsigned long length)
1296{
1297 struct riscom_board *bp = port_Board(port);
1298 unsigned long flags;
1299
Jeff Garzikd9afa432008-02-06 01:36:11 -08001300 spin_lock_irqsave(&riscom_lock, flags);
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 port->break_length = RISCOM_TPS / HZ * length;
1303 port->COR2 |= COR2_ETC;
1304 port->IER |= IER_TXRDY;
1305 rc_out(bp, CD180_CAR, port_No(port));
1306 rc_out(bp, CD180_COR2, port->COR2);
1307 rc_out(bp, CD180_IER, port->IER);
1308 rc_wait_CCR(bp);
1309 rc_out(bp, CD180_CCR, CCR_CORCHG2);
1310 rc_wait_CCR(bp);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001311
1312 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313}
1314
1315static inline int rc_set_serial_info(struct riscom_port * port,
1316 struct serial_struct __user * newinfo)
1317{
1318 struct serial_struct tmp;
1319 struct riscom_board *bp = port_Board(port);
1320 int change_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
1323 return -EFAULT;
1324
1325#if 0
1326 if ((tmp.irq != bp->irq) ||
1327 (tmp.port != bp->base) ||
1328 (tmp.type != PORT_CIRRUS) ||
1329 (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
1330 (tmp.custom_divisor != 0) ||
1331 (tmp.xmit_fifo_size != CD180_NFIFO) ||
1332 (tmp.flags & ~RISCOM_LEGAL_FLAGS))
1333 return -EINVAL;
1334#endif
1335
1336 change_speed = ((port->flags & ASYNC_SPD_MASK) !=
1337 (tmp.flags & ASYNC_SPD_MASK));
1338
1339 if (!capable(CAP_SYS_ADMIN)) {
1340 if ((tmp.close_delay != port->close_delay) ||
1341 (tmp.closing_wait != port->closing_wait) ||
1342 ((tmp.flags & ~ASYNC_USR_MASK) !=
1343 (port->flags & ~ASYNC_USR_MASK)))
1344 return -EPERM;
1345 port->flags = ((port->flags & ~ASYNC_USR_MASK) |
1346 (tmp.flags & ASYNC_USR_MASK));
1347 } else {
1348 port->flags = ((port->flags & ~ASYNC_FLAGS) |
1349 (tmp.flags & ASYNC_FLAGS));
1350 port->close_delay = tmp.close_delay;
1351 port->closing_wait = tmp.closing_wait;
1352 }
1353 if (change_speed) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001354 unsigned long flags;
1355
1356 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 rc_change_speed(bp, port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001358 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
1360 return 0;
1361}
1362
1363static inline int rc_get_serial_info(struct riscom_port * port,
1364 struct serial_struct __user *retinfo)
1365{
1366 struct serial_struct tmp;
1367 struct riscom_board *bp = port_Board(port);
1368
1369 memset(&tmp, 0, sizeof(tmp));
1370 tmp.type = PORT_CIRRUS;
1371 tmp.line = port - rc_port;
1372 tmp.port = bp->base;
1373 tmp.irq = bp->irq;
1374 tmp.flags = port->flags;
1375 tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
1376 tmp.close_delay = port->close_delay * HZ/100;
1377 tmp.closing_wait = port->closing_wait * HZ/100;
1378 tmp.xmit_fifo_size = CD180_NFIFO;
1379 return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
1380}
1381
1382static int rc_ioctl(struct tty_struct * tty, struct file * filp,
1383 unsigned int cmd, unsigned long arg)
1384
1385{
1386 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1387 void __user *argp = (void __user *)arg;
Alan Coxeb174552008-04-30 00:53:21 -07001388 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
1391 return -ENODEV;
1392
1393 switch (cmd) {
1394 case TCSBRK: /* SVID version: non-zero arg --> no break */
1395 retval = tty_check_change(tty);
1396 if (retval)
1397 return retval;
1398 tty_wait_until_sent(tty, 0);
1399 if (!arg)
1400 rc_send_break(port, HZ/4); /* 1/4 second */
1401 break;
1402 case TCSBRKP: /* support for POSIX tcsendbreak() */
1403 retval = tty_check_change(tty);
1404 if (retval)
1405 return retval;
1406 tty_wait_until_sent(tty, 0);
1407 rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
1408 break;
Alan Coxeb174552008-04-30 00:53:21 -07001409 case TIOCGSERIAL:
1410 lock_kernel();
1411 retval = rc_get_serial_info(port, argp);
1412 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 case TIOCSSERIAL:
Alan Coxeb174552008-04-30 00:53:21 -07001415 lock_kernel();
1416 retval = rc_set_serial_info(port, argp);
1417 unlock_kernel();
1418 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 default:
Alan Coxeb174552008-04-30 00:53:21 -07001420 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 }
Alan Coxeb174552008-04-30 00:53:21 -07001422 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423}
1424
1425static void rc_throttle(struct tty_struct * tty)
1426{
1427 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1428 struct riscom_board *bp;
1429 unsigned long flags;
1430
1431 if (rc_paranoia_check(port, tty->name, "rc_throttle"))
1432 return;
1433
1434 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001435
1436 spin_lock_irqsave(&riscom_lock, flags);
1437
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 port->MSVR &= ~MSVR_RTS;
1439 rc_out(bp, CD180_CAR, port_No(port));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001440 if (I_IXOFF(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 rc_wait_CCR(bp);
1442 rc_out(bp, CD180_CCR, CCR_SSCH2);
1443 rc_wait_CCR(bp);
1444 }
1445 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001446
1447 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448}
1449
1450static void rc_unthrottle(struct tty_struct * tty)
1451{
1452 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1453 struct riscom_board *bp;
1454 unsigned long flags;
1455
1456 if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
1457 return;
1458
1459 bp = port_Board(port);
1460
Jeff Garzikd9afa432008-02-06 01:36:11 -08001461 spin_lock_irqsave(&riscom_lock, flags);
1462
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 port->MSVR |= MSVR_RTS;
1464 rc_out(bp, CD180_CAR, port_No(port));
1465 if (I_IXOFF(tty)) {
1466 rc_wait_CCR(bp);
1467 rc_out(bp, CD180_CCR, CCR_SSCH1);
1468 rc_wait_CCR(bp);
1469 }
1470 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001471
1472 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473}
1474
1475static void rc_stop(struct tty_struct * tty)
1476{
1477 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1478 struct riscom_board *bp;
1479 unsigned long flags;
1480
1481 if (rc_paranoia_check(port, tty->name, "rc_stop"))
1482 return;
1483
1484 bp = port_Board(port);
1485
Jeff Garzikd9afa432008-02-06 01:36:11 -08001486 spin_lock_irqsave(&riscom_lock, flags);
1487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 port->IER &= ~IER_TXRDY;
1489 rc_out(bp, CD180_CAR, port_No(port));
1490 rc_out(bp, CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001491
1492 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493}
1494
1495static void rc_start(struct tty_struct * tty)
1496{
1497 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1498 struct riscom_board *bp;
1499 unsigned long flags;
1500
1501 if (rc_paranoia_check(port, tty->name, "rc_start"))
1502 return;
1503
1504 bp = port_Board(port);
1505
Jeff Garzikd9afa432008-02-06 01:36:11 -08001506 spin_lock_irqsave(&riscom_lock, flags);
1507
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
1509 port->IER |= IER_TXRDY;
1510 rc_out(bp, CD180_CAR, port_No(port));
1511 rc_out(bp, CD180_IER, port->IER);
1512 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001513
1514 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515}
1516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517static void rc_hangup(struct tty_struct * tty)
1518{
1519 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1520 struct riscom_board *bp;
1521
1522 if (rc_paranoia_check(port, tty->name, "rc_hangup"))
1523 return;
1524
1525 bp = port_Board(port);
1526
1527 rc_shutdown_port(bp, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 port->count = 0;
1529 port->flags &= ~ASYNC_NORMAL_ACTIVE;
1530 port->tty = NULL;
1531 wake_up_interruptible(&port->open_wait);
1532}
1533
Alan Cox606d0992006-12-08 02:38:45 -08001534static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535{
1536 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1537 unsigned long flags;
1538
1539 if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
1540 return;
1541
1542 if (tty->termios->c_cflag == old_termios->c_cflag &&
1543 tty->termios->c_iflag == old_termios->c_iflag)
1544 return;
1545
Jeff Garzikd9afa432008-02-06 01:36:11 -08001546 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 rc_change_speed(port_Board(port), port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001548 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 if ((old_termios->c_cflag & CRTSCTS) &&
1551 !(tty->termios->c_cflag & CRTSCTS)) {
1552 tty->hw_stopped = 0;
1553 rc_start(tty);
1554 }
1555}
1556
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001557static const struct tty_operations riscom_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 .open = rc_open,
1559 .close = rc_close,
1560 .write = rc_write,
1561 .put_char = rc_put_char,
1562 .flush_chars = rc_flush_chars,
1563 .write_room = rc_write_room,
1564 .chars_in_buffer = rc_chars_in_buffer,
1565 .flush_buffer = rc_flush_buffer,
1566 .ioctl = rc_ioctl,
1567 .throttle = rc_throttle,
1568 .unthrottle = rc_unthrottle,
1569 .set_termios = rc_set_termios,
1570 .stop = rc_stop,
1571 .start = rc_start,
1572 .hangup = rc_hangup,
1573 .tiocmget = rc_tiocmget,
1574 .tiocmset = rc_tiocmset,
1575};
1576
Jiri Slaby1386a822008-02-07 00:16:36 -08001577static int __init rc_init_drivers(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578{
1579 int error;
1580 int i;
1581
1582 riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
1583 if (!riscom_driver)
1584 return -ENOMEM;
1585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 riscom_driver->owner = THIS_MODULE;
1587 riscom_driver->name = "ttyL";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 riscom_driver->major = RISCOM8_NORMAL_MAJOR;
1589 riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
1590 riscom_driver->subtype = SERIAL_TYPE_NORMAL;
1591 riscom_driver->init_termios = tty_std_termios;
1592 riscom_driver->init_termios.c_cflag =
1593 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08001594 riscom_driver->init_termios.c_ispeed = 9600;
1595 riscom_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 riscom_driver->flags = TTY_DRIVER_REAL_RAW;
1597 tty_set_operations(riscom_driver, &riscom_ops);
1598 if ((error = tty_register_driver(riscom_driver))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 put_tty_driver(riscom_driver);
1600 printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
1601 "error = %d\n",
1602 error);
1603 return 1;
1604 }
1605
1606 memset(rc_port, 0, sizeof(rc_port));
1607 for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
1608 rc_port[i].magic = RISCOM8_MAGIC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 rc_port[i].close_delay = 50 * HZ/100;
1610 rc_port[i].closing_wait = 3000 * HZ/100;
1611 init_waitqueue_head(&rc_port[i].open_wait);
1612 init_waitqueue_head(&rc_port[i].close_wait);
1613 }
1614
1615 return 0;
1616}
1617
1618static void rc_release_drivers(void)
1619{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 tty_unregister_driver(riscom_driver);
1621 put_tty_driver(riscom_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622}
1623
1624#ifndef MODULE
1625/*
1626 * Called at boot time.
1627 *
1628 * You can specify IO base for up to RC_NBOARD cards,
1629 * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
1630 * Note that there will be no probing at default
1631 * addresses in this case.
1632 *
1633 */
1634static int __init riscom8_setup(char *str)
1635{
1636 int ints[RC_NBOARD];
1637 int i;
1638
1639 str = get_options(str, ARRAY_SIZE(ints), ints);
1640
1641 for (i = 0; i < RC_NBOARD; i++) {
1642 if (i < ints[0])
1643 rc_board[i].base = ints[i+1];
1644 else
1645 rc_board[i].base = 0;
1646 }
1647 return 1;
1648}
1649
1650__setup("riscom8=", riscom8_setup);
1651#endif
1652
1653static char banner[] __initdata =
1654 KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
1655 "1994-1996.\n";
1656static char no_boards_msg[] __initdata =
1657 KERN_INFO "rc: No RISCom/8 boards detected.\n";
1658
1659/*
1660 * This routine must be called by kernel at boot time
1661 */
1662static int __init riscom8_init(void)
1663{
1664 int i;
1665 int found = 0;
1666
1667 printk(banner);
1668
1669 if (rc_init_drivers())
1670 return -EIO;
1671
1672 for (i = 0; i < RC_NBOARD; i++)
1673 if (rc_board[i].base && !rc_probe(&rc_board[i]))
1674 found++;
1675
1676 if (!found) {
1677 rc_release_drivers();
1678 printk(no_boards_msg);
1679 return -EIO;
1680 }
1681 return 0;
1682}
1683
1684#ifdef MODULE
1685static int iobase;
1686static int iobase1;
1687static int iobase2;
1688static int iobase3;
Rusty Russell8d3b33f2006-03-25 03:07:05 -08001689module_param(iobase, int, 0);
1690module_param(iobase1, int, 0);
1691module_param(iobase2, int, 0);
1692module_param(iobase3, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694MODULE_LICENSE("GPL");
1695#endif /* MODULE */
1696
1697/*
1698 * You can setup up to 4 boards (current value of RC_NBOARD)
1699 * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
1700 *
1701 */
1702static int __init riscom8_init_module (void)
1703{
1704#ifdef MODULE
1705 int i;
1706
1707 if (iobase || iobase1 || iobase2 || iobase3) {
1708 for(i = 0; i < RC_NBOARD; i++)
Jiri Slaby9efda792008-03-13 12:32:39 -07001709 rc_board[i].base = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
1711
1712 if (iobase)
1713 rc_board[0].base = iobase;
1714 if (iobase1)
1715 rc_board[1].base = iobase1;
1716 if (iobase2)
1717 rc_board[2].base = iobase2;
1718 if (iobase3)
1719 rc_board[3].base = iobase3;
1720#endif /* MODULE */
1721
1722 return riscom8_init();
1723}
1724
1725static void __exit riscom8_exit_module (void)
1726{
1727 int i;
1728
1729 rc_release_drivers();
1730 for (i = 0; i < RC_NBOARD; i++)
1731 if (rc_board[i].flags & RC_BOARD_PRESENT)
1732 rc_release_io_range(&rc_board[i]);
1733
1734}
1735
1736module_init(riscom8_init_module);
1737module_exit(riscom8_exit_module);
1738