]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/staging/tty/specialix.c
Fix common misspellings
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / tty / specialix.c
CommitLineData
1da177e4
LT
1/*
2 * specialix.c -- specialix IO8+ multiport serial driver.
3 *
4 * Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl)
5 * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com)
6 *
7 * Specialix pays for the development and support of this driver.
8 * Please DO contact io8-linux@specialix.co.uk if you require
9 * support. But please read the documentation (specialix.txt)
10 * first.
11 *
25985edc 12 * This driver was developed in the BitWizard linux device
1da177e4
LT
13 * driver service. If you require a linux device driver for your
14 * product, please contact devices@BitWizard.nl for a quote.
15 *
16 * This code is firmly based on the riscom/8 serial driver,
17 * written by Dmitry Gorodchanin. The specialix IO8+ card
18 * programming information was obtained from the CL-CD1865 Data
19 * Book, and Specialix document number 6200059: IO8+ Hardware
20 * Functional Specification.
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License as
24 * published by the Free Software Foundation; either version 2 of
25 * the License, or (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be
28 * useful, but WITHOUT ANY WARRANTY; without even the implied
29 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
30 * PURPOSE. See the GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public
33 * License along with this program; if not, write to the Free
34 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
35 * USA.
36 *
37 * Revision history:
38 *
39 * Revision 1.0: April 1st 1997.
40 * Initial release for alpha testing.
d61780c0
JG
41 * Revision 1.1: April 14th 1997.
42 * Incorporated Richard Hudsons suggestions,
1da177e4
LT
43 * removed some debugging printk's.
44 * Revision 1.2: April 15th 1997.
45 * Ported to 2.1.x kernels.
d61780c0
JG
46 * Revision 1.3: April 17th 1997
47 * Backported to 2.0. (Compatibility macros).
1da177e4 48 * Revision 1.4: April 18th 1997
d61780c0
JG
49 * Fixed DTR/RTS bug that caused the card to indicate
50 * "don't send data" to a modem after the password prompt.
1da177e4
LT
51 * Fixed bug for premature (fake) interrupts.
52 * Revision 1.5: April 19th 1997
d61780c0 53 * fixed a minor typo in the header file, cleanup a little.
1da177e4
LT
54 * performance warnings are now MAXed at once per minute.
55 * Revision 1.6: May 23 1997
56 * Changed the specialix=... format to include interrupt.
57 * Revision 1.7: May 27 1997
58 * Made many more debug printk's a compile time option.
59 * Revision 1.8: Jul 1 1997
60 * port to linux-2.1.43 kernel.
61 * Revision 1.9: Oct 9 1998
62 * Added stuff for the IO8+/PCI version.
d61780c0
JG
63 * Revision 1.10: Oct 22 1999 / Jan 21 2000.
64 * Added stuff for setserial.
1da177e4 65 * Nicolas Mailhot (Nicolas.Mailhot@email.enst.fr)
d61780c0 66 *
1da177e4
LT
67 */
68
69#define VERSION "1.11"
70
71
72/*
73 * There is a bunch of documentation about the card, jumpers, config
74 * settings, restrictions, cables, device names and numbers in
31c00fc1 75 * Documentation/serial/specialix.txt
1da177e4
LT
76 */
77
1da177e4
LT
78#include <linux/module.h>
79
a72492bd 80#include <linux/io.h>
1da177e4
LT
81#include <linux/kernel.h>
82#include <linux/sched.h>
83#include <linux/ioport.h>
84#include <linux/interrupt.h>
85#include <linux/errno.h>
86#include <linux/tty.h>
33f0f88f 87#include <linux/tty_flip.h>
1da177e4
LT
88#include <linux/mm.h>
89#include <linux/serial.h>
90#include <linux/fcntl.h>
91#include <linux/major.h>
92#include <linux/delay.h>
1da177e4
LT
93#include <linux/pci.h>
94#include <linux/init.h>
a72492bd 95#include <linux/uaccess.h>
5a0e3ad6 96#include <linux/gfp.h>
1da177e4
LT
97
98#include "specialix_io8.h"
99#include "cd1865.h"
100
101
102/*
103 This driver can spew a whole lot of debugging output at you. If you
104 need maximum performance, you should disable the DEBUG define. To
105 aid in debugging in the field, I'm leaving the compile-time debug
106 features enabled, and disable them "runtime". That allows me to
107 instruct people with problems to enable debugging without requiring
108 them to recompile...
109*/
110#define DEBUG
111
112static int sx_debug;
113static int sx_rxfifo = SPECIALIX_RXFIFO;
d2fbd0f2 114static int sx_rtscts;
1da177e4
LT
115
116#ifdef DEBUG
a72492bd 117#define dprintk(f, str...) if (sx_debug & f) printk(str)
1da177e4
LT
118#else
119#define dprintk(f, str...) /* nothing */
120#endif
121
122#define SX_DEBUG_FLOW 0x0001
123#define SX_DEBUG_DATA 0x0002
124#define SX_DEBUG_PROBE 0x0004
125#define SX_DEBUG_CHAN 0x0008
126#define SX_DEBUG_INIT 0x0010
127#define SX_DEBUG_RX 0x0020
128#define SX_DEBUG_TX 0x0040
129#define SX_DEBUG_IRQ 0x0080
130#define SX_DEBUG_OPEN 0x0100
131#define SX_DEBUG_TERMIOS 0x0200
132#define SX_DEBUG_SIGNALS 0x0400
133#define SX_DEBUG_FIFO 0x0800
134
135
a72492bd
AC
136#define func_enter() dprintk(SX_DEBUG_FLOW, "io8: enter %s\n", __func__)
137#define func_exit() dprintk(SX_DEBUG_FLOW, "io8: exit %s\n", __func__)
1da177e4 138
1da177e4
LT
139
140/* Configurable options: */
141
142/* Am I paranoid or not ? ;-) */
143#define SPECIALIX_PARANOIA_CHECK
144
d61780c0 145/*
1da177e4
LT
146 * The following defines are mostly for testing purposes. But if you need
147 * some nice reporting in your syslog, you can define them also.
148 */
149#undef SX_REPORT_FIFO
150#undef SX_REPORT_OVERRUN
151
152
153
1da177e4
LT
154
155#define SPECIALIX_LEGAL_FLAGS \
156 (ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \
157 ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \
158 ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
159
1da177e4 160static struct tty_driver *specialix_driver;
1da177e4 161
1da177e4
LT
162static struct specialix_board sx_board[SX_NBOARD] = {
163 { 0, SX_IOBASE1, 9, },
164 { 0, SX_IOBASE2, 11, },
165 { 0, SX_IOBASE3, 12, },
166 { 0, SX_IOBASE4, 15, },
167};
168
169static struct specialix_port sx_port[SX_NBOARD * SX_NPORT];
170
171
d2fbd0f2 172static int sx_paranoia_check(struct specialix_port const *port,
1da177e4
LT
173 char *name, const char *routine)
174{
175#ifdef SPECIALIX_PARANOIA_CHECK
a72492bd
AC
176 static const char *badmagic = KERN_ERR
177 "sx: Warning: bad specialix port magic number for device %s in %s\n";
178 static const char *badinfo = KERN_ERR
179 "sx: Warning: null specialix port for device %s in %s\n";
d61780c0 180
1da177e4
LT
181 if (!port) {
182 printk(badinfo, name, routine);
183 return 1;
184 }
185 if (port->magic != SPECIALIX_MAGIC) {
186 printk(badmagic, name, routine);
187 return 1;
188 }
189#endif
190 return 0;
191}
192
193
194/*
d61780c0 195 *
1da177e4 196 * Service functions for specialix IO8+ driver.
d61780c0 197 *
1da177e4
LT
198 */
199
200/* Get board number from pointer */
a72492bd 201static inline int board_No(struct specialix_board *bp)
1da177e4
LT
202{
203 return bp - sx_board;
204}
205
206
207/* Get port number from pointer */
a72492bd 208static inline int port_No(struct specialix_port const *port)
1da177e4 209{
d61780c0 210 return SX_PORT(port - sx_port);
1da177e4
LT
211}
212
213
214/* Get pointer to board from pointer to port */
a72492bd
AC
215static inline struct specialix_board *port_Board(
216 struct specialix_port const *port)
1da177e4
LT
217{
218 return &sx_board[SX_BOARD(port - sx_port)];
219}
220
221
222/* Input Byte from CL CD186x register */
a72492bd
AC
223static inline unsigned char sx_in(struct specialix_board *bp,
224 unsigned short reg)
1da177e4
LT
225{
226 bp->reg = reg | 0x80;
a72492bd
AC
227 outb(reg | 0x80, bp->base + SX_ADDR_REG);
228 return inb(bp->base + SX_DATA_REG);
1da177e4
LT
229}
230
231
232/* Output Byte to CL CD186x register */
a72492bd 233static inline void sx_out(struct specialix_board *bp, unsigned short reg,
1da177e4
LT
234 unsigned char val)
235{
236 bp->reg = reg | 0x80;
a72492bd
AC
237 outb(reg | 0x80, bp->base + SX_ADDR_REG);
238 outb(val, bp->base + SX_DATA_REG);
1da177e4
LT
239}
240
241
242/* Input Byte from CL CD186x register */
a72492bd
AC
243static inline unsigned char sx_in_off(struct specialix_board *bp,
244 unsigned short reg)
1da177e4
LT
245{
246 bp->reg = reg;
a72492bd
AC
247 outb(reg, bp->base + SX_ADDR_REG);
248 return inb(bp->base + SX_DATA_REG);
1da177e4
LT
249}
250
251
252/* Output Byte to CL CD186x register */
a72492bd
AC
253static inline void sx_out_off(struct specialix_board *bp,
254 unsigned short reg, unsigned char val)
1da177e4
LT
255{
256 bp->reg = reg;
a72492bd
AC
257 outb(reg, bp->base + SX_ADDR_REG);
258 outb(val, bp->base + SX_DATA_REG);
1da177e4
LT
259}
260
261
262/* Wait for Channel Command Register ready */
d2fbd0f2 263static void sx_wait_CCR(struct specialix_board *bp)
1da177e4
LT
264{
265 unsigned long delay, flags;
266 unsigned char ccr;
267
268 for (delay = SX_CCR_TIMEOUT; delay; delay--) {
269 spin_lock_irqsave(&bp->lock, flags);
270 ccr = sx_in(bp, CD186x_CCR);
271 spin_unlock_irqrestore(&bp->lock, flags);
272 if (!ccr)
273 return;
a72492bd 274 udelay(1);
1da177e4 275 }
d61780c0 276
1da177e4
LT
277 printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
278}
279
280
281/* Wait for Channel Command Register ready */
d2fbd0f2 282static void sx_wait_CCR_off(struct specialix_board *bp)
1da177e4
LT
283{
284 unsigned long delay;
285 unsigned char crr;
286 unsigned long flags;
287
288 for (delay = SX_CCR_TIMEOUT; delay; delay--) {
289 spin_lock_irqsave(&bp->lock, flags);
290 crr = sx_in_off(bp, CD186x_CCR);
291 spin_unlock_irqrestore(&bp->lock, flags);
292 if (!crr)
293 return;
a72492bd 294 udelay(1);
1da177e4 295 }
d61780c0 296
1da177e4
LT
297 printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
298}
299
300
301/*
302 * specialix IO8+ IO range functions.
303 */
304
d2fbd0f2 305static int sx_request_io_range(struct specialix_board *bp)
1da177e4 306{
d61780c0
JG
307 return request_region(bp->base,
308 bp->flags & SX_BOARD_IS_PCI ? SX_PCI_IO_SPACE : SX_IO_SPACE,
309 "specialix IO8+") == NULL;
1da177e4
LT
310}
311
312
d2fbd0f2 313static void sx_release_io_range(struct specialix_board *bp)
1da177e4 314{
a72492bd
AC
315 release_region(bp->base, bp->flags & SX_BOARD_IS_PCI ?
316 SX_PCI_IO_SPACE : SX_IO_SPACE);
1da177e4
LT
317}
318
d61780c0 319
1da177e4 320/* Set the IRQ using the RTS lines that run to the PAL on the board.... */
a72492bd 321static int sx_set_irq(struct specialix_board *bp)
1da177e4
LT
322{
323 int virq;
324 int i;
325 unsigned long flags;
326
d61780c0 327 if (bp->flags & SX_BOARD_IS_PCI)
1da177e4
LT
328 return 1;
329 switch (bp->irq) {
330 /* In the same order as in the docs... */
a72492bd
AC
331 case 15:
332 virq = 0;
333 break;
334 case 12:
335 virq = 1;
336 break;
337 case 11:
338 virq = 2;
339 break;
340 case 9:
341 virq = 3;
342 break;
343 default:printk(KERN_ERR
344 "Speclialix: cannot set irq to %d.\n", bp->irq);
345 return 0;
1da177e4
LT
346 }
347 spin_lock_irqsave(&bp->lock, flags);
a72492bd 348 for (i = 0; i < 2; i++) {
1da177e4
LT
349 sx_out(bp, CD186x_CAR, i);
350 sx_out(bp, CD186x_MSVRTS, ((virq >> i) & 0x1)? MSVR_RTS:0);
351 }
352 spin_unlock_irqrestore(&bp->lock, flags);
353 return 1;
354}
355
356
357/* Reset and setup CD186x chip */
a72492bd 358static int sx_init_CD186x(struct specialix_board *bp)
1da177e4
LT
359{
360 unsigned long flags;
361 int scaler;
362 int rv = 1;
363
364 func_enter();
365 sx_wait_CCR_off(bp); /* Wait for CCR ready */
366 spin_lock_irqsave(&bp->lock, flags);
367 sx_out_off(bp, CD186x_CCR, CCR_HARDRESET); /* Reset CD186x chip */
368 spin_unlock_irqrestore(&bp->lock, flags);
3e98cee7 369 msleep(50); /* Delay 0.05 sec */
1da177e4
LT
370 spin_lock_irqsave(&bp->lock, flags);
371 sx_out_off(bp, CD186x_GIVR, SX_ID); /* Set ID for this chip */
372 sx_out_off(bp, CD186x_GICR, 0); /* Clear all bits */
373 sx_out_off(bp, CD186x_PILR1, SX_ACK_MINT); /* Prio for modem intr */
374 sx_out_off(bp, CD186x_PILR2, SX_ACK_TINT); /* Prio for transmitter intr */
375 sx_out_off(bp, CD186x_PILR3, SX_ACK_RINT); /* Prio for receiver intr */
376 /* Set RegAckEn */
a72492bd 377 sx_out_off(bp, CD186x_SRCR, sx_in(bp, CD186x_SRCR) | SRCR_REGACKEN);
d61780c0 378
1da177e4
LT
379 /* Setting up prescaler. We need 4 ticks per 1 ms */
380 scaler = SX_OSCFREQ/SPECIALIX_TPS;
381
382 sx_out_off(bp, CD186x_PPRH, scaler >> 8);
383 sx_out_off(bp, CD186x_PPRL, scaler & 0xff);
384 spin_unlock_irqrestore(&bp->lock, flags);
385
a72492bd 386 if (!sx_set_irq(bp)) {
1da177e4 387 /* Figure out how to pass this along... */
a72492bd 388 printk(KERN_ERR "Cannot set irq to %d.\n", bp->irq);
1da177e4
LT
389 rv = 0;
390 }
391
392 func_exit();
393 return rv;
394}
395
396
a72492bd 397static int read_cross_byte(struct specialix_board *bp, int reg, int bit)
1da177e4
LT
398{
399 int i;
400 int t;
401 unsigned long flags;
402
403 spin_lock_irqsave(&bp->lock, flags);
a72492bd
AC
404 for (i = 0, t = 0; i < 8; i++) {
405 sx_out_off(bp, CD186x_CAR, i);
406 if (sx_in_off(bp, reg) & bit)
1da177e4
LT
407 t |= 1 << i;
408 }
409 spin_unlock_irqrestore(&bp->lock, flags);
410
411 return t;
412}
413
414
1da177e4
LT
415/* Main probing routine, also sets irq. */
416static int sx_probe(struct specialix_board *bp)
417{
418 unsigned char val1, val2;
1da177e4
LT
419 int rev;
420 int chip;
421
422 func_enter();
423
d61780c0 424 if (sx_request_io_range(bp)) {
1da177e4
LT
425 func_exit();
426 return 1;
427 }
428
429 /* Are the I/O ports here ? */
430 sx_out_off(bp, CD186x_PPRL, 0x5a);
d2fbd0f2 431 udelay(1);
1da177e4
LT
432 val1 = sx_in_off(bp, CD186x_PPRL);
433
434 sx_out_off(bp, CD186x_PPRL, 0xa5);
d2fbd0f2 435 udelay(1);
1da177e4
LT
436 val2 = sx_in_off(bp, CD186x_PPRL);
437
d61780c0 438
d2fbd0f2 439 if (val1 != 0x5a || val2 != 0xa5) {
a72492bd
AC
440 printk(KERN_INFO
441 "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
442 board_No(bp), bp->base);
d61780c0 443 sx_release_io_range(bp);
1da177e4
LT
444 func_exit();
445 return 1;
446 }
447
d61780c0 448 /* Check the DSR lines that Specialix uses as board
1da177e4 449 identification */
a72492bd
AC
450 val1 = read_cross_byte(bp, CD186x_MSVR, MSVR_DSR);
451 val2 = read_cross_byte(bp, CD186x_MSVR, MSVR_RTS);
452 dprintk(SX_DEBUG_INIT,
453 "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
454 board_No(bp), val1, val2);
1da177e4
LT
455
456 /* They managed to switch the bit order between the docs and
457 the IO8+ card. The new PCI card now conforms to old docs.
458 They changed the PCI docs to reflect the situation on the
459 old card. */
460 val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
461 if (val1 != val2) {
a72492bd
AC
462 printk(KERN_INFO
463 "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
1da177e4 464 board_No(bp), val2, bp->base, val1);
d61780c0 465 sx_release_io_range(bp);
1da177e4
LT
466 func_exit();
467 return 1;
468 }
469
470
1da177e4
LT
471 /* Reset CD186x again */
472 if (!sx_init_CD186x(bp)) {
d61780c0 473 sx_release_io_range(bp);
1da177e4 474 func_exit();
d61780c0 475 return 1;
1da177e4
LT
476 }
477
478 sx_request_io_range(bp);
479 bp->flags |= SX_BOARD_PRESENT;
d61780c0 480
1da177e4 481 /* Chip revcode pkgtype
a72492bd 482 GFRCR SRCR bit 7
1da177e4
LT
483 CD180 rev B 0x81 0
484 CD180 rev C 0x82 0
485 CD1864 rev A 0x82 1
d61780c0 486 CD1865 rev A 0x83 1 -- Do not use!!! Does not work.
1da177e4
LT
487 CD1865 rev B 0x84 1
488 -- Thanks to Gwen Wang, Cirrus Logic.
489 */
490
491 switch (sx_in_off(bp, CD186x_GFRCR)) {
a72492bd
AC
492 case 0x82:
493 chip = 1864;
494 rev = 'A';
495 break;
496 case 0x83:
497 chip = 1865;
498 rev = 'A';
499 break;
500 case 0x84:
501 chip = 1865;
502 rev = 'B';
503 break;
504 case 0x85:
505 chip = 1865;
506 rev = 'C';
507 break; /* Does not exist at this time */
508 default:
509 chip = -1;
510 rev = 'x';
1da177e4
LT
511 }
512
a72492bd 513 dprintk(SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR));
1da177e4 514
a72492bd
AC
515 printk(KERN_INFO
516 "sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",
517 board_No(bp), bp->base, bp->irq, chip, rev);
1da177e4
LT
518
519 func_exit();
520 return 0;
521}
522
d61780c0
JG
523/*
524 *
1da177e4
LT
525 * Interrupt processing routines.
526 * */
527
d2fbd0f2 528static struct specialix_port *sx_get_port(struct specialix_board *bp,
a72492bd 529 unsigned char const *what)
1da177e4
LT
530{
531 unsigned char channel;
a72492bd 532 struct specialix_port *port = NULL;
1da177e4
LT
533
534 channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;
a72492bd 535 dprintk(SX_DEBUG_CHAN, "channel: %d\n", channel);
1da177e4
LT
536 if (channel < CD186x_NCH) {
537 port = &sx_port[board_No(bp) * SX_NPORT + channel];
a72492bd
AC
538 dprintk(SX_DEBUG_CHAN, "port: %d %p flags: 0x%lx\n",
539 board_No(bp) * SX_NPORT + channel, port,
540 port->port.flags & ASYNC_INITIALIZED);
1da177e4 541
44b7d1b3 542 if (port->port.flags & ASYNC_INITIALIZED) {
a72492bd 543 dprintk(SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
1da177e4
LT
544 func_exit();
545 return port;
546 }
547 }
d61780c0 548 printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n",
1da177e4
LT
549 board_No(bp), what, channel);
550 return NULL;
551}
552
553
d2fbd0f2 554static void sx_receive_exc(struct specialix_board *bp)
1da177e4
LT
555{
556 struct specialix_port *port;
557 struct tty_struct *tty;
558 unsigned char status;
33f0f88f 559 unsigned char ch, flag;
1da177e4
LT
560
561 func_enter();
562
563 port = sx_get_port(bp, "Receive");
564 if (!port) {
a72492bd 565 dprintk(SX_DEBUG_RX, "Hmm, couldn't find port.\n");
1da177e4
LT
566 func_exit();
567 return;
568 }
44b7d1b3 569 tty = port->port.tty;
d61780c0 570
1da177e4
LT
571 status = sx_in(bp, CD186x_RCSR);
572
a72492bd 573 dprintk(SX_DEBUG_RX, "status: 0x%x\n", status);
1da177e4
LT
574 if (status & RCSR_OE) {
575 port->overrun++;
a72492bd
AC
576 dprintk(SX_DEBUG_FIFO,
577 "sx%d: port %d: Overrun. Total %ld overruns.\n",
578 board_No(bp), port_No(port), port->overrun);
1da177e4
LT
579 }
580 status &= port->mark_mask;
581
582 /* This flip buffer check needs to be below the reading of the
583 status register to reset the chip's IRQ.... */
33f0f88f 584 if (tty_buffer_request_room(tty, 1) == 0) {
a72492bd
AC
585 dprintk(SX_DEBUG_FIFO,
586 "sx%d: port %d: Working around flip buffer overflow.\n",
587 board_No(bp), port_No(port));
1da177e4
LT
588 func_exit();
589 return;
590 }
591
592 ch = sx_in(bp, CD186x_RDR);
593 if (!status) {
594 func_exit();
595 return;
596 }
597 if (status & RCSR_TOUT) {
a72492bd
AC
598 printk(KERN_INFO
599 "sx%d: port %d: Receiver timeout. Hardware problems ?\n",
600 board_No(bp), port_No(port));
1da177e4
LT
601 func_exit();
602 return;
d61780c0 603
1da177e4
LT
604 } else if (status & RCSR_BREAK) {
605 dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
606 board_No(bp), port_No(port));
33f0f88f 607 flag = TTY_BREAK;
44b7d1b3 608 if (port->port.flags & ASYNC_SAK)
1da177e4 609 do_SAK(tty);
d61780c0
JG
610
611 } else if (status & RCSR_PE)
33f0f88f 612 flag = TTY_PARITY;
d61780c0
JG
613
614 else if (status & RCSR_FE)
33f0f88f 615 flag = TTY_FRAME;
d61780c0 616
1da177e4 617 else if (status & RCSR_OE)
33f0f88f 618 flag = TTY_OVERRUN;
d61780c0 619
1da177e4 620 else
33f0f88f 621 flag = TTY_NORMAL;
1da177e4 622
a72492bd 623 if (tty_insert_flip_char(tty, ch, flag))
33f0f88f 624 tty_flip_buffer_push(tty);
1da177e4
LT
625 func_exit();
626}
627
628
d2fbd0f2 629static void sx_receive(struct specialix_board *bp)
1da177e4
LT
630{
631 struct specialix_port *port;
632 struct tty_struct *tty;
633 unsigned char count;
634
635 func_enter();
d61780c0 636
a72492bd
AC
637 port = sx_get_port(bp, "Receive");
638 if (port == NULL) {
639 dprintk(SX_DEBUG_RX, "Hmm, couldn't find port.\n");
1da177e4
LT
640 func_exit();
641 return;
642 }
44b7d1b3 643 tty = port->port.tty;
d61780c0 644
1da177e4 645 count = sx_in(bp, CD186x_RDCR);
a72492bd 646 dprintk(SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
1da177e4 647 port->hits[count > 8 ? 9 : count]++;
d61780c0 648
33f0f88f
AC
649 while (count--)
650 tty_insert_flip_char(tty, sx_in(bp, CD186x_RDR), TTY_NORMAL);
651 tty_flip_buffer_push(tty);
1da177e4
LT
652 func_exit();
653}
654
655
d2fbd0f2 656static void sx_transmit(struct specialix_board *bp)
1da177e4
LT
657{
658 struct specialix_port *port;
659 struct tty_struct *tty;
660 unsigned char count;
661
662 func_enter();
a72492bd
AC
663 port = sx_get_port(bp, "Transmit");
664 if (port == NULL) {
1da177e4
LT
665 func_exit();
666 return;
667 }
a72492bd 668 dprintk(SX_DEBUG_TX, "port: %p\n", port);
44b7d1b3 669 tty = port->port.tty;
d61780c0 670
1da177e4
LT
671 if (port->IER & IER_TXEMPTY) {
672 /* FIFO drained */
673 sx_out(bp, CD186x_CAR, port_No(port));
674 port->IER &= ~IER_TXEMPTY;
675 sx_out(bp, CD186x_IER, port->IER);
676 func_exit();
677 return;
678 }
d61780c0 679
1da177e4
LT
680 if ((port->xmit_cnt <= 0 && !port->break_length)
681 || tty->stopped || tty->hw_stopped) {
682 sx_out(bp, CD186x_CAR, port_No(port));
683 port->IER &= ~IER_TXRDY;
684 sx_out(bp, CD186x_IER, port->IER);
685 func_exit();
686 return;
687 }
d61780c0 688
1da177e4
LT
689 if (port->break_length) {
690 if (port->break_length > 0) {
691 if (port->COR2 & COR2_ETC) {
692 sx_out(bp, CD186x_TDR, CD186x_C_ESC);
693 sx_out(bp, CD186x_TDR, CD186x_C_SBRK);
694 port->COR2 &= ~COR2_ETC;
695 }
696 count = min_t(int, port->break_length, 0xff);
697 sx_out(bp, CD186x_TDR, CD186x_C_ESC);
698 sx_out(bp, CD186x_TDR, CD186x_C_DELAY);
699 sx_out(bp, CD186x_TDR, count);
a72492bd
AC
700 port->break_length -= count;
701 if (port->break_length == 0)
1da177e4
LT
702 port->break_length--;
703 } else {
704 sx_out(bp, CD186x_TDR, CD186x_C_ESC);
705 sx_out(bp, CD186x_TDR, CD186x_C_EBRK);
706 sx_out(bp, CD186x_COR2, port->COR2);
707 sx_wait_CCR(bp);
708 sx_out(bp, CD186x_CCR, CCR_CORCHG2);
709 port->break_length = 0;
710 }
711
712 func_exit();
713 return;
714 }
d61780c0 715
1da177e4
LT
716 count = CD186x_NFIFO;
717 do {
718 sx_out(bp, CD186x_TDR, port->xmit_buf[port->xmit_tail++]);
719 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
720 if (--port->xmit_cnt <= 0)
721 break;
722 } while (--count > 0);
d61780c0 723
1da177e4
LT
724 if (port->xmit_cnt <= 0) {
725 sx_out(bp, CD186x_CAR, port_No(port));
726 port->IER &= ~IER_TXRDY;
727 sx_out(bp, CD186x_IER, port->IER);
728 }
729 if (port->xmit_cnt <= port->wakeup_chars)
a72492bd 730 tty_wakeup(tty);
1da177e4
LT
731
732 func_exit();
733}
734
735
d2fbd0f2 736static void sx_check_modem(struct specialix_board *bp)
1da177e4
LT
737{
738 struct specialix_port *port;
739 struct tty_struct *tty;
740 unsigned char mcr;
741 int msvr_cd;
742
a72492bd
AC
743 dprintk(SX_DEBUG_SIGNALS, "Modem intr. ");
744 port = sx_get_port(bp, "Modem");
745 if (port == NULL)
1da177e4 746 return;
d61780c0 747
44b7d1b3 748 tty = port->port.tty;
d61780c0 749
1da177e4 750 mcr = sx_in(bp, CD186x_MCR);
1da177e4
LT
751
752 if ((mcr & MCR_CDCHG)) {
a72492bd 753 dprintk(SX_DEBUG_SIGNALS, "CD just changed... ");
1da177e4
LT
754 msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
755 if (msvr_cd) {
a72492bd 756 dprintk(SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
44b7d1b3 757 wake_up_interruptible(&port->port.open_wait);
1da177e4 758 } else {
a72492bd 759 dprintk(SX_DEBUG_SIGNALS, "Sending HUP.\n");
d0d4e1c0 760 tty_hangup(tty);
1da177e4
LT
761 }
762 }
d61780c0 763
1da177e4
LT
764#ifdef SPECIALIX_BRAIN_DAMAGED_CTS
765 if (mcr & MCR_CTSCHG) {
766 if (sx_in(bp, CD186x_MSVR) & MSVR_CTS) {
767 tty->hw_stopped = 0;
768 port->IER |= IER_TXRDY;
769 if (port->xmit_cnt <= port->wakeup_chars)
d0d4e1c0 770 tty_wakeup(tty);
1da177e4
LT
771 } else {
772 tty->hw_stopped = 1;
773 port->IER &= ~IER_TXRDY;
774 }
775 sx_out(bp, CD186x_IER, port->IER);
776 }
777 if (mcr & MCR_DSSXHG) {
778 if (sx_in(bp, CD186x_MSVR) & MSVR_DSR) {
779 tty->hw_stopped = 0;
780 port->IER |= IER_TXRDY;
781 if (port->xmit_cnt <= port->wakeup_chars)
d0d4e1c0 782 tty_wakeup(tty);
1da177e4
LT
783 } else {
784 tty->hw_stopped = 1;
785 port->IER &= ~IER_TXRDY;
786 }
787 sx_out(bp, CD186x_IER, port->IER);
788 }
789#endif /* SPECIALIX_BRAIN_DAMAGED_CTS */
d61780c0 790
1da177e4
LT
791 /* Clear change bits */
792 sx_out(bp, CD186x_MCR, 0);
793}
794
795
796/* The main interrupt processing routine */
a6f97b29 797static irqreturn_t sx_interrupt(int dummy, void *dev_id)
1da177e4
LT
798{
799 unsigned char status;
800 unsigned char ack;
a6f97b29 801 struct specialix_board *bp = dev_id;
1da177e4
LT
802 unsigned long loop = 0;
803 int saved_reg;
804 unsigned long flags;
805
806 func_enter();
807
1da177e4
LT
808 spin_lock_irqsave(&bp->lock, flags);
809
a72492bd
AC
810 dprintk(SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__,
811 port_No(sx_get_port(bp, "INT")),
812 SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
c7bec5ab 813 if (!(bp->flags & SX_BOARD_ACTIVE)) {
a72492bd
AC
814 dprintk(SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n",
815 bp->irq);
1da177e4
LT
816 spin_unlock_irqrestore(&bp->lock, flags);
817 func_exit();
818 return IRQ_NONE;
819 }
820
821 saved_reg = bp->reg;
822
a72492bd
AC
823 while (++loop < 16) {
824 status = sx_in(bp, CD186x_SRSR) &
825 (SRSR_RREQint | SRSR_TREQint | SRSR_MREQint);
826 if (status == 0)
827 break;
1da177e4
LT
828 if (status & SRSR_RREQint) {
829 ack = sx_in(bp, CD186x_RRAR);
830
831 if (ack == (SX_ID | GIVR_IT_RCV))
832 sx_receive(bp);
833 else if (ack == (SX_ID | GIVR_IT_REXC))
834 sx_receive_exc(bp);
835 else
a72492bd
AC
836 printk(KERN_ERR
837 "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
838 board_No(bp), status, ack);
d61780c0 839
1da177e4
LT
840 } else if (status & SRSR_TREQint) {
841 ack = sx_in(bp, CD186x_TRAR);
842
843 if (ack == (SX_ID | GIVR_IT_TX))
844 sx_transmit(bp);
845 else
846 printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",
a72492bd
AC
847 board_No(bp), status, ack,
848 port_No(sx_get_port(bp, "Int")));
1da177e4
LT
849 } else if (status & SRSR_MREQint) {
850 ack = sx_in(bp, CD186x_MRAR);
851
d61780c0 852 if (ack == (SX_ID | GIVR_IT_MODEM))
1da177e4
LT
853 sx_check_modem(bp);
854 else
a72492bd
AC
855 printk(KERN_ERR
856 "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
1da177e4 857 board_No(bp), status, ack);
d61780c0
JG
858
859 }
1da177e4
LT
860
861 sx_out(bp, CD186x_EOIR, 0); /* Mark end of interrupt */
862 }
863 bp->reg = saved_reg;
a72492bd 864 outb(bp->reg, bp->base + SX_ADDR_REG);
1da177e4
LT
865 spin_unlock_irqrestore(&bp->lock, flags);
866 func_exit();
867 return IRQ_HANDLED;
868}
869
870
871/*
872 * Routines for open & close processing.
873 */
874
a72492bd 875static void turn_ints_off(struct specialix_board *bp)
1da177e4
LT
876{
877 unsigned long flags;
878
879 func_enter();
1da177e4 880 spin_lock_irqsave(&bp->lock, flags);
a72492bd 881 (void) sx_in_off(bp, 0); /* Turn off interrupts. */
1da177e4
LT
882 spin_unlock_irqrestore(&bp->lock, flags);
883
884 func_exit();
885}
886
a72492bd 887static void turn_ints_on(struct specialix_board *bp)
1da177e4
LT
888{
889 unsigned long flags;
890
891 func_enter();
892
1da177e4 893 spin_lock_irqsave(&bp->lock, flags);
a72492bd 894 (void) sx_in(bp, 0); /* Turn ON interrupts. */
1da177e4
LT
895 spin_unlock_irqrestore(&bp->lock, flags);
896
897 func_exit();
898}
899
900
901/* Called with disabled interrupts */
d2fbd0f2 902static int sx_setup_board(struct specialix_board *bp)
1da177e4
LT
903{
904 int error;
905
d61780c0 906 if (bp->flags & SX_BOARD_ACTIVE)
1da177e4
LT
907 return 0;
908
909 if (bp->flags & SX_BOARD_IS_PCI)
a72492bd
AC
910 error = request_irq(bp->irq, sx_interrupt,
911 IRQF_DISABLED | IRQF_SHARED, "specialix IO8+", bp);
1da177e4 912 else
a72492bd
AC
913 error = request_irq(bp->irq, sx_interrupt,
914 IRQF_DISABLED, "specialix IO8+", bp);
1da177e4 915
d61780c0 916 if (error)
1da177e4
LT
917 return error;
918
a72492bd 919 turn_ints_on(bp);
1da177e4
LT
920 bp->flags |= SX_BOARD_ACTIVE;
921
922 return 0;
923}
924
925
926/* Called with disabled interrupts */
d2fbd0f2 927static void sx_shutdown_board(struct specialix_board *bp)
1da177e4
LT
928{
929 func_enter();
930
931 if (!(bp->flags & SX_BOARD_ACTIVE)) {
932 func_exit();
933 return;
934 }
935
936 bp->flags &= ~SX_BOARD_ACTIVE;
d61780c0 937
a72492bd
AC
938 dprintk(SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
939 bp->irq, board_No(bp));
1da177e4 940 free_irq(bp->irq, bp);
a72492bd 941 turn_ints_off(bp);
1da177e4
LT
942 func_exit();
943}
944
d2fbd0f2
AC
945static unsigned int sx_crtscts(struct tty_struct *tty)
946{
947 if (sx_rtscts)
948 return C_CRTSCTS(tty);
949 return 1;
950}
1da177e4
LT
951
952/*
d61780c0 953 * Setting up port characteristics.
1da177e4
LT
954 * Must be called with disabled interrupts
955 */
a72492bd
AC
956static void sx_change_speed(struct specialix_board *bp,
957 struct specialix_port *port)
1da177e4
LT
958{
959 struct tty_struct *tty;
960 unsigned long baud;
961 long tmp;
962 unsigned char cor1 = 0, cor3 = 0;
963 unsigned char mcor1 = 0, mcor2 = 0;
964 static unsigned long again;
965 unsigned long flags;
966
967 func_enter();
968
a72492bd
AC
969 tty = port->port.tty;
970 if (!tty || !tty->termios) {
1da177e4
LT
971 func_exit();
972 return;
973 }
974
975 port->IER = 0;
976 port->COR2 = 0;
977 /* Select port on the board */
978 spin_lock_irqsave(&bp->lock, flags);
979 sx_out(bp, CD186x_CAR, port_No(port));
980
25985edc 981 /* The Specialix board does't implement the RTS lines.
1da177e4 982 They are used to set the IRQ level. Don't touch them. */
d2fbd0f2 983 if (sx_crtscts(tty))
1da177e4
LT
984 port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
985 else
986 port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
987 spin_unlock_irqrestore(&bp->lock, flags);
a72492bd 988 dprintk(SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
67cc0161 989 baud = tty_get_baud_rate(tty);
d61780c0 990
67cc0161 991 if (baud == 38400) {
44b7d1b3 992 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
a4bb2cf1 993 baud = 57600;
44b7d1b3 994 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
a4bb2cf1 995 baud = 115200;
1da177e4 996 }
d61780c0 997
67cc0161 998 if (!baud) {
1da177e4 999 /* Drop DTR & exit */
a72492bd 1000 dprintk(SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
d2fbd0f2 1001 if (!sx_crtscts(tty)) {
a72492bd 1002 port->MSVR &= ~MSVR_DTR;
1da177e4 1003 spin_lock_irqsave(&bp->lock, flags);
a72492bd 1004 sx_out(bp, CD186x_MSVR, port->MSVR);
1da177e4 1005 spin_unlock_irqrestore(&bp->lock, flags);
a72492bd
AC
1006 } else
1007 dprintk(SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
1da177e4
LT
1008 return;
1009 } else {
1010 /* Set DTR on */
d2fbd0f2 1011 if (!sx_crtscts(tty))
a72492bd 1012 port->MSVR |= MSVR_DTR;
1da177e4 1013 }
d61780c0 1014
1da177e4 1015 /*
d61780c0 1016 * Now we must calculate some speed depended things
1da177e4
LT
1017 */
1018
1019 /* Set baud rate for port */
1020 tmp = port->custom_divisor ;
a72492bd
AC
1021 if (tmp)
1022 printk(KERN_INFO
1023 "sx%d: Using custom baud rate divisor %ld. \n"
1024 "This is an untested option, please be careful.\n",
1025 port_No(port), tmp);
1da177e4 1026 else
a72492bd
AC
1027 tmp = (((SX_OSCFREQ + baud/2) / baud + CD186x_TPC/2) /
1028 CD186x_TPC);
1da177e4 1029
a72492bd 1030 if (tmp < 0x10 && time_before(again, jiffies)) {
1da177e4
LT
1031 again = jiffies + HZ * 60;
1032 /* Page 48 of version 2.0 of the CL-CD1865 databook */
1033 if (tmp >= 12) {
a72492bd
AC
1034 printk(KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
1035 "Performance degradation is possible.\n"
1036 "Read specialix.txt for more info.\n",
1037 port_No(port), tmp);
1da177e4 1038 } else {
a72492bd
AC
1039 printk(KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
1040 "Warning: overstressing Cirrus chip. This might not work.\n"
1041 "Read specialix.txt for more info.\n", port_No(port), tmp);
1da177e4
LT
1042 }
1043 }
1044 spin_lock_irqsave(&bp->lock, flags);
d61780c0
JG
1045 sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff);
1046 sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff);
1047 sx_out(bp, CD186x_RBPRL, tmp & 0xff);
1da177e4
LT
1048 sx_out(bp, CD186x_TBPRL, tmp & 0xff);
1049 spin_unlock_irqrestore(&bp->lock, flags);
a4bb2cf1 1050 if (port->custom_divisor)
a72492bd
AC
1051 baud = (SX_OSCFREQ + port->custom_divisor/2) /
1052 port->custom_divisor;
a4bb2cf1 1053 baud = (baud + 5) / 10; /* Estimated CPS */
1da177e4
LT
1054
1055 /* Two timer ticks seems enough to wakeup something like SLIP driver */
d61780c0 1056 tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO;
1da177e4
LT
1057 port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
1058 SERIAL_XMIT_SIZE - 1 : tmp);
d61780c0 1059
1da177e4
LT
1060 /* Receiver timeout will be transmission time for 1.5 chars */
1061 tmp = (SPECIALIX_TPS + SPECIALIX_TPS/2 + baud/2) / baud;
1062 tmp = (tmp > 0xff) ? 0xff : tmp;
1063 spin_lock_irqsave(&bp->lock, flags);
1064 sx_out(bp, CD186x_RTPR, tmp);
1065 spin_unlock_irqrestore(&bp->lock, flags);
1066 switch (C_CSIZE(tty)) {
a72492bd 1067 case CS5:
1da177e4
LT
1068 cor1 |= COR1_5BITS;
1069 break;
a72492bd 1070 case CS6:
1da177e4
LT
1071 cor1 |= COR1_6BITS;
1072 break;
a72492bd 1073 case CS7:
1da177e4
LT
1074 cor1 |= COR1_7BITS;
1075 break;
a72492bd 1076 case CS8:
1da177e4
LT
1077 cor1 |= COR1_8BITS;
1078 break;
1079 }
d61780c0
JG
1080
1081 if (C_CSTOPB(tty))
1da177e4 1082 cor1 |= COR1_2SB;
d61780c0 1083
1da177e4
LT
1084 cor1 |= COR1_IGNORE;
1085 if (C_PARENB(tty)) {
1086 cor1 |= COR1_NORMPAR;
d61780c0 1087 if (C_PARODD(tty))
1da177e4 1088 cor1 |= COR1_ODDP;
d61780c0 1089 if (I_INPCK(tty))
1da177e4
LT
1090 cor1 &= ~COR1_IGNORE;
1091 }
1092 /* Set marking of some errors */
1093 port->mark_mask = RCSR_OE | RCSR_TOUT;
d61780c0 1094 if (I_INPCK(tty))
1da177e4 1095 port->mark_mask |= RCSR_FE | RCSR_PE;
d61780c0 1096 if (I_BRKINT(tty) || I_PARMRK(tty))
1da177e4 1097 port->mark_mask |= RCSR_BREAK;
d61780c0 1098 if (I_IGNPAR(tty))
1da177e4
LT
1099 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
1100 if (I_IGNBRK(tty)) {
1101 port->mark_mask &= ~RCSR_BREAK;
d61780c0 1102 if (I_IGNPAR(tty))
1da177e4
LT
1103 /* Real raw mode. Ignore all */
1104 port->mark_mask &= ~RCSR_OE;
1105 }
1106 /* Enable Hardware Flow Control */
1107 if (C_CRTSCTS(tty)) {
1108#ifdef SPECIALIX_BRAIN_DAMAGED_CTS
1109 port->IER |= IER_DSR | IER_CTS;
1110 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
1111 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
1112 spin_lock_irqsave(&bp->lock, flags);
a72492bd
AC
1113 tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) &
1114 (MSVR_CTS|MSVR_DSR));
1da177e4
LT
1115 spin_unlock_irqrestore(&bp->lock, flags);
1116#else
d61780c0 1117 port->COR2 |= COR2_CTSAE;
1da177e4
LT
1118#endif
1119 }
1120 /* Enable Software Flow Control. FIXME: I'm not sure about this */
1121 /* Some people reported that it works, but I still doubt it */
1122 if (I_IXON(tty)) {
1123 port->COR2 |= COR2_TXIBE;
1124 cor3 |= (COR3_FCT | COR3_SCDE);
1125 if (I_IXANY(tty))
1126 port->COR2 |= COR2_IXM;
1127 spin_lock_irqsave(&bp->lock, flags);
1128 sx_out(bp, CD186x_SCHR1, START_CHAR(tty));
1129 sx_out(bp, CD186x_SCHR2, STOP_CHAR(tty));
1130 sx_out(bp, CD186x_SCHR3, START_CHAR(tty));
1131 sx_out(bp, CD186x_SCHR4, STOP_CHAR(tty));
1132 spin_unlock_irqrestore(&bp->lock, flags);
1133 }
1134 if (!C_CLOCAL(tty)) {
1135 /* Enable CD check */
1136 port->IER |= IER_CD;
1137 mcor1 |= MCOR1_CDZD;
1138 mcor2 |= MCOR2_CDOD;
1139 }
d61780c0
JG
1140
1141 if (C_CREAD(tty))
1da177e4
LT
1142 /* Enable receiver */
1143 port->IER |= IER_RXD;
d61780c0 1144
1da177e4
LT
1145 /* Set input FIFO size (1-8 bytes) */
1146 cor3 |= sx_rxfifo;
1147 /* Setting up CD186x channel registers */
1148 spin_lock_irqsave(&bp->lock, flags);
1149 sx_out(bp, CD186x_COR1, cor1);
1150 sx_out(bp, CD186x_COR2, port->COR2);
1151 sx_out(bp, CD186x_COR3, cor3);
1152 spin_unlock_irqrestore(&bp->lock, flags);
1153 /* Make CD186x know about registers change */
1154 sx_wait_CCR(bp);
1155 spin_lock_irqsave(&bp->lock, flags);
1156 sx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
1157 /* Setting up modem option registers */
a72492bd
AC
1158 dprintk(SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n",
1159 mcor1, mcor2);
1da177e4
LT
1160 sx_out(bp, CD186x_MCOR1, mcor1);
1161 sx_out(bp, CD186x_MCOR2, mcor2);
1162 spin_unlock_irqrestore(&bp->lock, flags);
1163 /* Enable CD186x transmitter & receiver */
1164 sx_wait_CCR(bp);
1165 spin_lock_irqsave(&bp->lock, flags);
1166 sx_out(bp, CD186x_CCR, CCR_TXEN | CCR_RXEN);
1167 /* Enable interrupts */
1168 sx_out(bp, CD186x_IER, port->IER);
1169 /* And finally set the modem lines... */
1170 sx_out(bp, CD186x_MSVR, port->MSVR);
1171 spin_unlock_irqrestore(&bp->lock, flags);
1172
1173 func_exit();
1174}
1175
1176
1177/* Must be called with interrupts enabled */
a72492bd
AC
1178static int sx_setup_port(struct specialix_board *bp,
1179 struct specialix_port *port)
1da177e4
LT
1180{
1181 unsigned long flags;
1182
1183 func_enter();
1184
44b7d1b3 1185 if (port->port.flags & ASYNC_INITIALIZED) {
1da177e4
LT
1186 func_exit();
1187 return 0;
1188 }
d61780c0 1189
1da177e4
LT
1190 if (!port->xmit_buf) {
1191 /* We may sleep in get_zeroed_page() */
1192 unsigned long tmp;
d61780c0 1193
a72492bd
AC
1194 tmp = get_zeroed_page(GFP_KERNEL);
1195 if (tmp == 0L) {
1da177e4
LT
1196 func_exit();
1197 return -ENOMEM;
1198 }
1199
1200 if (port->xmit_buf) {
1201 free_page(tmp);
1202 func_exit();
1203 return -ERESTARTSYS;
1204 }
1205 port->xmit_buf = (unsigned char *) tmp;
1206 }
d61780c0 1207
1da177e4
LT
1208 spin_lock_irqsave(&port->lock, flags);
1209
44b7d1b3
AC
1210 if (port->port.tty)
1211 clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
1da177e4
LT
1212
1213 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1214 sx_change_speed(bp, port);
44b7d1b3 1215 port->port.flags |= ASYNC_INITIALIZED;
1da177e4
LT
1216
1217 spin_unlock_irqrestore(&port->lock, flags);
1218
d61780c0 1219
1da177e4
LT
1220 func_exit();
1221 return 0;
1222}
1223
1224
1225/* Must be called with interrupts disabled */
a72492bd
AC
1226static void sx_shutdown_port(struct specialix_board *bp,
1227 struct specialix_port *port)
1da177e4
LT
1228{
1229 struct tty_struct *tty;
1230 int i;
1231 unsigned long flags;
d61780c0 1232
1da177e4
LT
1233 func_enter();
1234
44b7d1b3 1235 if (!(port->port.flags & ASYNC_INITIALIZED)) {
1da177e4
LT
1236 func_exit();
1237 return;
1238 }
d61780c0 1239
1da177e4 1240 if (sx_debug & SX_DEBUG_FIFO) {
a72492bd
AC
1241 dprintk(SX_DEBUG_FIFO,
1242 "sx%d: port %d: %ld overruns, FIFO hits [ ",
1243 board_No(bp), port_No(port), port->overrun);
1244 for (i = 0; i < 10; i++)
1da177e4 1245 dprintk(SX_DEBUG_FIFO, "%ld ", port->hits[i]);
1da177e4
LT
1246 dprintk(SX_DEBUG_FIFO, "].\n");
1247 }
1248
1249 if (port->xmit_buf) {
1250 free_page((unsigned long) port->xmit_buf);
1251 port->xmit_buf = NULL;
1252 }
1253
1254 /* Select port */
1255 spin_lock_irqsave(&bp->lock, flags);
1256 sx_out(bp, CD186x_CAR, port_No(port));
1257
a72492bd
AC
1258 tty = port->port.tty;
1259 if (tty == NULL || C_HUPCL(tty)) {
1da177e4
LT
1260 /* Drop DTR */
1261 sx_out(bp, CD186x_MSVDTR, 0);
1262 }
1263 spin_unlock_irqrestore(&bp->lock, flags);
1264 /* Reset port */
1265 sx_wait_CCR(bp);
1266 spin_lock_irqsave(&bp->lock, flags);
1267 sx_out(bp, CD186x_CCR, CCR_SOFTRESET);
1268 /* Disable all interrupts from this port */
1269 port->IER = 0;
1270 sx_out(bp, CD186x_IER, port->IER);
1271 spin_unlock_irqrestore(&bp->lock, flags);
1272 if (tty)
1273 set_bit(TTY_IO_ERROR, &tty->flags);
44b7d1b3 1274 port->port.flags &= ~ASYNC_INITIALIZED;
d61780c0
JG
1275
1276 if (!bp->count)
1da177e4
LT
1277 sx_shutdown_board(bp);
1278 func_exit();
1279}
1280
d61780c0 1281
a72492bd
AC
1282static int block_til_ready(struct tty_struct *tty, struct file *filp,
1283 struct specialix_port *port)
1da177e4
LT
1284{
1285 DECLARE_WAITQUEUE(wait, current);
1286 struct specialix_board *bp = port_Board(port);
1287 int retval;
1288 int do_clocal = 0;
1289 int CD;
1290 unsigned long flags;
1291
1292 func_enter();
1293
1294 /*
1295 * If the device is in the middle of being closed, then block
1296 * until it's done, and then try again.
1297 */
44b7d1b3
AC
1298 if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
1299 interruptible_sleep_on(&port->port.close_wait);
1300 if (port->port.flags & ASYNC_HUP_NOTIFY) {
1da177e4
LT
1301 func_exit();
1302 return -EAGAIN;
1303 } else {
1304 func_exit();
1305 return -ERESTARTSYS;
1306 }
1307 }
d61780c0 1308
1da177e4
LT
1309 /*
1310 * If non-blocking mode is set, or the port is not enabled,
1311 * then make the check up front and then exit.
1312 */
1313 if ((filp->f_flags & O_NONBLOCK) ||
1314 (tty->flags & (1 << TTY_IO_ERROR))) {
44b7d1b3 1315 port->port.flags |= ASYNC_NORMAL_ACTIVE;
1da177e4
LT
1316 func_exit();
1317 return 0;
1318 }
1319
1320 if (C_CLOCAL(tty))
1321 do_clocal = 1;
1322
1323 /*
1324 * Block waiting for the carrier detect and the line to become
1325 * free (i.e., not in use by the callout). While we are in
1326 * this loop, info->count is dropped by one, so that
1327 * rs_close() knows when to free things. We restore it upon
1328 * exit, either normal or abnormal.
1329 */
1330 retval = 0;
44b7d1b3 1331 add_wait_queue(&port->port.open_wait, &wait);
1da177e4 1332 spin_lock_irqsave(&port->lock, flags);
a72492bd 1333 if (!tty_hung_up_p(filp))
44b7d1b3 1334 port->port.count--;
1da177e4 1335 spin_unlock_irqrestore(&port->lock, flags);
44b7d1b3 1336 port->port.blocked_open++;
1da177e4
LT
1337 while (1) {
1338 spin_lock_irqsave(&bp->lock, flags);
1339 sx_out(bp, CD186x_CAR, port_No(port));
1340 CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
d2fbd0f2 1341 if (sx_crtscts(tty)) {
1da177e4
LT
1342 /* Activate RTS */
1343 port->MSVR |= MSVR_DTR; /* WTF? */
a72492bd 1344 sx_out(bp, CD186x_MSVR, port->MSVR);
1da177e4
LT
1345 } else {
1346 /* Activate DTR */
1347 port->MSVR |= MSVR_DTR;
a72492bd 1348 sx_out(bp, CD186x_MSVR, port->MSVR);
1da177e4
LT
1349 }
1350 spin_unlock_irqrestore(&bp->lock, flags);
1351 set_current_state(TASK_INTERRUPTIBLE);
1352 if (tty_hung_up_p(filp) ||
44b7d1b3
AC
1353 !(port->port.flags & ASYNC_INITIALIZED)) {
1354 if (port->port.flags & ASYNC_HUP_NOTIFY)
1da177e4
LT
1355 retval = -EAGAIN;
1356 else
d61780c0 1357 retval = -ERESTARTSYS;
1da177e4
LT
1358 break;
1359 }
44b7d1b3 1360 if (!(port->port.flags & ASYNC_CLOSING) &&
1da177e4
LT
1361 (do_clocal || CD))
1362 break;
1363 if (signal_pending(current)) {
1364 retval = -ERESTARTSYS;
1365 break;
1366 }
e142a31d 1367 tty_unlock();
1da177e4 1368 schedule();
e142a31d 1369 tty_lock();
1da177e4
LT
1370 }
1371
1372 set_current_state(TASK_RUNNING);
44b7d1b3 1373 remove_wait_queue(&port->port.open_wait, &wait);
1da177e4 1374 spin_lock_irqsave(&port->lock, flags);
a72492bd 1375 if (!tty_hung_up_p(filp))
44b7d1b3 1376 port->port.count++;
44b7d1b3 1377 port->port.blocked_open--;
1da177e4
LT
1378 spin_unlock_irqrestore(&port->lock, flags);
1379 if (retval) {
1380 func_exit();
1381 return retval;
1382 }
1383
44b7d1b3 1384 port->port.flags |= ASYNC_NORMAL_ACTIVE;
1da177e4
LT
1385 func_exit();
1386 return 0;
d61780c0 1387}
1da177e4
LT
1388
1389
a72492bd 1390static int sx_open(struct tty_struct *tty, struct file *filp)
1da177e4
LT
1391{
1392 int board;
1393 int error;
a72492bd
AC
1394 struct specialix_port *port;
1395 struct specialix_board *bp;
1da177e4
LT
1396 int i;
1397 unsigned long flags;
1398
1399 func_enter();
1400
1401 board = SX_BOARD(tty->index);
1402
1403 if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT)) {
1404 func_exit();
1405 return -ENODEV;
1406 }
d61780c0 1407
1da177e4
LT
1408 bp = &sx_board[board];
1409 port = sx_port + board * SX_NPORT + SX_PORT(tty->index);
1410 port->overrun = 0;
1411 for (i = 0; i < 10; i++)
a72492bd 1412 port->hits[i] = 0;
1da177e4 1413
a72492bd
AC
1414 dprintk(SX_DEBUG_OPEN,
1415 "Board = %d, bp = %p, port = %p, portno = %d.\n",
1416 board, bp, port, SX_PORT(tty->index));
1da177e4
LT
1417
1418 if (sx_paranoia_check(port, tty->name, "sx_open")) {
115bcd15 1419 func_exit();
1da177e4
LT
1420 return -ENODEV;
1421 }
1422
a72492bd
AC
1423 error = sx_setup_board(bp);
1424 if (error) {
1da177e4
LT
1425 func_exit();
1426 return error;
1427 }
1428
1429 spin_lock_irqsave(&bp->lock, flags);
44b7d1b3 1430 port->port.count++;
1da177e4
LT
1431 bp->count++;
1432 tty->driver_data = port;
44b7d1b3 1433 port->port.tty = tty;
1da177e4
LT
1434 spin_unlock_irqrestore(&bp->lock, flags);
1435
a72492bd
AC
1436 error = sx_setup_port(bp, port);
1437 if (error) {
115bcd15 1438 func_exit();
1da177e4
LT
1439 return error;
1440 }
d61780c0 1441
a72492bd
AC
1442 error = block_til_ready(tty, filp, port);
1443 if (error) {
115bcd15 1444 func_exit();
1da177e4
LT
1445 return error;
1446 }
1447
1448 func_exit();
1449 return 0;
1450}
1451
978e595f
AC
1452static void sx_flush_buffer(struct tty_struct *tty)
1453{
c9f19e96 1454 struct specialix_port *port = tty->driver_data;
978e595f 1455 unsigned long flags;
a72492bd 1456 struct specialix_board *bp;
978e595f
AC
1457
1458 func_enter();
1459
1460 if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
1461 func_exit();
1462 return;
1463 }
1464
1465 bp = port_Board(port);
1466 spin_lock_irqsave(&port->lock, flags);
1467 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1468 spin_unlock_irqrestore(&port->lock, flags);
1469 tty_wakeup(tty);
1470
1471 func_exit();
1472}
1da177e4 1473
a72492bd 1474static void sx_close(struct tty_struct *tty, struct file *filp)
1da177e4 1475{
c9f19e96 1476 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1477 struct specialix_board *bp;
1478 unsigned long flags;
1479 unsigned long timeout;
d61780c0 1480
1da177e4
LT
1481 func_enter();
1482 if (!port || sx_paranoia_check(port, tty->name, "close")) {
1483 func_exit();
1484 return;
1485 }
1486 spin_lock_irqsave(&port->lock, flags);
1487
1488 if (tty_hung_up_p(filp)) {
1489 spin_unlock_irqrestore(&port->lock, flags);
1490 func_exit();
1491 return;
1492 }
d61780c0 1493
1da177e4 1494 bp = port_Board(port);
d2fbd0f2 1495 if (tty->count == 1 && port->port.count != 1) {
1da177e4
LT
1496 printk(KERN_ERR "sx%d: sx_close: bad port count;"
1497 " tty->count is 1, port count is %d\n",
44b7d1b3
AC
1498 board_No(bp), port->port.count);
1499 port->port.count = 1;
1da177e4
LT
1500 }
1501
44b7d1b3
AC
1502 if (port->port.count > 1) {
1503 port->port.count--;
1da177e4
LT
1504 bp->count--;
1505
1506 spin_unlock_irqrestore(&port->lock, flags);
1507
1508 func_exit();
1509 return;
1510 }
44b7d1b3 1511 port->port.flags |= ASYNC_CLOSING;
1da177e4 1512 /*
d61780c0 1513 * Now we wait for the transmit buffer to clear; and we notify
1da177e4
LT
1514 * the line discipline to only process XON/XOFF characters.
1515 */
1516 tty->closing = 1;
1517 spin_unlock_irqrestore(&port->lock, flags);
a72492bd
AC
1518 dprintk(SX_DEBUG_OPEN, "Closing\n");
1519 if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
44b7d1b3 1520 tty_wait_until_sent(tty, port->port.closing_wait);
1da177e4
LT
1521 /*
1522 * At this point we stop accepting input. To do this, we
1523 * disable the receive line status interrupts, and tell the
1524 * interrupt driver to stop checking the data ready bit in the
1525 * line status register.
1526 */
a72492bd 1527 dprintk(SX_DEBUG_OPEN, "Closed\n");
1da177e4 1528 port->IER &= ~IER_RXD;
44b7d1b3 1529 if (port->port.flags & ASYNC_INITIALIZED) {
1da177e4
LT
1530 port->IER &= ~IER_TXRDY;
1531 port->IER |= IER_TXEMPTY;
1532 spin_lock_irqsave(&bp->lock, flags);
1533 sx_out(bp, CD186x_CAR, port_No(port));
1534 sx_out(bp, CD186x_IER, port->IER);
1535 spin_unlock_irqrestore(&bp->lock, flags);
1536 /*
1537 * Before we drop DTR, make sure the UART transmitter
1538 * has completely drained; this is especially
1539 * important if there is a transmit FIFO!
1540 */
1541 timeout = jiffies+HZ;
a72492bd
AC
1542 while (port->IER & IER_TXEMPTY) {
1543 set_current_state(TASK_INTERRUPTIBLE);
1da177e4
LT
1544 msleep_interruptible(jiffies_to_msecs(port->timeout));
1545 if (time_after(jiffies, timeout)) {
a72492bd 1546 printk(KERN_INFO "Timeout waiting for close\n");
1da177e4
LT
1547 break;
1548 }
1549 }
1550
1551 }
1552
1553 if (--bp->count < 0) {
a72492bd
AC
1554 printk(KERN_ERR
1555 "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
1556 board_No(bp), bp->count, tty->index);
1da177e4
LT
1557 bp->count = 0;
1558 }
44b7d1b3 1559 if (--port->port.count < 0) {
a72492bd
AC
1560 printk(KERN_ERR
1561 "sx%d: sx_close: bad port count for tty%d: %d\n",
1562 board_No(bp), port_No(port), port->port.count);
44b7d1b3 1563 port->port.count = 0;
1da177e4
LT
1564 }
1565
1566 sx_shutdown_port(bp, port);
978e595f 1567 sx_flush_buffer(tty);
1da177e4
LT
1568 tty_ldisc_flush(tty);
1569 spin_lock_irqsave(&port->lock, flags);
1570 tty->closing = 0;
44b7d1b3 1571 port->port.tty = NULL;
1da177e4 1572 spin_unlock_irqrestore(&port->lock, flags);
44b7d1b3 1573 if (port->port.blocked_open) {
a72492bd
AC
1574 if (port->port.close_delay)
1575 msleep_interruptible(
1576 jiffies_to_msecs(port->port.close_delay));
44b7d1b3 1577 wake_up_interruptible(&port->port.open_wait);
1da177e4 1578 }
44b7d1b3
AC
1579 port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1580 wake_up_interruptible(&port->port.close_wait);
1da177e4
LT
1581
1582 func_exit();
1583}
1584
1585
a72492bd
AC
1586static int sx_write(struct tty_struct *tty,
1587 const unsigned char *buf, int count)
1da177e4 1588{
c9f19e96 1589 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1590 struct specialix_board *bp;
1591 int c, total = 0;
1592 unsigned long flags;
1593
1594 func_enter();
1595 if (sx_paranoia_check(port, tty->name, "sx_write")) {
1596 func_exit();
1597 return 0;
1598 }
d61780c0 1599
1da177e4
LT
1600 bp = port_Board(port);
1601
365e0223 1602 if (!port->xmit_buf) {
1da177e4
LT
1603 func_exit();
1604 return 0;
1605 }
1606
1607 while (1) {
1608 spin_lock_irqsave(&port->lock, flags);
1609 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
1610 SERIAL_XMIT_SIZE - port->xmit_head));
1611 if (c <= 0) {
1612 spin_unlock_irqrestore(&port->lock, flags);
1613 break;
1614 }
1615 memcpy(port->xmit_buf + port->xmit_head, buf, c);
1616 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
1617 port->xmit_cnt += c;
1618 spin_unlock_irqrestore(&port->lock, flags);
1619
1620 buf += c;
1621 count -= c;
1622 total += c;
1623 }
1624
1625 spin_lock_irqsave(&bp->lock, flags);
1626 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1627 !(port->IER & IER_TXRDY)) {
1628 port->IER |= IER_TXRDY;
1629 sx_out(bp, CD186x_CAR, port_No(port));
1630 sx_out(bp, CD186x_IER, port->IER);
1631 }
1632 spin_unlock_irqrestore(&bp->lock, flags);
1633 func_exit();
1634
1635 return total;
1636}
1637
1638
a72492bd 1639static int sx_put_char(struct tty_struct *tty, unsigned char ch)
1da177e4 1640{
c9f19e96 1641 struct specialix_port *port = tty->driver_data;
1da177e4 1642 unsigned long flags;
a72492bd 1643 struct specialix_board *bp;
1da177e4
LT
1644
1645 func_enter();
1646
1647 if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
1648 func_exit();
6ae04576 1649 return 0;
1da177e4 1650 }
a72492bd 1651 dprintk(SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
326f28e9 1652 if (!port->xmit_buf) {
1da177e4 1653 func_exit();
6ae04576 1654 return 0;
1da177e4
LT
1655 }
1656 bp = port_Board(port);
1657 spin_lock_irqsave(&port->lock, flags);
1658
a72492bd
AC
1659 dprintk(SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n",
1660 port->xmit_cnt, port->xmit_buf);
1661 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1 || !port->xmit_buf) {
1da177e4 1662 spin_unlock_irqrestore(&port->lock, flags);
a72492bd 1663 dprintk(SX_DEBUG_TX, "Exit size\n");
1da177e4 1664 func_exit();
6ae04576 1665 return 0;
1da177e4 1666 }
a72492bd 1667 dprintk(SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
1da177e4
LT
1668 port->xmit_buf[port->xmit_head++] = ch;
1669 port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1670 port->xmit_cnt++;
1671 spin_unlock_irqrestore(&port->lock, flags);
1672
1673 func_exit();
6ae04576 1674 return 1;
1da177e4
LT
1675}
1676
1677
a72492bd 1678static void sx_flush_chars(struct tty_struct *tty)
1da177e4 1679{
c9f19e96 1680 struct specialix_port *port = tty->driver_data;
1da177e4 1681 unsigned long flags;
a72492bd 1682 struct specialix_board *bp = port_Board(port);
1da177e4
LT
1683
1684 func_enter();
1685
1686 if (sx_paranoia_check(port, tty->name, "sx_flush_chars")) {
1687 func_exit();
1688 return;
1689 }
1690 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1691 !port->xmit_buf) {
1692 func_exit();
1693 return;
1694 }
1695 spin_lock_irqsave(&bp->lock, flags);
1696 port->IER |= IER_TXRDY;
1697 sx_out(port_Board(port), CD186x_CAR, port_No(port));
1698 sx_out(port_Board(port), CD186x_IER, port->IER);
1699 spin_unlock_irqrestore(&bp->lock, flags);
1700
1701 func_exit();
1702}
1703
1704
a72492bd 1705static int sx_write_room(struct tty_struct *tty)
1da177e4 1706{
c9f19e96 1707 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1708 int ret;
1709
1710 func_enter();
1711
1712 if (sx_paranoia_check(port, tty->name, "sx_write_room")) {
1713 func_exit();
1714 return 0;
1715 }
1716
1717 ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1718 if (ret < 0)
1719 ret = 0;
1720
1721 func_exit();
1722 return ret;
1723}
1724
1725
1726static int sx_chars_in_buffer(struct tty_struct *tty)
1727{
c9f19e96 1728 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1729
1730 func_enter();
d61780c0 1731
1da177e4
LT
1732 if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) {
1733 func_exit();
1734 return 0;
1735 }
1736 func_exit();
1737 return port->xmit_cnt;
1738}
1739
60b33c13 1740static int sx_tiocmget(struct tty_struct *tty)
1da177e4 1741{
c9f19e96 1742 struct specialix_port *port = tty->driver_data;
a72492bd 1743 struct specialix_board *bp;
1da177e4
LT
1744 unsigned char status;
1745 unsigned int result;
1746 unsigned long flags;
1747
1748 func_enter();
1749
bf9d8929 1750 if (sx_paranoia_check(port, tty->name, __func__)) {
1da177e4
LT
1751 func_exit();
1752 return -ENODEV;
1753 }
1754
1755 bp = port_Board(port);
a72492bd 1756 spin_lock_irqsave(&bp->lock, flags);
1da177e4
LT
1757 sx_out(bp, CD186x_CAR, port_No(port));
1758 status = sx_in(bp, CD186x_MSVR);
1759 spin_unlock_irqrestore(&bp->lock, flags);
a72492bd
AC
1760 dprintk(SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
1761 port_No(port), status, sx_in(bp, CD186x_CAR));
1762 dprintk(SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
d2fbd0f2
AC
1763 if (sx_crtscts(port->port.tty)) {
1764 result = TIOCM_DTR | TIOCM_DSR
a72492bd
AC
1765 | ((status & MSVR_DTR) ? TIOCM_RTS : 0)
1766 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
a72492bd 1767 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1da177e4 1768 } else {
d2fbd0f2 1769 result = TIOCM_RTS | TIOCM_DSR
a72492bd
AC
1770 | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1771 | ((status & MSVR_CD) ? TIOCM_CAR : 0)
a72492bd 1772 | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1da177e4
LT
1773 }
1774
1775 func_exit();
1776
1777 return result;
1778}
1779
1780
20b9d177 1781static int sx_tiocmset(struct tty_struct *tty,
1da177e4
LT
1782 unsigned int set, unsigned int clear)
1783{
c9f19e96 1784 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1785 unsigned long flags;
1786 struct specialix_board *bp;
1787
1788 func_enter();
1789
bf9d8929 1790 if (sx_paranoia_check(port, tty->name, __func__)) {
1da177e4
LT
1791 func_exit();
1792 return -ENODEV;
1793 }
1794
1795 bp = port_Board(port);
1796
1797 spin_lock_irqsave(&port->lock, flags);
d2fbd0f2 1798 if (sx_crtscts(port->port.tty)) {
1da177e4
LT
1799 if (set & TIOCM_RTS)
1800 port->MSVR |= MSVR_DTR;
1801 } else {
1802 if (set & TIOCM_DTR)
1803 port->MSVR |= MSVR_DTR;
1804 }
d2fbd0f2 1805 if (sx_crtscts(port->port.tty)) {
1da177e4
LT
1806 if (clear & TIOCM_RTS)
1807 port->MSVR &= ~MSVR_DTR;
1808 } else {
1809 if (clear & TIOCM_DTR)
1810 port->MSVR &= ~MSVR_DTR;
1811 }
25470256 1812 spin_lock(&bp->lock);
1da177e4
LT
1813 sx_out(bp, CD186x_CAR, port_No(port));
1814 sx_out(bp, CD186x_MSVR, port->MSVR);
25470256 1815 spin_unlock(&bp->lock);
1da177e4
LT
1816 spin_unlock_irqrestore(&port->lock, flags);
1817 func_exit();
1818 return 0;
1819}
1820
1821
faa7612c 1822static int sx_send_break(struct tty_struct *tty, int length)
1da177e4 1823{
c9f19e96 1824 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1825 struct specialix_board *bp = port_Board(port);
1826 unsigned long flags;
d61780c0 1827
1da177e4 1828 func_enter();
faa7612c
AC
1829 if (length == 0 || length == -1)
1830 return -EOPNOTSUPP;
1da177e4 1831
a72492bd 1832 spin_lock_irqsave(&port->lock, flags);
1da177e4
LT
1833 port->break_length = SPECIALIX_TPS / HZ * length;
1834 port->COR2 |= COR2_ETC;
1835 port->IER |= IER_TXRDY;
25470256 1836 spin_lock(&bp->lock);
1da177e4
LT
1837 sx_out(bp, CD186x_CAR, port_No(port));
1838 sx_out(bp, CD186x_COR2, port->COR2);
1839 sx_out(bp, CD186x_IER, port->IER);
25470256 1840 spin_unlock(&bp->lock);
a72492bd 1841 spin_unlock_irqrestore(&port->lock, flags);
1da177e4
LT
1842 sx_wait_CCR(bp);
1843 spin_lock_irqsave(&bp->lock, flags);
1844 sx_out(bp, CD186x_CCR, CCR_CORCHG2);
1845 spin_unlock_irqrestore(&bp->lock, flags);
1846 sx_wait_CCR(bp);
1847
1848 func_exit();
faa7612c 1849 return 0;
1da177e4
LT
1850}
1851
1852
d2fbd0f2 1853static int sx_set_serial_info(struct specialix_port *port,
a72492bd 1854 struct serial_struct __user *newinfo)
1da177e4
LT
1855{
1856 struct serial_struct tmp;
1857 struct specialix_board *bp = port_Board(port);
1858 int change_speed;
1859
1860 func_enter();
b190e178 1861
1da177e4 1862 if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
115bcd15 1863 func_exit();
1da177e4
LT
1864 return -EFAULT;
1865 }
d61780c0 1866
7479db07 1867 mutex_lock(&port->port.mutex);
44b7d1b3 1868 change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
1da177e4
LT
1869 (tmp.flags & ASYNC_SPD_MASK));
1870 change_speed |= (tmp.custom_divisor != port->custom_divisor);
d61780c0 1871
1da177e4 1872 if (!capable(CAP_SYS_ADMIN)) {
44b7d1b3
AC
1873 if ((tmp.close_delay != port->port.close_delay) ||
1874 (tmp.closing_wait != port->port.closing_wait) ||
1da177e4 1875 ((tmp.flags & ~ASYNC_USR_MASK) !=
44b7d1b3 1876 (port->port.flags & ~ASYNC_USR_MASK))) {
1da177e4 1877 func_exit();
7479db07 1878 mutex_unlock(&port->port.mutex);
1da177e4
LT
1879 return -EPERM;
1880 }
44b7d1b3 1881 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
a72492bd 1882 (tmp.flags & ASYNC_USR_MASK));
1da177e4
LT
1883 port->custom_divisor = tmp.custom_divisor;
1884 } else {
44b7d1b3 1885 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
a72492bd 1886 (tmp.flags & ASYNC_FLAGS));
44b7d1b3
AC
1887 port->port.close_delay = tmp.close_delay;
1888 port->port.closing_wait = tmp.closing_wait;
1da177e4
LT
1889 port->custom_divisor = tmp.custom_divisor;
1890 }
a72492bd 1891 if (change_speed)
1da177e4 1892 sx_change_speed(bp, port);
a72492bd 1893
1da177e4 1894 func_exit();
7479db07 1895 mutex_unlock(&port->port.mutex);
1da177e4
LT
1896 return 0;
1897}
1898
1899
d2fbd0f2 1900static int sx_get_serial_info(struct specialix_port *port,
1da177e4
LT
1901 struct serial_struct __user *retinfo)
1902{
1903 struct serial_struct tmp;
1904 struct specialix_board *bp = port_Board(port);
d61780c0 1905
1da177e4
LT
1906 func_enter();
1907
1da177e4 1908 memset(&tmp, 0, sizeof(tmp));
7479db07 1909 mutex_lock(&port->port.mutex);
1da177e4
LT
1910 tmp.type = PORT_CIRRUS;
1911 tmp.line = port - sx_port;
1912 tmp.port = bp->base;
1913 tmp.irq = bp->irq;
44b7d1b3 1914 tmp.flags = port->port.flags;
1da177e4 1915 tmp.baud_base = (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC;
44b7d1b3
AC
1916 tmp.close_delay = port->port.close_delay * HZ/100;
1917 tmp.closing_wait = port->port.closing_wait * HZ/100;
1da177e4
LT
1918 tmp.custom_divisor = port->custom_divisor;
1919 tmp.xmit_fifo_size = CD186x_NFIFO;
7479db07 1920 mutex_unlock(&port->port.mutex);
1da177e4
LT
1921 if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
1922 func_exit();
1923 return -EFAULT;
1924 }
1925
1926 func_exit();
1927 return 0;
1928}
1929
1930
6caa76b7 1931static int sx_ioctl(struct tty_struct *tty,
a72492bd 1932 unsigned int cmd, unsigned long arg)
1da177e4 1933{
c9f19e96 1934 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1935 void __user *argp = (void __user *)arg;
1936
1937 func_enter();
1938
1939 if (sx_paranoia_check(port, tty->name, "sx_ioctl")) {
1940 func_exit();
1941 return -ENODEV;
1942 }
d61780c0 1943
1da177e4 1944 switch (cmd) {
a72492bd 1945 case TIOCGSERIAL:
faa7612c 1946 func_exit();
1da177e4 1947 return sx_get_serial_info(port, argp);
a72492bd 1948 case TIOCSSERIAL:
faa7612c 1949 func_exit();
1da177e4 1950 return sx_set_serial_info(port, argp);
a72492bd 1951 default:
faa7612c 1952 func_exit();
1da177e4
LT
1953 return -ENOIOCTLCMD;
1954 }
1955 func_exit();
1956 return 0;
1957}
1958
1959
a72492bd 1960static void sx_throttle(struct tty_struct *tty)
1da177e4 1961{
c9f19e96 1962 struct specialix_port *port = tty->driver_data;
1da177e4
LT
1963 struct specialix_board *bp;
1964 unsigned long flags;
1965
1966 func_enter();
1967
1968 if (sx_paranoia_check(port, tty->name, "sx_throttle")) {
1969 func_exit();
1970 return;
1971 }
d61780c0 1972
1da177e4 1973 bp = port_Board(port);
d61780c0 1974
1da177e4 1975 /* Use DTR instead of RTS ! */
d2fbd0f2 1976 if (sx_crtscts(tty))
1da177e4
LT
1977 port->MSVR &= ~MSVR_DTR;
1978 else {
1979 /* Auch!!! I think the system shouldn't call this then. */
1980 /* Or maybe we're supposed (allowed?) to do our side of hw
d61780c0 1981 handshake anyway, even when hardware handshake is off.
1da177e4 1982 When you see this in your logs, please report.... */
a72492bd
AC
1983 printk(KERN_ERR
1984 "sx%d: Need to throttle, but can't (hardware hs is off)\n",
1985 port_No(port));
1da177e4
LT
1986 }
1987 spin_lock_irqsave(&bp->lock, flags);
1988 sx_out(bp, CD186x_CAR, port_No(port));
1989 spin_unlock_irqrestore(&bp->lock, flags);
1990 if (I_IXOFF(tty)) {
1da177e4
LT
1991 sx_wait_CCR(bp);
1992 spin_lock_irqsave(&bp->lock, flags);
1993 sx_out(bp, CD186x_CCR, CCR_SSCH2);
1994 spin_unlock_irqrestore(&bp->lock, flags);
1995 sx_wait_CCR(bp);
1996 }
1997 spin_lock_irqsave(&bp->lock, flags);
1998 sx_out(bp, CD186x_MSVR, port->MSVR);
1999 spin_unlock_irqrestore(&bp->lock, flags);
2000
2001 func_exit();
2002}
2003
2004
a72492bd 2005static void sx_unthrottle(struct tty_struct *tty)
1da177e4 2006{
c9f19e96 2007 struct specialix_port *port = tty->driver_data;
1da177e4
LT
2008 struct specialix_board *bp;
2009 unsigned long flags;
2010
2011 func_enter();
d61780c0 2012
1da177e4
LT
2013 if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) {
2014 func_exit();
2015 return;
2016 }
d61780c0 2017
1da177e4 2018 bp = port_Board(port);
d61780c0 2019
1da177e4
LT
2020 spin_lock_irqsave(&port->lock, flags);
2021 /* XXXX Use DTR INSTEAD???? */
d2fbd0f2 2022 if (sx_crtscts(tty))
1da177e4 2023 port->MSVR |= MSVR_DTR;
a72492bd 2024 /* Else clause: see remark in "sx_throttle"... */
25470256 2025 spin_lock(&bp->lock);
1da177e4 2026 sx_out(bp, CD186x_CAR, port_No(port));
25470256 2027 spin_unlock(&bp->lock);
1da177e4
LT
2028 if (I_IXOFF(tty)) {
2029 spin_unlock_irqrestore(&port->lock, flags);
2030 sx_wait_CCR(bp);
2031 spin_lock_irqsave(&bp->lock, flags);
2032 sx_out(bp, CD186x_CCR, CCR_SSCH1);
2033 spin_unlock_irqrestore(&bp->lock, flags);
2034 sx_wait_CCR(bp);
2035 spin_lock_irqsave(&port->lock, flags);
2036 }
25470256 2037 spin_lock(&bp->lock);
1da177e4 2038 sx_out(bp, CD186x_MSVR, port->MSVR);
25470256 2039 spin_unlock(&bp->lock);
1da177e4
LT
2040 spin_unlock_irqrestore(&port->lock, flags);
2041
2042 func_exit();
2043}
2044
2045
a72492bd 2046static void sx_stop(struct tty_struct *tty)
1da177e4 2047{
c9f19e96 2048 struct specialix_port *port = tty->driver_data;
1da177e4
LT
2049 struct specialix_board *bp;
2050 unsigned long flags;
2051
2052 func_enter();
d61780c0 2053
1da177e4
LT
2054 if (sx_paranoia_check(port, tty->name, "sx_stop")) {
2055 func_exit();
2056 return;
2057 }
2058
2059 bp = port_Board(port);
d61780c0 2060
1da177e4
LT
2061 spin_lock_irqsave(&port->lock, flags);
2062 port->IER &= ~IER_TXRDY;
25470256 2063 spin_lock(&bp->lock);
1da177e4
LT
2064 sx_out(bp, CD186x_CAR, port_No(port));
2065 sx_out(bp, CD186x_IER, port->IER);
25470256 2066 spin_unlock(&bp->lock);
1da177e4
LT
2067 spin_unlock_irqrestore(&port->lock, flags);
2068
2069 func_exit();
2070}
2071
2072
a72492bd 2073static void sx_start(struct tty_struct *tty)
1da177e4 2074{
c9f19e96 2075 struct specialix_port *port = tty->driver_data;
1da177e4
LT
2076 struct specialix_board *bp;
2077 unsigned long flags;
2078
2079 func_enter();
d61780c0 2080
1da177e4
LT
2081 if (sx_paranoia_check(port, tty->name, "sx_start")) {
2082 func_exit();
2083 return;
2084 }
d61780c0 2085
1da177e4 2086 bp = port_Board(port);
d61780c0 2087
1da177e4
LT
2088 spin_lock_irqsave(&port->lock, flags);
2089 if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
2090 port->IER |= IER_TXRDY;
25470256 2091 spin_lock(&bp->lock);
1da177e4
LT
2092 sx_out(bp, CD186x_CAR, port_No(port));
2093 sx_out(bp, CD186x_IER, port->IER);
25470256 2094 spin_unlock(&bp->lock);
1da177e4
LT
2095 }
2096 spin_unlock_irqrestore(&port->lock, flags);
2097
2098 func_exit();
2099}
2100
a72492bd 2101static void sx_hangup(struct tty_struct *tty)
1da177e4 2102{
c9f19e96 2103 struct specialix_port *port = tty->driver_data;
1da177e4
LT
2104 struct specialix_board *bp;
2105 unsigned long flags;
2106
2107 func_enter();
2108
2109 if (sx_paranoia_check(port, tty->name, "sx_hangup")) {
2110 func_exit();
2111 return;
2112 }
d61780c0 2113
1da177e4 2114 bp = port_Board(port);
d61780c0 2115
1da177e4
LT
2116 sx_shutdown_port(bp, port);
2117 spin_lock_irqsave(&port->lock, flags);
44b7d1b3 2118 bp->count -= port->port.count;
1da177e4 2119 if (bp->count < 0) {
a72492bd
AC
2120 printk(KERN_ERR
2121 "sx%d: sx_hangup: bad board count: %d port: %d\n",
2122 board_No(bp), bp->count, tty->index);
1da177e4
LT
2123 bp->count = 0;
2124 }
44b7d1b3
AC
2125 port->port.count = 0;
2126 port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
2127 port->port.tty = NULL;
1da177e4 2128 spin_unlock_irqrestore(&port->lock, flags);
44b7d1b3 2129 wake_up_interruptible(&port->port.open_wait);
1da177e4
LT
2130
2131 func_exit();
2132}
2133
2134
a72492bd
AC
2135static void sx_set_termios(struct tty_struct *tty,
2136 struct ktermios *old_termios)
1da177e4 2137{
c9f19e96 2138 struct specialix_port *port = tty->driver_data;
1da177e4 2139 unsigned long flags;
a72492bd 2140 struct specialix_board *bp;
d61780c0 2141
1da177e4
LT
2142 if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
2143 return;
d61780c0 2144
1da177e4
LT
2145 bp = port_Board(port);
2146 spin_lock_irqsave(&port->lock, flags);
2147 sx_change_speed(port_Board(port), port);
2148 spin_unlock_irqrestore(&port->lock, flags);
2149
2150 if ((old_termios->c_cflag & CRTSCTS) &&
2151 !(tty->termios->c_cflag & CRTSCTS)) {
2152 tty->hw_stopped = 0;
2153 sx_start(tty);
2154 }
2155}
2156
b68e31d0 2157static const struct tty_operations sx_ops = {
1da177e4
LT
2158 .open = sx_open,
2159 .close = sx_close,
2160 .write = sx_write,
2161 .put_char = sx_put_char,
2162 .flush_chars = sx_flush_chars,
2163 .write_room = sx_write_room,
2164 .chars_in_buffer = sx_chars_in_buffer,
2165 .flush_buffer = sx_flush_buffer,
2166 .ioctl = sx_ioctl,
2167 .throttle = sx_throttle,
2168 .unthrottle = sx_unthrottle,
2169 .set_termios = sx_set_termios,
2170 .stop = sx_stop,
2171 .start = sx_start,
2172 .hangup = sx_hangup,
2173 .tiocmget = sx_tiocmget,
2174 .tiocmset = sx_tiocmset,
faa7612c 2175 .break_ctl = sx_send_break,
1da177e4
LT
2176};
2177
2178static int sx_init_drivers(void)
2179{
2180 int error;
2181 int i;
2182
2183 func_enter();
2184
2185 specialix_driver = alloc_tty_driver(SX_NBOARD * SX_NPORT);
2186 if (!specialix_driver) {
2187 printk(KERN_ERR "sx: Couldn't allocate tty_driver.\n");
2188 func_exit();
2189 return 1;
2190 }
d61780c0 2191
1da177e4
LT
2192 specialix_driver->owner = THIS_MODULE;
2193 specialix_driver->name = "ttyW";
2194 specialix_driver->major = SPECIALIX_NORMAL_MAJOR;
2195 specialix_driver->type = TTY_DRIVER_TYPE_SERIAL;
2196 specialix_driver->subtype = SERIAL_TYPE_NORMAL;
2197 specialix_driver->init_termios = tty_std_termios;
2198 specialix_driver->init_termios.c_cflag =
2199 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
606d099c
AC
2200 specialix_driver->init_termios.c_ispeed = 9600;
2201 specialix_driver->init_termios.c_ospeed = 9600;
faa7612c
AC
2202 specialix_driver->flags = TTY_DRIVER_REAL_RAW |
2203 TTY_DRIVER_HARDWARE_BREAK;
1da177e4
LT
2204 tty_set_operations(specialix_driver, &sx_ops);
2205
a72492bd
AC
2206 error = tty_register_driver(specialix_driver);
2207 if (error) {
1da177e4 2208 put_tty_driver(specialix_driver);
a72492bd
AC
2209 printk(KERN_ERR
2210 "sx: Couldn't register specialix IO8+ driver, error = %d\n",
2211 error);
1da177e4
LT
2212 func_exit();
2213 return 1;
2214 }
2215 memset(sx_port, 0, sizeof(sx_port));
2216 for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
2217 sx_port[i].magic = SPECIALIX_MAGIC;
44b7d1b3 2218 tty_port_init(&sx_port[i].port);
1da177e4
LT
2219 spin_lock_init(&sx_port[i].lock);
2220 }
d61780c0 2221
1da177e4
LT
2222 func_exit();
2223 return 0;
2224}
2225
2226static void sx_release_drivers(void)
2227{
2228 func_enter();
2229
1da177e4
LT
2230 tty_unregister_driver(specialix_driver);
2231 put_tty_driver(specialix_driver);
2232 func_exit();
2233}
2234
d61780c0
JG
2235/*
2236 * This routine must be called by kernel at boot time
1da177e4
LT
2237 */
2238static int __init specialix_init(void)
2239{
2240 int i;
2241 int found = 0;
2242
2243 func_enter();
2244
2245 printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
2246 printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
d2fbd0f2
AC
2247 if (sx_rtscts)
2248 printk(KERN_INFO
2249 "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
2250 else
2251 printk(KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
d61780c0 2252
1da177e4 2253 for (i = 0; i < SX_NBOARD; i++)
34af946a 2254 spin_lock_init(&sx_board[i].lock);
1da177e4
LT
2255
2256 if (sx_init_drivers()) {
2257 func_exit();
2258 return -EIO;
2259 }
2260
d61780c0 2261 for (i = 0; i < SX_NBOARD; i++)
1da177e4
LT
2262 if (sx_board[i].base && !sx_probe(&sx_board[i]))
2263 found++;
2264
2265#ifdef CONFIG_PCI
2266 {
2267 struct pci_dev *pdev = NULL;
2268
a72492bd 2269 i = 0;
1da177e4
LT
2270 while (i < SX_NBOARD) {
2271 if (sx_board[i].flags & SX_BOARD_PRESENT) {
2272 i++;
2273 continue;
2274 }
a72492bd
AC
2275 pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX,
2276 PCI_DEVICE_ID_SPECIALIX_IO8, pdev);
2277 if (!pdev)
2278 break;
1da177e4
LT
2279
2280 if (pci_enable_device(pdev))
2281 continue;
2282
2283 sx_board[i].irq = pdev->irq;
2284
a72492bd 2285 sx_board[i].base = pci_resource_start(pdev, 2);
1da177e4
LT
2286
2287 sx_board[i].flags |= SX_BOARD_IS_PCI;
2288 if (!sx_probe(&sx_board[i]))
a72492bd 2289 found++;
1da177e4 2290 }
606d099c
AC
2291 /* May exit pci_get sequence early with lots of boards */
2292 if (pdev != NULL)
2293 pci_dev_put(pdev);
1da177e4
LT
2294 }
2295#endif
2296
2297 if (!found) {
2298 sx_release_drivers();
2299 printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
2300 func_exit();
2301 return -EIO;
2302 }
2303
2304 func_exit();
2305 return 0;
2306}
2307
2308static int iobase[SX_NBOARD] = {0,};
d2fbd0f2 2309static int irq[SX_NBOARD] = {0,};
1da177e4
LT
2310
2311module_param_array(iobase, int, NULL, 0);
2312module_param_array(irq, int, NULL, 0);
2313module_param(sx_debug, int, 0);
d2fbd0f2 2314module_param(sx_rtscts, int, 0);
1da177e4 2315module_param(sx_rxfifo, int, 0);
1da177e4
LT
2316
2317/*
2318 * You can setup up to 4 boards.
2319 * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
d61780c0
JG
2320 * You should specify the IRQs too in that case "irq=....,...".
2321 *
1da177e4 2322 * More than 4 boards in one computer is not possible, as the card can
d61780c0 2323 * only use 4 different interrupts.
1da177e4
LT
2324 *
2325 */
2326static int __init specialix_init_module(void)
2327{
2328 int i;
2329
2330 func_enter();
2331
1da177e4 2332 if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
a72492bd 2333 for (i = 0; i < SX_NBOARD; i++) {
1da177e4
LT
2334 sx_board[i].base = iobase[i];
2335 sx_board[i].irq = irq[i];
a72492bd 2336 sx_board[i].count = 0;
1da177e4
LT
2337 }
2338 }
2339
2340 func_exit();
2341
2342 return specialix_init();
2343}
d61780c0 2344
1da177e4
LT
2345static void __exit specialix_exit_module(void)
2346{
2347 int i;
d61780c0 2348
1da177e4
LT
2349 func_enter();
2350
2351 sx_release_drivers();
2352 for (i = 0; i < SX_NBOARD; i++)
d61780c0 2353 if (sx_board[i].flags & SX_BOARD_PRESENT)
1da177e4 2354 sx_release_io_range(&sx_board[i]);
1da177e4
LT
2355 func_exit();
2356}
2357
fd0f5c54 2358static struct pci_device_id specialx_pci_tbl[] __devinitdata __used = {
7691030b
CS
2359 { PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },
2360 { }
2361};
2362MODULE_DEVICE_TABLE(pci, specialx_pci_tbl);
2363
1da177e4
LT
2364module_init(specialix_init_module);
2365module_exit(specialix_exit_module);
2366
2367MODULE_LICENSE("GPL");
5350d3ba 2368MODULE_ALIAS_CHARDEV_MAJOR(SPECIALIX_NORMAL_MAJOR);