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