blob: 9b19abf29a2b1ad1f22db65d31a3524f4c98d777 [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
81#define RS_EVENT_WRITE_WAKEUP 0
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
117static inline int rc_paranoia_check(struct riscom_port const * port,
118 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/*
139 *
140 * Service functions for RISCom/8 driver.
141 *
142 */
143
144/* Get board number from pointer */
145static inline int board_No (struct riscom_board const * bp)
146{
147 return bp - rc_board;
148}
149
150/* Get port number from pointer */
151static inline int port_No (struct riscom_port const * port)
152{
153 return RC_PORT(port - rc_port);
154}
155
156/* Get pointer to board from pointer to port */
157static inline struct riscom_board * port_Board(struct riscom_port const * port)
158{
159 return &rc_board[RC_BOARD(port - rc_port)];
160}
161
162/* Input Byte from CL CD180 register */
163static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg)
164{
165 return inb(bp->base + RC_TO_ISA(reg));
166}
167
168/* Output Byte to CL CD180 register */
169static inline void rc_out(struct riscom_board const * bp, unsigned short reg,
170 unsigned char val)
171{
172 outb(val, bp->base + RC_TO_ISA(reg));
173}
174
175/* Wait for Channel Command Register ready */
176static inline void rc_wait_CCR(struct riscom_board const * bp)
177{
178 unsigned long delay;
179
180 /* FIXME: need something more descriptive then 100000 :) */
181 for (delay = 100000; delay; delay--)
182 if (!rc_in(bp, CD180_CCR))
183 return;
184
185 printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
186}
187
188/*
189 * RISCom/8 probe functions.
190 */
191
192static inline int rc_request_io_range(struct riscom_board * const bp)
193{
194 int i;
195
196 for (i = 0; i < RC_NIOPORT; i++)
197 if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
198 "RISCom/8")) {
199 goto out_release;
200 }
201 return 0;
202out_release:
203 printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
204 board_No(bp), bp->base);
205 while(--i >= 0)
206 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
207 return 1;
208}
209
210static inline void rc_release_io_range(struct riscom_board * const bp)
211{
212 int i;
213
214 for (i = 0; i < RC_NIOPORT; i++)
215 release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
216}
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218/* Reset and setup CD180 chip */
219static void __init rc_init_CD180(struct riscom_board const * bp)
220{
221 unsigned long flags;
222
Jeff Garzikd9afa432008-02-06 01:36:11 -0800223 spin_lock_irqsave(&riscom_lock, flags);
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
226 rc_wait_CCR(bp); /* Wait for CCR ready */
227 rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800228 spin_unlock_irqrestore(&riscom_lock, flags);
Jiri Slabyc4ebd922007-07-17 04:05:20 -0700229 msleep(50); /* Delay 0.05 sec */
Jeff Garzikd9afa432008-02-06 01:36:11 -0800230 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
232 rc_out(bp, CD180_GICR, 0); /* Clear all bits */
233 rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
234 rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */
235 rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */
236
237 /* Setting up prescaler. We need 4 ticks per 1 ms */
238 rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
239 rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
240
Jeff Garzikd9afa432008-02-06 01:36:11 -0800241 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244/* Main probing routine, also sets irq. */
245static int __init rc_probe(struct riscom_board *bp)
246{
247 unsigned char val1, val2;
248 int irqs = 0;
249 int retries;
250
251 bp->irq = 0;
252
253 if (rc_request_io_range(bp))
254 return 1;
255
256 /* Are the I/O ports here ? */
257 rc_out(bp, CD180_PPRL, 0x5a);
258 outb(0xff, 0x80);
259 val1 = rc_in(bp, CD180_PPRL);
260 rc_out(bp, CD180_PPRL, 0xa5);
261 outb(0x00, 0x80);
262 val2 = rc_in(bp, CD180_PPRL);
263
264 if ((val1 != 0x5a) || (val2 != 0xa5)) {
265 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
266 board_No(bp), bp->base);
267 goto out_release;
268 }
269
270 /* It's time to find IRQ for this board */
271 for (retries = 0; retries < 5 && irqs <= 0; retries++) {
272 irqs = probe_irq_on();
273 rc_init_CD180(bp); /* Reset CD180 chip */
274 rc_out(bp, CD180_CAR, 2); /* Select port 2 */
275 rc_wait_CCR(bp);
276 rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
277 rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */
Jiri Slabyc4ebd922007-07-17 04:05:20 -0700278 msleep(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 irqs = probe_irq_off(irqs);
280 val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
281 val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
282 rc_init_CD180(bp); /* Reset CD180 again */
283
284 if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
285 printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
286 "found.\n", board_No(bp), bp->base);
287 goto out_release;
288 }
289 }
290
291 if (irqs <= 0) {
292 printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
293 "at 0x%03x.\n", board_No(bp), bp->base);
294 goto out_release;
295 }
296 bp->irq = irqs;
297 bp->flags |= RC_BOARD_PRESENT;
298
299 printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
300 "0x%03x, IRQ %d.\n",
301 board_No(bp),
302 (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
303 bp->base, bp->irq);
304
305 return 0;
306out_release:
307 rc_release_io_range(bp);
308 return 1;
309}
310
311/*
312 *
313 * Interrupt processing routines.
314 *
315 */
316
317static inline void rc_mark_event(struct riscom_port * port, int event)
318{
319 set_bit(event, &port->event);
320 schedule_work(&port->tqueue);
321}
322
323static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
324 unsigned char const * what)
325{
326 unsigned char channel;
327 struct riscom_port * port;
328
329 channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
330 if (channel < CD180_NCH) {
331 port = &rc_port[board_No(bp) * RC_NPORT + channel];
332 if (port->flags & ASYNC_INITIALIZED) {
333 return port;
334 }
335 }
336 printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
337 board_No(bp), what, channel);
338 return NULL;
339}
340
341static inline void rc_receive_exc(struct riscom_board const * bp)
342{
343 struct riscom_port *port;
344 struct tty_struct *tty;
345 unsigned char status;
Alan Cox33f0f882006-01-09 20:54:13 -0800346 unsigned char ch, flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 if (!(port = rc_get_port(bp, "Receive")))
349 return;
350
351 tty = port->tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353#ifdef RC_REPORT_OVERRUN
354 status = rc_in(bp, CD180_RCSR);
Alan Cox33f0f882006-01-09 20:54:13 -0800355 if (status & RCSR_OE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 port->overrun++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 status &= port->mark_mask;
358#else
359 status = rc_in(bp, CD180_RCSR) & port->mark_mask;
360#endif
361 ch = rc_in(bp, CD180_RDR);
362 if (!status) {
363 return;
364 }
365 if (status & RCSR_TOUT) {
366 printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
367 "Hardware problems ?\n",
368 board_No(bp), port_No(port));
369 return;
370
371 } else if (status & RCSR_BREAK) {
372 printk(KERN_INFO "rc%d: port %d: Handling break...\n",
373 board_No(bp), port_No(port));
Alan Cox33f0f882006-01-09 20:54:13 -0800374 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 if (port->flags & ASYNC_SAK)
376 do_SAK(tty);
377
378 } else if (status & RCSR_PE)
Alan Cox33f0f882006-01-09 20:54:13 -0800379 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 else if (status & RCSR_FE)
Alan Cox33f0f882006-01-09 20:54:13 -0800382 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 else if (status & RCSR_OE)
Alan Cox33f0f882006-01-09 20:54:13 -0800385 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 else
Alan Cox33f0f882006-01-09 20:54:13 -0800388 flag = TTY_NORMAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Alan Cox33f0f882006-01-09 20:54:13 -0800390 tty_insert_flip_char(tty, ch, flag);
391 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
394static inline void rc_receive(struct riscom_board const * bp)
395{
396 struct riscom_port *port;
397 struct tty_struct *tty;
398 unsigned char count;
399
400 if (!(port = rc_get_port(bp, "Receive")))
401 return;
402
403 tty = port->tty;
404
405 count = rc_in(bp, CD180_RDCR);
406
407#ifdef RC_REPORT_FIFO
408 port->hits[count > 8 ? 9 : count]++;
409#endif
410
411 while (count--) {
Alan Cox33f0f882006-01-09 20:54:13 -0800412 if (tty_buffer_request_room(tty, 1) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 printk(KERN_WARNING "rc%d: port %d: Working around "
414 "flip buffer overflow.\n",
415 board_No(bp), port_No(port));
416 break;
417 }
Alan Cox33f0f882006-01-09 20:54:13 -0800418 tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
Alan Cox33f0f882006-01-09 20:54:13 -0800420 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
422
423static inline void rc_transmit(struct riscom_board const * bp)
424{
425 struct riscom_port *port;
426 struct tty_struct *tty;
427 unsigned char count;
428
429
430 if (!(port = rc_get_port(bp, "Transmit")))
431 return;
432
433 tty = port->tty;
434
435 if (port->IER & IER_TXEMPTY) {
436 /* FIFO drained */
437 rc_out(bp, CD180_CAR, port_No(port));
438 port->IER &= ~IER_TXEMPTY;
439 rc_out(bp, CD180_IER, port->IER);
440 return;
441 }
442
443 if ((port->xmit_cnt <= 0 && !port->break_length)
444 || tty->stopped || tty->hw_stopped) {
445 rc_out(bp, CD180_CAR, port_No(port));
446 port->IER &= ~IER_TXRDY;
447 rc_out(bp, CD180_IER, port->IER);
448 return;
449 }
450
451 if (port->break_length) {
452 if (port->break_length > 0) {
453 if (port->COR2 & COR2_ETC) {
454 rc_out(bp, CD180_TDR, CD180_C_ESC);
455 rc_out(bp, CD180_TDR, CD180_C_SBRK);
456 port->COR2 &= ~COR2_ETC;
457 }
458 count = min_t(int, port->break_length, 0xff);
459 rc_out(bp, CD180_TDR, CD180_C_ESC);
460 rc_out(bp, CD180_TDR, CD180_C_DELAY);
461 rc_out(bp, CD180_TDR, count);
462 if (!(port->break_length -= count))
463 port->break_length--;
464 } else {
465 rc_out(bp, CD180_TDR, CD180_C_ESC);
466 rc_out(bp, CD180_TDR, CD180_C_EBRK);
467 rc_out(bp, CD180_COR2, port->COR2);
468 rc_wait_CCR(bp);
469 rc_out(bp, CD180_CCR, CCR_CORCHG2);
470 port->break_length = 0;
471 }
472 return;
473 }
474
475 count = CD180_NFIFO;
476 do {
477 rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
478 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
479 if (--port->xmit_cnt <= 0)
480 break;
481 } while (--count > 0);
482
483 if (port->xmit_cnt <= 0) {
484 rc_out(bp, CD180_CAR, port_No(port));
485 port->IER &= ~IER_TXRDY;
486 rc_out(bp, CD180_IER, port->IER);
487 }
488 if (port->xmit_cnt <= port->wakeup_chars)
489 rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
490}
491
492static inline void rc_check_modem(struct riscom_board const * bp)
493{
494 struct riscom_port *port;
495 struct tty_struct *tty;
496 unsigned char mcr;
497
498 if (!(port = rc_get_port(bp, "Modem")))
499 return;
500
501 tty = port->tty;
502
503 mcr = rc_in(bp, CD180_MCR);
504 if (mcr & MCR_CDCHG) {
505 if (rc_in(bp, CD180_MSVR) & MSVR_CD)
506 wake_up_interruptible(&port->open_wait);
507 else
508 schedule_work(&port->tqueue_hangup);
509 }
510
511#ifdef RISCOM_BRAIN_DAMAGED_CTS
512 if (mcr & MCR_CTSCHG) {
513 if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
514 tty->hw_stopped = 0;
515 port->IER |= IER_TXRDY;
516 if (port->xmit_cnt <= port->wakeup_chars)
517 rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
518 } else {
519 tty->hw_stopped = 1;
520 port->IER &= ~IER_TXRDY;
521 }
522 rc_out(bp, CD180_IER, port->IER);
523 }
524 if (mcr & MCR_DSRCHG) {
525 if (rc_in(bp, CD180_MSVR) & MSVR_DSR) {
526 tty->hw_stopped = 0;
527 port->IER |= IER_TXRDY;
528 if (port->xmit_cnt <= port->wakeup_chars)
529 rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
530 } else {
531 tty->hw_stopped = 1;
532 port->IER &= ~IER_TXRDY;
533 }
534 rc_out(bp, CD180_IER, port->IER);
535 }
536#endif /* RISCOM_BRAIN_DAMAGED_CTS */
537
538 /* Clear change bits */
539 rc_out(bp, CD180_MCR, 0);
540}
541
542/* The main interrupt processing routine */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400543static irqreturn_t rc_interrupt(int dummy, void * dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 unsigned char status;
546 unsigned char ack;
Jeff Garzikf07ef392007-10-23 19:12:11 -0400547 struct riscom_board *bp = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 unsigned long loop = 0;
549 int handled = 0;
550
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400551 if (!(bp->flags & RC_BOARD_ACTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 return IRQ_NONE;
Jeff Garzikc7bec5a2006-10-06 15:00:58 -0400553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
555 (RC_BSR_TOUT | RC_BSR_TINT |
556 RC_BSR_MINT | RC_BSR_RINT))) {
557 handled = 1;
558 if (status & RC_BSR_TOUT)
559 printk(KERN_WARNING "rc%d: Got timeout. Hardware "
560 "error?\n", board_No(bp));
561
562 else if (status & RC_BSR_RINT) {
563 ack = rc_in(bp, RC_ACK_RINT);
564
565 if (ack == (RC_ID | GIVR_IT_RCV))
566 rc_receive(bp);
567 else if (ack == (RC_ID | GIVR_IT_REXC))
568 rc_receive_exc(bp);
569 else
570 printk(KERN_WARNING "rc%d: Bad receive ack "
571 "0x%02x.\n",
572 board_No(bp), ack);
573
574 } else if (status & RC_BSR_TINT) {
575 ack = rc_in(bp, RC_ACK_TINT);
576
577 if (ack == (RC_ID | GIVR_IT_TX))
578 rc_transmit(bp);
579 else
580 printk(KERN_WARNING "rc%d: Bad transmit ack "
581 "0x%02x.\n",
582 board_No(bp), ack);
583
584 } else /* if (status & RC_BSR_MINT) */ {
585 ack = rc_in(bp, RC_ACK_MINT);
586
587 if (ack == (RC_ID | GIVR_IT_MODEM))
588 rc_check_modem(bp);
589 else
590 printk(KERN_WARNING "rc%d: Bad modem ack "
591 "0x%02x.\n",
592 board_No(bp), ack);
593
594 }
595
596 rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
597 rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
598 }
599 return IRQ_RETVAL(handled);
600}
601
602/*
603 * Routines for open & close processing.
604 */
605
606/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400607static int rc_setup_board(struct riscom_board * bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 int error;
610
611 if (bp->flags & RC_BOARD_ACTIVE)
612 return 0;
613
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700614 error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
Jeff Garzikf07ef392007-10-23 19:12:11 -0400615 "RISCom/8", bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (error)
617 return error;
618
619 rc_out(bp, RC_CTOUT, 0); /* Just in case */
620 bp->DTR = ~0;
621 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 bp->flags |= RC_BOARD_ACTIVE;
624
625 return 0;
626}
627
628/* Called with disabled interrupts */
Jeff Garzikf07ef392007-10-23 19:12:11 -0400629static void rc_shutdown_board(struct riscom_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
631 if (!(bp->flags & RC_BOARD_ACTIVE))
632 return;
633
634 bp->flags &= ~RC_BOARD_ACTIVE;
635
636 free_irq(bp->irq, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 bp->DTR = ~0;
639 rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
640
641}
642
643/*
644 * Setting up port characteristics.
645 * Must be called with disabled interrupts
646 */
647static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
648{
649 struct tty_struct *tty;
650 unsigned long baud;
651 long tmp;
652 unsigned char cor1 = 0, cor3 = 0;
653 unsigned char mcor1 = 0, mcor2 = 0;
654
655 if (!(tty = port->tty) || !tty->termios)
656 return;
657
658 port->IER = 0;
659 port->COR2 = 0;
660 port->MSVR = MSVR_RTS;
661
Alan Coxc7bce302006-09-30 23:27:24 -0700662 baud = tty_get_baud_rate(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 /* Select port on the board */
665 rc_out(bp, CD180_CAR, port_No(port));
666
Alan Coxc7bce302006-09-30 23:27:24 -0700667 if (!baud) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 /* Drop DTR & exit */
669 bp->DTR |= (1u << port_No(port));
670 rc_out(bp, RC_DTR, bp->DTR);
671 return;
672 } else {
673 /* Set DTR on */
674 bp->DTR &= ~(1u << port_No(port));
675 rc_out(bp, RC_DTR, bp->DTR);
676 }
677
678 /*
679 * Now we must calculate some speed depended things
680 */
681
682 /* Set baud rate for port */
Alan Coxc7bce302006-09-30 23:27:24 -0700683 tmp = (((RC_OSCFREQ + baud/2) / baud +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 CD180_TPC/2) / CD180_TPC);
685
686 rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
687 rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
688 rc_out(bp, CD180_RBPRL, tmp & 0xff);
689 rc_out(bp, CD180_TBPRL, tmp & 0xff);
690
Alan Coxc7bce302006-09-30 23:27:24 -0700691 baud = (baud + 5) / 10; /* Estimated CPS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 /* Two timer ticks seems enough to wakeup something like SLIP driver */
694 tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
695 port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
696 SERIAL_XMIT_SIZE - 1 : tmp);
697
698 /* Receiver timeout will be transmission time for 1.5 chars */
699 tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
700 tmp = (tmp > 0xff) ? 0xff : tmp;
701 rc_out(bp, CD180_RTPR, tmp);
702
703 switch (C_CSIZE(tty)) {
704 case CS5:
705 cor1 |= COR1_5BITS;
706 break;
707 case CS6:
708 cor1 |= COR1_6BITS;
709 break;
710 case CS7:
711 cor1 |= COR1_7BITS;
712 break;
713 case CS8:
714 cor1 |= COR1_8BITS;
715 break;
716 }
717
718 if (C_CSTOPB(tty))
719 cor1 |= COR1_2SB;
720
721 cor1 |= COR1_IGNORE;
722 if (C_PARENB(tty)) {
723 cor1 |= COR1_NORMPAR;
724 if (C_PARODD(tty))
725 cor1 |= COR1_ODDP;
726 if (I_INPCK(tty))
727 cor1 &= ~COR1_IGNORE;
728 }
729 /* Set marking of some errors */
730 port->mark_mask = RCSR_OE | RCSR_TOUT;
731 if (I_INPCK(tty))
732 port->mark_mask |= RCSR_FE | RCSR_PE;
733 if (I_BRKINT(tty) || I_PARMRK(tty))
734 port->mark_mask |= RCSR_BREAK;
735 if (I_IGNPAR(tty))
736 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
737 if (I_IGNBRK(tty)) {
738 port->mark_mask &= ~RCSR_BREAK;
739 if (I_IGNPAR(tty))
740 /* Real raw mode. Ignore all */
741 port->mark_mask &= ~RCSR_OE;
742 }
743 /* Enable Hardware Flow Control */
744 if (C_CRTSCTS(tty)) {
745#ifdef RISCOM_BRAIN_DAMAGED_CTS
746 port->IER |= IER_DSR | IER_CTS;
747 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
748 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
749 tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
750#else
751 port->COR2 |= COR2_CTSAE;
752#endif
753 }
754 /* Enable Software Flow Control. FIXME: I'm not sure about this */
755 /* Some people reported that it works, but I still doubt */
756 if (I_IXON(tty)) {
757 port->COR2 |= COR2_TXIBE;
758 cor3 |= (COR3_FCT | COR3_SCDE);
759 if (I_IXANY(tty))
760 port->COR2 |= COR2_IXM;
761 rc_out(bp, CD180_SCHR1, START_CHAR(tty));
762 rc_out(bp, CD180_SCHR2, STOP_CHAR(tty));
763 rc_out(bp, CD180_SCHR3, START_CHAR(tty));
764 rc_out(bp, CD180_SCHR4, STOP_CHAR(tty));
765 }
766 if (!C_CLOCAL(tty)) {
767 /* Enable CD check */
768 port->IER |= IER_CD;
769 mcor1 |= MCOR1_CDZD;
770 mcor2 |= MCOR2_CDOD;
771 }
772
773 if (C_CREAD(tty))
774 /* Enable receiver */
775 port->IER |= IER_RXD;
776
777 /* Set input FIFO size (1-8 bytes) */
778 cor3 |= RISCOM_RXFIFO;
779 /* Setting up CD180 channel registers */
780 rc_out(bp, CD180_COR1, cor1);
781 rc_out(bp, CD180_COR2, port->COR2);
782 rc_out(bp, CD180_COR3, cor3);
783 /* Make CD180 know about registers change */
784 rc_wait_CCR(bp);
785 rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
786 /* Setting up modem option registers */
787 rc_out(bp, CD180_MCOR1, mcor1);
788 rc_out(bp, CD180_MCOR2, mcor2);
789 /* Enable CD180 transmitter & receiver */
790 rc_wait_CCR(bp);
791 rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
792 /* Enable interrupts */
793 rc_out(bp, CD180_IER, port->IER);
794 /* And finally set RTS on */
795 rc_out(bp, CD180_MSVR, port->MSVR);
796}
797
798/* Must be called with interrupts enabled */
799static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
800{
801 unsigned long flags;
802
803 if (port->flags & ASYNC_INITIALIZED)
804 return 0;
805
806 if (!port->xmit_buf) {
807 /* We may sleep in get_zeroed_page() */
808 unsigned long tmp;
809
810 if (!(tmp = get_zeroed_page(GFP_KERNEL)))
811 return -ENOMEM;
812
813 if (port->xmit_buf) {
814 free_page(tmp);
815 return -ERESTARTSYS;
816 }
817 port->xmit_buf = (unsigned char *) tmp;
818 }
Jeff Garzikd9afa432008-02-06 01:36:11 -0800819
820 spin_lock_irqsave(&riscom_lock, flags);
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (port->tty)
823 clear_bit(TTY_IO_ERROR, &port->tty->flags);
824
825 if (port->count == 1)
826 bp->count++;
827
828 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
829 rc_change_speed(bp, port);
830 port->flags |= ASYNC_INITIALIZED;
831
Jeff Garzikd9afa432008-02-06 01:36:11 -0800832 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 return 0;
834}
835
836/* Must be called with interrupts disabled */
837static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
838{
839 struct tty_struct *tty;
840
841 if (!(port->flags & ASYNC_INITIALIZED))
842 return;
843
844#ifdef RC_REPORT_OVERRUN
845 printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
846 board_No(bp), port_No(port), port->overrun);
847#endif
848#ifdef RC_REPORT_FIFO
849 {
850 int i;
851
852 printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
853 board_No(bp), port_No(port));
854 for (i = 0; i < 10; i++) {
855 printk("%ld ", port->hits[i]);
856 }
857 printk("].\n");
858 }
859#endif
860 if (port->xmit_buf) {
861 free_page((unsigned long) port->xmit_buf);
862 port->xmit_buf = NULL;
863 }
864
865 if (!(tty = port->tty) || C_HUPCL(tty)) {
866 /* Drop DTR */
867 bp->DTR |= (1u << port_No(port));
868 rc_out(bp, RC_DTR, bp->DTR);
869 }
870
871 /* Select port */
872 rc_out(bp, CD180_CAR, port_No(port));
873 /* Reset port */
874 rc_wait_CCR(bp);
875 rc_out(bp, CD180_CCR, CCR_SOFTRESET);
876 /* Disable all interrupts from this port */
877 port->IER = 0;
878 rc_out(bp, CD180_IER, port->IER);
879
880 if (tty)
881 set_bit(TTY_IO_ERROR, &tty->flags);
882 port->flags &= ~ASYNC_INITIALIZED;
883
884 if (--bp->count < 0) {
885 printk(KERN_INFO "rc%d: rc_shutdown_port: "
886 "bad board count: %d\n",
887 board_No(bp), bp->count);
888 bp->count = 0;
889 }
890
891 /*
892 * If this is the last opened port on the board
893 * shutdown whole board
894 */
895 if (!bp->count)
896 rc_shutdown_board(bp);
897}
898
899
900static int block_til_ready(struct tty_struct *tty, struct file * filp,
901 struct riscom_port *port)
902{
903 DECLARE_WAITQUEUE(wait, current);
904 struct riscom_board *bp = port_Board(port);
905 int retval;
906 int do_clocal = 0;
907 int CD;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800908 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 /*
911 * If the device is in the middle of being closed, then block
912 * until it's done, and then try again.
913 */
914 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
915 interruptible_sleep_on(&port->close_wait);
916 if (port->flags & ASYNC_HUP_NOTIFY)
917 return -EAGAIN;
918 else
919 return -ERESTARTSYS;
920 }
921
922 /*
923 * If non-blocking mode is set, or the port is not enabled,
924 * then make the check up front and then exit.
925 */
926 if ((filp->f_flags & O_NONBLOCK) ||
927 (tty->flags & (1 << TTY_IO_ERROR))) {
928 port->flags |= ASYNC_NORMAL_ACTIVE;
929 return 0;
930 }
931
932 if (C_CLOCAL(tty))
933 do_clocal = 1;
934
935 /*
936 * Block waiting for the carrier detect and the line to become
937 * free (i.e., not in use by the callout). While we are in
938 * this loop, info->count is dropped by one, so that
939 * rs_close() knows when to free things. We restore it upon
940 * exit, either normal or abnormal.
941 */
942 retval = 0;
943 add_wait_queue(&port->open_wait, &wait);
Jeff Garzikd9afa432008-02-06 01:36:11 -0800944
945 spin_lock_irqsave(&riscom_lock, flags);
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 if (!tty_hung_up_p(filp))
948 port->count--;
Jeff Garzikd9afa432008-02-06 01:36:11 -0800949
950 spin_unlock_irqrestore(&riscom_lock, flags);
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 port->blocked_open++;
953 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -0800954 spin_lock_irqsave(&riscom_lock, flags);
955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 rc_out(bp, CD180_CAR, port_No(port));
957 CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
958 rc_out(bp, CD180_MSVR, MSVR_RTS);
959 bp->DTR &= ~(1u << port_No(port));
960 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -0800961
962 spin_unlock_irqrestore(&riscom_lock, flags);
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 set_current_state(TASK_INTERRUPTIBLE);
965 if (tty_hung_up_p(filp) ||
966 !(port->flags & ASYNC_INITIALIZED)) {
967 if (port->flags & ASYNC_HUP_NOTIFY)
968 retval = -EAGAIN;
969 else
970 retval = -ERESTARTSYS;
971 break;
972 }
973 if (!(port->flags & ASYNC_CLOSING) &&
974 (do_clocal || CD))
975 break;
976 if (signal_pending(current)) {
977 retval = -ERESTARTSYS;
978 break;
979 }
980 schedule();
981 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700982 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 remove_wait_queue(&port->open_wait, &wait);
984 if (!tty_hung_up_p(filp))
985 port->count++;
986 port->blocked_open--;
987 if (retval)
988 return retval;
989
990 port->flags |= ASYNC_NORMAL_ACTIVE;
991 return 0;
992}
993
994static int rc_open(struct tty_struct * tty, struct file * filp)
995{
996 int board;
997 int error;
998 struct riscom_port * port;
999 struct riscom_board * bp;
1000
1001 board = RC_BOARD(tty->index);
1002 if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
1003 return -ENODEV;
1004
1005 bp = &rc_board[board];
1006 port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
1007 if (rc_paranoia_check(port, tty->name, "rc_open"))
1008 return -ENODEV;
1009
1010 if ((error = rc_setup_board(bp)))
1011 return error;
1012
1013 port->count++;
1014 tty->driver_data = port;
1015 port->tty = tty;
1016
1017 if ((error = rc_setup_port(bp, port)))
1018 return error;
1019
1020 if ((error = block_til_ready(tty, filp, port)))
1021 return error;
1022
1023 return 0;
1024}
1025
1026static void rc_close(struct tty_struct * tty, struct file * filp)
1027{
1028 struct riscom_port *port = (struct riscom_port *) tty->driver_data;
1029 struct riscom_board *bp;
1030 unsigned long flags;
1031 unsigned long timeout;
1032
1033 if (!port || rc_paranoia_check(port, tty->name, "close"))
1034 return;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001035
1036 spin_lock_irqsave(&riscom_lock, flags);
1037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 if (tty_hung_up_p(filp))
1039 goto out;
1040
1041 bp = port_Board(port);
1042 if ((tty->count == 1) && (port->count != 1)) {
1043 printk(KERN_INFO "rc%d: rc_close: bad port count;"
1044 " tty->count is 1, port count is %d\n",
1045 board_No(bp), port->count);
1046 port->count = 1;
1047 }
1048 if (--port->count < 0) {
1049 printk(KERN_INFO "rc%d: rc_close: bad port count "
1050 "for tty%d: %d\n",
1051 board_No(bp), port_No(port), port->count);
1052 port->count = 0;
1053 }
1054 if (port->count)
1055 goto out;
1056 port->flags |= ASYNC_CLOSING;
1057 /*
1058 * Now we wait for the transmit buffer to clear; and we notify
1059 * the line discipline to only process XON/XOFF characters.
1060 */
1061 tty->closing = 1;
1062 if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
1063 tty_wait_until_sent(tty, port->closing_wait);
1064 /*
1065 * At this point we stop accepting input. To do this, we
1066 * disable the receive line status interrupts, and tell the
1067 * interrupt driver to stop checking the data ready bit in the
1068 * line status register.
1069 */
1070 port->IER &= ~IER_RXD;
1071 if (port->flags & ASYNC_INITIALIZED) {
1072 port->IER &= ~IER_TXRDY;
1073 port->IER |= IER_TXEMPTY;
1074 rc_out(bp, CD180_CAR, port_No(port));
1075 rc_out(bp, CD180_IER, port->IER);
1076 /*
1077 * Before we drop DTR, make sure the UART transmitter
1078 * has completely drained; this is especially
1079 * important if there is a transmit FIFO!
1080 */
1081 timeout = jiffies+HZ;
1082 while(port->IER & IER_TXEMPTY) {
1083 msleep_interruptible(jiffies_to_msecs(port->timeout));
1084 if (time_after(jiffies, timeout))
1085 break;
1086 }
1087 }
1088 rc_shutdown_port(bp, port);
1089 if (tty->driver->flush_buffer)
1090 tty->driver->flush_buffer(tty);
1091 tty_ldisc_flush(tty);
1092
1093 tty->closing = 0;
1094 port->event = 0;
1095 port->tty = NULL;
1096 if (port->blocked_open) {
1097 if (port->close_delay) {
1098 msleep_interruptible(jiffies_to_msecs(port->close_delay));
1099 }
1100 wake_up_interruptible(&port->open_wait);
1101 }
1102 port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1103 wake_up_interruptible(&port->close_wait);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001104
1105out:
1106 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109static int rc_write(struct tty_struct * tty,
1110 const unsigned char *buf, int count)
1111{
1112 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1113 struct riscom_board *bp;
1114 int c, total = 0;
1115 unsigned long flags;
1116
1117 if (rc_paranoia_check(port, tty->name, "rc_write"))
1118 return 0;
1119
1120 bp = port_Board(port);
1121
Jiri Slabyb3218a72006-10-04 02:15:27 -07001122 if (!tty || !port->xmit_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 return 0;
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 while (1) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001126 spin_lock_irqsave(&riscom_lock, flags);
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
1129 SERIAL_XMIT_SIZE - port->xmit_head));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001130 if (c <= 0)
1131 break; /* lock continues to be held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 memcpy(port->xmit_buf + port->xmit_head, buf, c);
1134 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
1135 port->xmit_cnt += c;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001136
1137 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
1139 buf += c;
1140 count -= c;
1141 total += c;
1142 }
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1145 !(port->IER & IER_TXRDY)) {
1146 port->IER |= IER_TXRDY;
1147 rc_out(bp, CD180_CAR, port_No(port));
1148 rc_out(bp, CD180_IER, port->IER);
1149 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001150
1151 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 return total;
1154}
1155
1156static void rc_put_char(struct tty_struct * tty, unsigned char ch)
1157{
1158 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1159 unsigned long flags;
1160
1161 if (rc_paranoia_check(port, tty->name, "rc_put_char"))
1162 return;
1163
1164 if (!tty || !port->xmit_buf)
1165 return;
1166
Jeff Garzikd9afa432008-02-06 01:36:11 -08001167 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
1170 goto out;
1171
1172 port->xmit_buf[port->xmit_head++] = ch;
1173 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1174 port->xmit_cnt++;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001175
1176out:
1177 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180static void rc_flush_chars(struct tty_struct * tty)
1181{
1182 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1183 unsigned long flags;
1184
1185 if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
1186 return;
1187
1188 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1189 !port->xmit_buf)
1190 return;
1191
Jeff Garzikd9afa432008-02-06 01:36:11 -08001192 spin_lock_irqsave(&riscom_lock, flags);
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 port->IER |= IER_TXRDY;
1195 rc_out(port_Board(port), CD180_CAR, port_No(port));
1196 rc_out(port_Board(port), CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001197
1198 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199}
1200
1201static int rc_write_room(struct tty_struct * tty)
1202{
1203 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1204 int ret;
1205
1206 if (rc_paranoia_check(port, tty->name, "rc_write_room"))
1207 return 0;
1208
1209 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1210 if (ret < 0)
1211 ret = 0;
1212 return ret;
1213}
1214
1215static int rc_chars_in_buffer(struct tty_struct *tty)
1216{
1217 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1218
1219 if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
1220 return 0;
1221
1222 return port->xmit_cnt;
1223}
1224
1225static void rc_flush_buffer(struct tty_struct *tty)
1226{
1227 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1228 unsigned long flags;
1229
1230 if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
1231 return;
1232
Jeff Garzikd9afa432008-02-06 01:36:11 -08001233 spin_lock_irqsave(&riscom_lock, flags);
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001236
1237 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 tty_wakeup(tty);
1240}
1241
1242static int rc_tiocmget(struct tty_struct *tty, struct file *file)
1243{
1244 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1245 struct riscom_board * bp;
1246 unsigned char status;
1247 unsigned int result;
1248 unsigned long flags;
1249
1250 if (rc_paranoia_check(port, tty->name, __FUNCTION__))
1251 return -ENODEV;
1252
1253 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001254
1255 spin_lock_irqsave(&riscom_lock, flags);
1256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 rc_out(bp, CD180_CAR, port_No(port));
1258 status = rc_in(bp, CD180_MSVR);
1259 result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
Jeff Garzikd9afa432008-02-06 01:36:11 -08001260
1261 spin_unlock_irqrestore(&riscom_lock, flags);
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
1264 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1265 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
1266 | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
1267 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1268 return result;
1269}
1270
1271static int rc_tiocmset(struct tty_struct *tty, struct file *file,
1272 unsigned int set, unsigned int clear)
1273{
1274 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1275 unsigned long flags;
1276 struct riscom_board *bp;
1277
1278 if (rc_paranoia_check(port, tty->name, __FUNCTION__))
1279 return -ENODEV;
1280
1281 bp = port_Board(port);
1282
Jeff Garzikd9afa432008-02-06 01:36:11 -08001283 spin_lock_irqsave(&riscom_lock, flags);
1284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 if (set & TIOCM_RTS)
1286 port->MSVR |= MSVR_RTS;
1287 if (set & TIOCM_DTR)
1288 bp->DTR &= ~(1u << port_No(port));
1289
1290 if (clear & TIOCM_RTS)
1291 port->MSVR &= ~MSVR_RTS;
1292 if (clear & TIOCM_DTR)
1293 bp->DTR |= (1u << port_No(port));
1294
1295 rc_out(bp, CD180_CAR, port_No(port));
1296 rc_out(bp, CD180_MSVR, port->MSVR);
1297 rc_out(bp, RC_DTR, bp->DTR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001298
1299 spin_unlock_irqrestore(&riscom_lock, flags);
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 return 0;
1302}
1303
1304static inline void rc_send_break(struct riscom_port * port, unsigned long length)
1305{
1306 struct riscom_board *bp = port_Board(port);
1307 unsigned long flags;
1308
Jeff Garzikd9afa432008-02-06 01:36:11 -08001309 spin_lock_irqsave(&riscom_lock, flags);
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 port->break_length = RISCOM_TPS / HZ * length;
1312 port->COR2 |= COR2_ETC;
1313 port->IER |= IER_TXRDY;
1314 rc_out(bp, CD180_CAR, port_No(port));
1315 rc_out(bp, CD180_COR2, port->COR2);
1316 rc_out(bp, CD180_IER, port->IER);
1317 rc_wait_CCR(bp);
1318 rc_out(bp, CD180_CCR, CCR_CORCHG2);
1319 rc_wait_CCR(bp);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001320
1321 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322}
1323
1324static inline int rc_set_serial_info(struct riscom_port * port,
1325 struct serial_struct __user * newinfo)
1326{
1327 struct serial_struct tmp;
1328 struct riscom_board *bp = port_Board(port);
1329 int change_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
1331 if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
1332 return -EFAULT;
1333
1334#if 0
1335 if ((tmp.irq != bp->irq) ||
1336 (tmp.port != bp->base) ||
1337 (tmp.type != PORT_CIRRUS) ||
1338 (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
1339 (tmp.custom_divisor != 0) ||
1340 (tmp.xmit_fifo_size != CD180_NFIFO) ||
1341 (tmp.flags & ~RISCOM_LEGAL_FLAGS))
1342 return -EINVAL;
1343#endif
1344
1345 change_speed = ((port->flags & ASYNC_SPD_MASK) !=
1346 (tmp.flags & ASYNC_SPD_MASK));
1347
1348 if (!capable(CAP_SYS_ADMIN)) {
1349 if ((tmp.close_delay != port->close_delay) ||
1350 (tmp.closing_wait != port->closing_wait) ||
1351 ((tmp.flags & ~ASYNC_USR_MASK) !=
1352 (port->flags & ~ASYNC_USR_MASK)))
1353 return -EPERM;
1354 port->flags = ((port->flags & ~ASYNC_USR_MASK) |
1355 (tmp.flags & ASYNC_USR_MASK));
1356 } else {
1357 port->flags = ((port->flags & ~ASYNC_FLAGS) |
1358 (tmp.flags & ASYNC_FLAGS));
1359 port->close_delay = tmp.close_delay;
1360 port->closing_wait = tmp.closing_wait;
1361 }
1362 if (change_speed) {
Jeff Garzikd9afa432008-02-06 01:36:11 -08001363 unsigned long flags;
1364
1365 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 rc_change_speed(bp, port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001367 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
1369 return 0;
1370}
1371
1372static inline int rc_get_serial_info(struct riscom_port * port,
1373 struct serial_struct __user *retinfo)
1374{
1375 struct serial_struct tmp;
1376 struct riscom_board *bp = port_Board(port);
1377
1378 memset(&tmp, 0, sizeof(tmp));
1379 tmp.type = PORT_CIRRUS;
1380 tmp.line = port - rc_port;
1381 tmp.port = bp->base;
1382 tmp.irq = bp->irq;
1383 tmp.flags = port->flags;
1384 tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
1385 tmp.close_delay = port->close_delay * HZ/100;
1386 tmp.closing_wait = port->closing_wait * HZ/100;
1387 tmp.xmit_fifo_size = CD180_NFIFO;
1388 return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
1389}
1390
1391static int rc_ioctl(struct tty_struct * tty, struct file * filp,
1392 unsigned int cmd, unsigned long arg)
1393
1394{
1395 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1396 void __user *argp = (void __user *)arg;
1397 int retval;
1398
1399 if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
1400 return -ENODEV;
1401
1402 switch (cmd) {
1403 case TCSBRK: /* SVID version: non-zero arg --> no break */
1404 retval = tty_check_change(tty);
1405 if (retval)
1406 return retval;
1407 tty_wait_until_sent(tty, 0);
1408 if (!arg)
1409 rc_send_break(port, HZ/4); /* 1/4 second */
1410 break;
1411 case TCSBRKP: /* support for POSIX tcsendbreak() */
1412 retval = tty_check_change(tty);
1413 if (retval)
1414 return retval;
1415 tty_wait_until_sent(tty, 0);
1416 rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
1417 break;
1418 case TIOCGSOFTCAR:
1419 return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned __user *)argp);
1420 case TIOCSSOFTCAR:
1421 if (get_user(arg,(unsigned __user *) argp))
1422 return -EFAULT;
1423 tty->termios->c_cflag =
1424 ((tty->termios->c_cflag & ~CLOCAL) |
1425 (arg ? CLOCAL : 0));
1426 break;
1427 case TIOCGSERIAL:
1428 return rc_get_serial_info(port, argp);
1429 case TIOCSSERIAL:
1430 return rc_set_serial_info(port, argp);
1431 default:
1432 return -ENOIOCTLCMD;
1433 }
1434 return 0;
1435}
1436
1437static void rc_throttle(struct tty_struct * tty)
1438{
1439 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1440 struct riscom_board *bp;
1441 unsigned long flags;
1442
1443 if (rc_paranoia_check(port, tty->name, "rc_throttle"))
1444 return;
1445
1446 bp = port_Board(port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001447
1448 spin_lock_irqsave(&riscom_lock, flags);
1449
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 port->MSVR &= ~MSVR_RTS;
1451 rc_out(bp, CD180_CAR, port_No(port));
Jeff Garzikd9afa432008-02-06 01:36:11 -08001452 if (I_IXOFF(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 rc_wait_CCR(bp);
1454 rc_out(bp, CD180_CCR, CCR_SSCH2);
1455 rc_wait_CCR(bp);
1456 }
1457 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001458
1459 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460}
1461
1462static void rc_unthrottle(struct tty_struct * tty)
1463{
1464 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1465 struct riscom_board *bp;
1466 unsigned long flags;
1467
1468 if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
1469 return;
1470
1471 bp = port_Board(port);
1472
Jeff Garzikd9afa432008-02-06 01:36:11 -08001473 spin_lock_irqsave(&riscom_lock, flags);
1474
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 port->MSVR |= MSVR_RTS;
1476 rc_out(bp, CD180_CAR, port_No(port));
1477 if (I_IXOFF(tty)) {
1478 rc_wait_CCR(bp);
1479 rc_out(bp, CD180_CCR, CCR_SSCH1);
1480 rc_wait_CCR(bp);
1481 }
1482 rc_out(bp, CD180_MSVR, port->MSVR);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001483
1484 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485}
1486
1487static void rc_stop(struct tty_struct * tty)
1488{
1489 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1490 struct riscom_board *bp;
1491 unsigned long flags;
1492
1493 if (rc_paranoia_check(port, tty->name, "rc_stop"))
1494 return;
1495
1496 bp = port_Board(port);
1497
Jeff Garzikd9afa432008-02-06 01:36:11 -08001498 spin_lock_irqsave(&riscom_lock, flags);
1499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 port->IER &= ~IER_TXRDY;
1501 rc_out(bp, CD180_CAR, port_No(port));
1502 rc_out(bp, CD180_IER, port->IER);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001503
1504 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505}
1506
1507static void rc_start(struct tty_struct * tty)
1508{
1509 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1510 struct riscom_board *bp;
1511 unsigned long flags;
1512
1513 if (rc_paranoia_check(port, tty->name, "rc_start"))
1514 return;
1515
1516 bp = port_Board(port);
1517
Jeff Garzikd9afa432008-02-06 01:36:11 -08001518 spin_lock_irqsave(&riscom_lock, flags);
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
1521 port->IER |= IER_TXRDY;
1522 rc_out(bp, CD180_CAR, port_No(port));
1523 rc_out(bp, CD180_IER, port->IER);
1524 }
Jeff Garzikd9afa432008-02-06 01:36:11 -08001525
1526 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527}
1528
1529/*
1530 * This routine is called from the work queue when the interrupt
1531 * routine has signalled that a hangup has occurred. The path of
1532 * hangup processing is:
1533 *
1534 * serial interrupt routine -> (workqueue) ->
1535 * do_rc_hangup() -> tty->hangup() -> rc_hangup()
1536 *
1537 */
Al Viro3e577a82006-12-06 18:41:45 +00001538static void do_rc_hangup(struct work_struct *ugly_api)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539{
Al Viro3e577a82006-12-06 18:41:45 +00001540 struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue_hangup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 struct tty_struct *tty;
1542
1543 tty = port->tty;
1544 if (tty)
1545 tty_hangup(tty); /* FIXME: module removal race still here */
1546}
1547
1548static void rc_hangup(struct tty_struct * tty)
1549{
1550 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1551 struct riscom_board *bp;
1552
1553 if (rc_paranoia_check(port, tty->name, "rc_hangup"))
1554 return;
1555
1556 bp = port_Board(port);
1557
1558 rc_shutdown_port(bp, port);
1559 port->event = 0;
1560 port->count = 0;
1561 port->flags &= ~ASYNC_NORMAL_ACTIVE;
1562 port->tty = NULL;
1563 wake_up_interruptible(&port->open_wait);
1564}
1565
Alan Cox606d0992006-12-08 02:38:45 -08001566static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567{
1568 struct riscom_port *port = (struct riscom_port *)tty->driver_data;
1569 unsigned long flags;
1570
1571 if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
1572 return;
1573
1574 if (tty->termios->c_cflag == old_termios->c_cflag &&
1575 tty->termios->c_iflag == old_termios->c_iflag)
1576 return;
1577
Jeff Garzikd9afa432008-02-06 01:36:11 -08001578 spin_lock_irqsave(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 rc_change_speed(port_Board(port), port);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001580 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 if ((old_termios->c_cflag & CRTSCTS) &&
1583 !(tty->termios->c_cflag & CRTSCTS)) {
1584 tty->hw_stopped = 0;
1585 rc_start(tty);
1586 }
1587}
1588
Al Viro3e577a82006-12-06 18:41:45 +00001589static void do_softint(struct work_struct *ugly_api)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
Al Viro3e577a82006-12-06 18:41:45 +00001591 struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 struct tty_struct *tty;
1593
1594 if(!(tty = port->tty))
1595 return;
1596
Jiri Slabyb963a842007-02-10 01:44:55 -08001597 if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599}
1600
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001601static const struct tty_operations riscom_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 .open = rc_open,
1603 .close = rc_close,
1604 .write = rc_write,
1605 .put_char = rc_put_char,
1606 .flush_chars = rc_flush_chars,
1607 .write_room = rc_write_room,
1608 .chars_in_buffer = rc_chars_in_buffer,
1609 .flush_buffer = rc_flush_buffer,
1610 .ioctl = rc_ioctl,
1611 .throttle = rc_throttle,
1612 .unthrottle = rc_unthrottle,
1613 .set_termios = rc_set_termios,
1614 .stop = rc_stop,
1615 .start = rc_start,
1616 .hangup = rc_hangup,
1617 .tiocmget = rc_tiocmget,
1618 .tiocmset = rc_tiocmset,
1619};
1620
Jiri Slaby1386a822008-02-07 00:16:36 -08001621static int __init rc_init_drivers(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
1623 int error;
1624 int i;
1625
1626 riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
1627 if (!riscom_driver)
1628 return -ENOMEM;
1629
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 riscom_driver->owner = THIS_MODULE;
1631 riscom_driver->name = "ttyL";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 riscom_driver->major = RISCOM8_NORMAL_MAJOR;
1633 riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
1634 riscom_driver->subtype = SERIAL_TYPE_NORMAL;
1635 riscom_driver->init_termios = tty_std_termios;
1636 riscom_driver->init_termios.c_cflag =
1637 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08001638 riscom_driver->init_termios.c_ispeed = 9600;
1639 riscom_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 riscom_driver->flags = TTY_DRIVER_REAL_RAW;
1641 tty_set_operations(riscom_driver, &riscom_ops);
1642 if ((error = tty_register_driver(riscom_driver))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 put_tty_driver(riscom_driver);
1644 printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
1645 "error = %d\n",
1646 error);
1647 return 1;
1648 }
1649
1650 memset(rc_port, 0, sizeof(rc_port));
1651 for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
1652 rc_port[i].magic = RISCOM8_MAGIC;
Al Viro3e577a82006-12-06 18:41:45 +00001653 INIT_WORK(&rc_port[i].tqueue, do_softint);
1654 INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 rc_port[i].close_delay = 50 * HZ/100;
1656 rc_port[i].closing_wait = 3000 * HZ/100;
1657 init_waitqueue_head(&rc_port[i].open_wait);
1658 init_waitqueue_head(&rc_port[i].close_wait);
1659 }
1660
1661 return 0;
1662}
1663
1664static void rc_release_drivers(void)
1665{
1666 unsigned long flags;
1667
Jeff Garzikd9afa432008-02-06 01:36:11 -08001668 spin_lock_irqsave(&riscom_lock, flags);
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 tty_unregister_driver(riscom_driver);
1671 put_tty_driver(riscom_driver);
Jeff Garzikd9afa432008-02-06 01:36:11 -08001672
1673 spin_unlock_irqrestore(&riscom_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674}
1675
1676#ifndef MODULE
1677/*
1678 * Called at boot time.
1679 *
1680 * You can specify IO base for up to RC_NBOARD cards,
1681 * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
1682 * Note that there will be no probing at default
1683 * addresses in this case.
1684 *
1685 */
1686static int __init riscom8_setup(char *str)
1687{
1688 int ints[RC_NBOARD];
1689 int i;
1690
1691 str = get_options(str, ARRAY_SIZE(ints), ints);
1692
1693 for (i = 0; i < RC_NBOARD; i++) {
1694 if (i < ints[0])
1695 rc_board[i].base = ints[i+1];
1696 else
1697 rc_board[i].base = 0;
1698 }
1699 return 1;
1700}
1701
1702__setup("riscom8=", riscom8_setup);
1703#endif
1704
1705static char banner[] __initdata =
1706 KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
1707 "1994-1996.\n";
1708static char no_boards_msg[] __initdata =
1709 KERN_INFO "rc: No RISCom/8 boards detected.\n";
1710
1711/*
1712 * This routine must be called by kernel at boot time
1713 */
1714static int __init riscom8_init(void)
1715{
1716 int i;
1717 int found = 0;
1718
1719 printk(banner);
1720
1721 if (rc_init_drivers())
1722 return -EIO;
1723
1724 for (i = 0; i < RC_NBOARD; i++)
1725 if (rc_board[i].base && !rc_probe(&rc_board[i]))
1726 found++;
1727
1728 if (!found) {
1729 rc_release_drivers();
1730 printk(no_boards_msg);
1731 return -EIO;
1732 }
1733 return 0;
1734}
1735
1736#ifdef MODULE
1737static int iobase;
1738static int iobase1;
1739static int iobase2;
1740static int iobase3;
Rusty Russell8d3b33f2006-03-25 03:07:05 -08001741module_param(iobase, int, 0);
1742module_param(iobase1, int, 0);
1743module_param(iobase2, int, 0);
1744module_param(iobase3, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
1746MODULE_LICENSE("GPL");
1747#endif /* MODULE */
1748
1749/*
1750 * You can setup up to 4 boards (current value of RC_NBOARD)
1751 * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
1752 *
1753 */
1754static int __init riscom8_init_module (void)
1755{
1756#ifdef MODULE
1757 int i;
1758
1759 if (iobase || iobase1 || iobase2 || iobase3) {
1760 for(i = 0; i < RC_NBOARD; i++)
1761 rc_board[0].base = 0;
1762 }
1763
1764 if (iobase)
1765 rc_board[0].base = iobase;
1766 if (iobase1)
1767 rc_board[1].base = iobase1;
1768 if (iobase2)
1769 rc_board[2].base = iobase2;
1770 if (iobase3)
1771 rc_board[3].base = iobase3;
1772#endif /* MODULE */
1773
1774 return riscom8_init();
1775}
1776
1777static void __exit riscom8_exit_module (void)
1778{
1779 int i;
1780
1781 rc_release_drivers();
1782 for (i = 0; i < RC_NBOARD; i++)
1783 if (rc_board[i].flags & RC_BOARD_PRESENT)
1784 rc_release_io_range(&rc_board[i]);
1785
1786}
1787
1788module_init(riscom8_init_module);
1789module_exit(riscom8_exit_module);
1790