~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/specialix.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.