ia64/linux-2.6.18-xen.hg

annotate drivers/char/specialix.c @ 893:f994bfe9b93b

linux/blktap2: reduce TLB flush scope

c/s 885 added very coarse TLB flushing. Since these flushes always
follow single page updates, single page flushes (when available) are
sufficient.

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