root/drivers/char/pcxx.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. memwinon
  2. memwinoff
  3. globalwinon
  4. rxwinon
  5. txwinon
  6. memoff
  7. assertgwinon
  8. assertmemoff
  9. pcxe_sched_event
  10. pcxx_error
  11. pcxx_waitcarrier
  12. pcxe_open
  13. shutdown
  14. pcxe_close
  15. pcxe_hangup
  16. pcxe_write
  17. pcxe_put_char
  18. pcxe_write_room
  19. pcxe_chars_in_buffer
  20. pcxe_flush_buffer
  21. pcxe_flush_chars
  22. pcxx_setup
  23. pcxe_init
  24. pcxxpoll
  25. doevent
  26. pcxxdelay
  27. fepcmd
  28. termios2digi_c
  29. termios2digi_i
  30. termios2digi_h
  31. pcxxparam
  32. receive_data
  33. pcxe_ioctl
  34. pcxe_set_termios
  35. do_pcxe_bh
  36. do_softint
  37. pcxe_stop
  38. pcxe_throttle
  39. pcxe_unthrottle
  40. pcxe_start
  41. digi_send_break
  42. setup_empty_event

   1 /*
   2  *  linux/drivers/char/pcxe.c
   3  * 
   4  *  Written by Troy De Jongh, November, 1994
   5  *
   6  *  Copyright (C) 1994,1995 Troy De Jongh
   7  *  This software may be used and distributed according to the terms 
   8  *  of the GNU Public License.
   9  *
  10  *  This driver is for the DigiBoard PC/Xe and PC/Xi line of products.
  11  *
  12  *  This driver does NOT support DigiBoard's fastcook FEP option and
  13  *  does not support the transparent print (i.e. digiprint) option.
  14  *
  15  * This Driver is currently maintained by Christoph Lameter (clameter@fuller.edu)
  16  * Please contact the mailing list for problems first. 
  17  *
  18  * Sources of Information:
  19  * 1. The Linux Digiboard Page at http://private.fuller.edu/clameter/digi.html
  20  * 2. The Linux Digiboard Mailing list at digiboard@list.fuller.edu
  21  *    (Simply write a message to introduce yourself to subscribe)
  22  *
  23  *  1.5.2 Fall 1995 Bug fixes by David Nugent
  24  *  1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory
  25  *              allocation harmonized with 1.3.X Series.
  26  *  1.5.4 March 30, 1996 Christoph Lameter: Fixup for 1.3.81. Use init_bh
  27  *              instead of direct assignment to kernel arrays.
  28  *  1.5.5 April 5, 1996 Major device numbers corrected.
  29  *              Mike McLagan<mike.mclagan@linux.org>: Add setup
  30  *              variable handling, instead of using the old pcxxconfig.h
  31  *  1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup.
  32  *              Call out devices changed to /dev/cudxx.
  33  *
  34  */
  35 
  36 #undef SPEED_HACK
  37 /* If you define SPEED_HACK then you get the following Baudrate translation
  38    19200 = 57600
  39    38400 = 115K
  40    The driver supports the native 57.6K and 115K Baudrates under Linux, but
  41    some distributions like Slackware 3.0 dont like these high baudrates.
  42 */
  43 
  44 #include <linux/mm.h>
  45 #include <linux/ioport.h>
  46 #include <linux/errno.h>
  47 #include <linux/signal.h>
  48 #include <linux/sched.h>
  49 #include <linux/timer.h>
  50 #include <linux/interrupt.h>
  51 #include <linux/tty.h>
  52 #include <linux/tty_flip.h>
  53 #include <linux/major.h>
  54 #include <linux/string.h>
  55 #include <linux/fcntl.h>
  56 #include <linux/ptrace.h>
  57 #include <linux/delay.h>
  58 #include <linux/serial.h>
  59 #include <linux/tty_driver.h>
  60 #include <linux/malloc.h>
  61 #include <linux/string.h>
  62 #include <linux/ctype.h>
  63 
  64 #include <asm/system.h>
  65 #include <asm/io.h>
  66 #include <asm/segment.h>
  67 #include <asm/bitops.h>
  68 
  69 #define VERSION         "1.5.6"
  70 static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.6.  Christoph Lameter <clameter@fuller.edu>.";
  71 
  72 /*#define       DEFAULT_HW_FLOW 1 */
  73 /*#define       DEBUG_IOCTL */
  74 
  75 #include "digi.h"
  76 #include "fep.h"
  77 #include "pcxx.h"
  78 #include "digi_fep.h"
  79 #include "digi_bios.h"
  80 
  81 /* Define one default setting if no digi= config line is used.
  82  * Default is ALTPIN = ON, PC/16E, 16 ports, I/O 200h Memory 0D0000h
  83  */
  84 static struct board_info boards[MAX_DIGI_BOARDS] = { {  ENABLED, 0, ON, 16, 0x200, 0xd0000,0 } };
  85  
  86 static int numcards = 1;
  87 static int nbdevs = 0;
  88  
  89 static struct channel    *digi_channels;
  90 static struct tty_struct **pcxe_table;
  91 static struct termios    **pcxe_termios;
  92 static struct termios    **pcxe_termios_locked;
  93  
  94 int pcxx_ncook=sizeof(pcxx_cook);
  95 int pcxx_nbios=sizeof(pcxx_bios);
  96 
  97 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
  98 #define pcxxassert(x, msg)  if(!(x)) pcxx_error(__LINE__, msg)
  99 
 100 #define FEPTIMEOUT 200000  
 101 #define SERIAL_TYPE_NORMAL      1
 102 #define SERIAL_TYPE_CALLOUT     2
 103 #define PCXE_EVENT_HANGUP   1
 104 
 105 struct tty_driver pcxe_driver;
 106 struct tty_driver pcxe_callout;
 107 static int pcxe_refcount;
 108 
 109 DECLARE_TASK_QUEUE(tq_pcxx);
 110 
 111 static void pcxxpoll(void);
 112 static void pcxxdelay(int);
 113 static void fepcmd(struct channel *, int, int, int, int, int);
 114 static void pcxe_put_char(struct tty_struct *, unsigned char);
 115 static void pcxe_flush_chars(struct tty_struct *);
 116 static void pcxx_error(int, char *);
 117 static void pcxe_close(struct tty_struct *, struct file *);
 118 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
 119 static void pcxe_set_termios(struct tty_struct *, struct termios *);
 120 static int pcxe_write(struct tty_struct *, int, const unsigned char *, int);
 121 static int pcxe_write_room(struct tty_struct *);
 122 static int pcxe_chars_in_buffer(struct tty_struct *);
 123 static void pcxe_flush_buffer(struct tty_struct *);
 124 static void doevent(int);
 125 static void receive_data(struct channel *);
 126 static void pcxxparam(struct tty_struct *, struct channel *ch);
 127 static void do_softint(void *);
 128 static inline void pcxe_sched_event(struct channel *, int);
 129 static void do_pcxe_bh(void);
 130 static void pcxe_start(struct tty_struct *);
 131 static void pcxe_stop(struct tty_struct *);
 132 static void pcxe_throttle(struct tty_struct *);
 133 static void pcxe_unthrottle(struct tty_struct *);
 134 static void digi_send_break(struct channel *ch, int msec);
 135 static void shutdown(struct channel *);
 136 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
 137 static inline void memwinon(struct board_info *b, unsigned int win);
 138 static inline void memwinoff(struct board_info *b, unsigned int win);
 139 static inline void globalwinon(struct channel *ch);
 140 static inline void rxwinon(struct channel *ch);
 141 static inline void txwinon(struct channel *ch);
 142 static inline void memoff(struct channel *ch);
 143 static inline void assertgwinon(struct channel *ch);
 144 static inline void assertmemoff(struct channel *ch);
 145 
 146 #define TZ_BUFSZ 4096
 147 
 148 static inline struct channel *chan(register struct tty_struct *tty)
 149 {
 150         if (tty) {
 151                 register struct channel *ch=(struct channel *)tty->driver_data;
 152                 if (ch >= digi_channels && ch < digi_channels+nbdevs) {
 153                         if (ch->magic==PCXX_MAGIC)
 154                                 return ch;
 155                 }
 156         }
 157         return NULL;
 158 }
 159 
 160 /* These inline routines are to turn board memory on and off */
 161 static inline void memwinon(struct board_info *b, unsigned int win)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         if(b->type == PCXEVE)
 164                 outb_p(FEPWIN|win, b->port+1);
 165         else
 166                 outb_p(inb(b->port)|FEPMEM, b->port);
 167 }
 168 
 169 static inline void memwinoff(struct board_info *b, unsigned int win)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171         outb_p(inb(b->port)&~FEPMEM, b->port);
 172         if(b->type == PCXEVE)
 173                 outb_p(0, b->port + 1);
 174 }
 175 
 176 static inline void globalwinon(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178         if(ch->board->type == PCXEVE)
 179                 outb_p(FEPWIN, ch->board->port+1);
 180         else
 181                 outb_p(FEPMEM, ch->board->port);
 182 }
 183 
 184 static inline void rxwinon(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186         if(ch->rxwin == 0)
 187                 outb_p(FEPMEM, ch->board->port);
 188         else 
 189                 outb_p(ch->rxwin, ch->board->port+1);
 190 }
 191 
 192 static inline void txwinon(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         if(ch->txwin == 0)
 195                 outb_p(FEPMEM, ch->board->port);
 196         else
 197                 outb_p(ch->txwin, ch->board->port+1);
 198 }
 199 
 200 static inline void memoff(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202         outb_p(0, ch->board->port);
 203         if(ch->board->type == PCXEVE)
 204                 outb_p(0, ch->board->port+1);
 205 }
 206 
 207 static inline void assertgwinon(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209         if(ch->board->type != PCXEVE)
 210                 pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
 211 }
 212 
 213 static inline void assertmemoff(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         if(ch->board->type != PCXEVE)
 216                 pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
 217 }
 218 
 219 static inline void pcxe_sched_event(struct channel *info, int event)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221         info->event |= 1 << event;
 222         queue_task_irq_off(&info->tqueue, &tq_pcxx);
 223         mark_bh(DIGI_BH);
 224 }
 225 
 226 static void pcxx_error(int line, char *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
 229 }
 230 
 231 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
     /* [previous][next][first][last][top][bottom][index][help] */
 232 {
 233         struct wait_queue wait = { current, NULL };
 234         int     retval = 0;
 235         int     do_clocal = 0;
 236 
 237         if (info->asyncflags & ASYNC_CALLOUT_ACTIVE) {
 238                 if (info->normal_termios.c_cflag & CLOCAL)
 239                         do_clocal = 1;
 240         } else {
 241                 if (tty->termios->c_cflag & CLOCAL)
 242                         do_clocal = 1;
 243         }
 244 
 245         /*
 246          * Block waiting for the carrier detect and the line to become free
 247          */
 248 
 249         retval = 0;
 250         add_wait_queue(&info->open_wait, &wait);
 251         info->count--;
 252         info->blocked_open++;
 253 
 254         for (;;) {
 255                 cli();
 256                 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0) {
 257                         globalwinon(info);
 258                         info->omodem |= DTR|RTS;
 259                         fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
 260                         memoff(info);
 261                 }
 262                 sti();
 263                 current->state = TASK_INTERRUPTIBLE;
 264                 if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
 265                         if(info->asyncflags & ASYNC_HUP_NOTIFY)
 266                                 retval = -EAGAIN;
 267                         else
 268                                 retval = -ERESTARTSYS;  
 269                         break;
 270                 }
 271                 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0 &&
 272                     (info->asyncflags & ASYNC_CLOSING) == 0 &&
 273                         (do_clocal || (info->imodem & info->dcd)))
 274                         break;
 275                 if(current->signal & ~current->blocked) {
 276                         retval = -ERESTARTSYS;
 277                         break;
 278                 }
 279                 schedule();
 280         }
 281         current->state = TASK_RUNNING;
 282         remove_wait_queue(&info->open_wait, &wait);
 283 
 284         if(!tty_hung_up_p(filp))
 285                 info->count++;
 286         info->blocked_open--;
 287 
 288         return retval;
 289 }       
 290 
 291 
 292 /* static  ???why static??? */
 293 int pcxe_open(struct tty_struct *tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 294 {
 295         volatile struct board_chan *bc;
 296         struct channel *ch;
 297         unsigned long flags;
 298         int line;
 299         int boardnum;
 300         int retval;
 301 
 302         line = MINOR(tty->device) - tty->driver.minor_start;
 303 
 304         if(line < 0 || line >= nbdevs) {
 305                 printk("line out of range in pcxe_open\n");
 306                 tty->driver_data = NULL;
 307                 return(-ENODEV);
 308         }
 309 
 310         for(boardnum=0;boardnum<numcards;boardnum++)
 311                 if ((line >= boards[boardnum].first_minor) && 
 312                         (line <= boards[boardnum].first_minor + boards[boardnum].numports))
 313                 break;
 314 
 315         if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
 316                 (line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
 317                 tty->driver_data = NULL;   /* Mark this device as 'down' */
 318                 return(-ENODEV);
 319         }
 320 
 321         ch = digi_channels+line;
 322 
 323         if(ch->brdchan == 0) {
 324                 tty->driver_data = NULL;
 325                 return(-ENODEV);
 326         }
 327 
 328         /*
 329          * If the device is in the middle of being closed, then block
 330          * until it's done, and then try again.
 331          */
 332         if(ch->asyncflags & ASYNC_CLOSING) {
 333                 interruptible_sleep_on(&ch->close_wait);
 334                 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
 335                         return -EAGAIN;
 336                 else
 337                         return -ERESTARTSYS;
 338         }
 339 
 340         save_flags(flags);
 341         cli();
 342         ch->count++;
 343         tty->driver_data = ch;
 344         ch->tty = tty;
 345 
 346         if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
 347                 unsigned int head;
 348 
 349                 globalwinon(ch);
 350                 ch->statusflags = 0;
 351                 bc=ch->brdchan;
 352                 ch->imodem = bc->mstat;
 353                 head = bc->rin;
 354                 bc->rout = head;
 355                 ch->tty = tty;
 356                 pcxxparam(tty,ch);
 357                 ch->imodem = bc->mstat;
 358                 bc->idata = 1;
 359                 ch->omodem = DTR|RTS;
 360                 fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
 361                 memoff(ch);
 362                 ch->asyncflags |= ASYNC_INITIALIZED;
 363         }
 364         restore_flags(flags);
 365 
 366         if(ch->asyncflags & ASYNC_CLOSING) {
 367                 interruptible_sleep_on(&ch->close_wait);
 368                 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
 369                         return -EAGAIN;
 370                 else
 371                         return -ERESTARTSYS;
 372         }
 373         /*
 374          * If this is a callout device, then just make sure the normal
 375          * device isn't being used.
 376          */
 377         if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
 378                 if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
 379                         return -EBUSY;
 380                 if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) {
 381                         if ((ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
 382                                 (ch->session != current->session))
 383                             return -EBUSY;
 384                         if((ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
 385                             (ch->pgrp != current->pgrp))
 386                             return -EBUSY;
 387                 }
 388                 ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
 389         }
 390         else {
 391                 if (filp->f_flags & O_NONBLOCK) {
 392                         if(ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
 393                                 return -EBUSY;
 394                 }
 395                 else {
 396                         if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
 397                                 return retval;
 398                 }
 399                 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
 400         }
 401         
 402         save_flags(flags);
 403         cli();
 404         if((ch->count == 1) && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
 405                 if(tty->driver.subtype == SERIAL_TYPE_NORMAL)
 406                         *tty->termios = ch->normal_termios;
 407                 else 
 408                         *tty->termios = ch->callout_termios;
 409                 globalwinon(ch);
 410                 pcxxparam(tty,ch);
 411                 memoff(ch);
 412         }
 413 
 414         ch->session = current->session;
 415         ch->pgrp = current->pgrp;
 416         restore_flags(flags);
 417         return 0;
 418 } 
 419 
 420 static void shutdown(struct channel *info)
     /* [previous][next][first][last][top][bottom][index][help] */
 421 {
 422         unsigned long flags;
 423         volatile struct board_chan *bc;
 424         struct tty_struct *tty;
 425 
 426         if (!(info->asyncflags & ASYNC_INITIALIZED)) 
 427                 return;
 428 
 429         save_flags(flags);
 430         cli();
 431         globalwinon(info);
 432 
 433         bc = info->brdchan;
 434         if(bc)
 435                 bc->idata = 0;
 436 
 437         tty = info->tty;
 438 
 439         /*
 440          * If we're a modem control device and HUPCL is on, drop RTS & DTR.
 441          */
 442         if(tty->termios->c_cflag & HUPCL) {
 443                 info->omodem &= ~(RTS|DTR);
 444                 fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
 445         }
 446 
 447         memoff(info);
 448         info->asyncflags &= ~ASYNC_INITIALIZED;
 449         restore_flags(flags);
 450 }
 451 
 452 
 453 static void pcxe_close(struct tty_struct * tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 454 {
 455         struct channel *info;
 456 
 457         if ((info=chan(tty))!=NULL) {
 458                 unsigned long flags;
 459                 save_flags(flags);
 460                 cli();
 461 
 462                 if(tty_hung_up_p(filp)) {
 463                         restore_flags(flags);
 464                         return;
 465                 }
 466                 if (info->count-- > 1) {
 467                         restore_flags(flags);
 468                         return;
 469                 }
 470                 if (info->count < 0) {
 471                         info->count = 0;
 472                 }
 473 
 474                 info->asyncflags |= ASYNC_CLOSING;
 475         
 476                 /*
 477                 * Save the termios structure, since this port may have
 478                 * separate termios for callout and dialin.
 479                 */
 480                 if(info->asyncflags & ASYNC_NORMAL_ACTIVE)
 481                         info->normal_termios = *tty->termios;
 482                 if(info->asyncflags & ASYNC_CALLOUT_ACTIVE)
 483                         info->callout_termios = *tty->termios;
 484                 tty->closing = 1;
 485                 if(info->asyncflags & ASYNC_INITIALIZED) {
 486                         setup_empty_event(tty,info);            
 487                         tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
 488                 }
 489         
 490                 if(tty->driver.flush_buffer)
 491                         tty->driver.flush_buffer(tty);
 492                 if(tty->ldisc.flush_buffer)
 493                         tty->ldisc.flush_buffer(tty);
 494                 shutdown(info);
 495                 tty->closing = 0;
 496                 info->event = 0;
 497                 info->tty = NULL;
 498                 if(tty->ldisc.num != ldiscs[N_TTY].num) {
 499                         if(tty->ldisc.close)
 500                                 (tty->ldisc.close)(tty);
 501                         tty->ldisc = ldiscs[N_TTY];
 502                         tty->termios->c_line = N_TTY;
 503                         if(tty->ldisc.open)
 504                                 (tty->ldisc.open)(tty);
 505                 }
 506                 if(info->blocked_open) {
 507                         if(info->close_delay) {
 508                                 current->state = TASK_INTERRUPTIBLE;
 509                                 current->timeout = jiffies + info->close_delay;
 510                                 schedule();
 511                         }
 512                         wake_up_interruptible(&info->open_wait);
 513                 }
 514                 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
 515                                                           ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
 516                 wake_up_interruptible(&info->close_wait);
 517                 restore_flags(flags);
 518         }
 519 }
 520 
 521 
 522 void pcxe_hangup(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524         struct channel *ch;
 525 
 526         if ((ch=chan(tty))!=NULL) {
 527                 unsigned long flags;
 528 
 529                 save_flags(flags);
 530                 cli();
 531                 shutdown(ch);
 532                 ch->event = 0;
 533                 ch->count = 0;
 534                 ch->tty = NULL;
 535                 ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
 536                 wake_up_interruptible(&ch->open_wait);
 537                 restore_flags(flags);
 538         }
 539 }
 540 
 541 
 542 
 543 static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 544 {
 545         struct channel *ch;
 546         volatile struct board_chan *bc;
 547         int total, remain, size, stlen;
 548         unsigned int head, tail;
 549         unsigned long flags;
 550 
 551         /* printk("Entering pcxe_write()\n"); */
 552 
 553         if ((ch=chan(tty))==NULL)
 554                 return 0;
 555 
 556         bc = ch->brdchan;
 557         size = ch->txbufsize;
 558 
 559         if (from_user) {
 560 
 561                 save_flags(flags);
 562                 cli();
 563                 globalwinon(ch);
 564                 head = bc->tin & (size - 1);
 565                 tail = bc->tout;
 566                 if (tail != bc->tout)
 567                         tail = bc->tout;
 568                 tail &= (size - 1);
 569                 stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
 570                 count = MIN(stlen, count);
 571                 if (count) {
 572                         if (verify_area(VERIFY_READ, (char*)buf, count))
 573                                 count=0;
 574                         else memcpy_fromfs(ch->tmp_buf, buf, count);
 575                 }
 576                 buf = ch->tmp_buf;
 577                 memoff(ch);
 578                 restore_flags(flags);
 579         }
 580 
 581         /*
 582          * All data is now local
 583          */
 584 
 585         total = 0;
 586         save_flags(flags);
 587         cli();
 588         globalwinon(ch);
 589         head = bc->tin & (size - 1);
 590         tail = bc->tout;
 591         if (tail != bc->tout)
 592                 tail = bc->tout;
 593         tail &= (size - 1);
 594         if (head >= tail) {
 595                 remain = size - (head - tail) - 1;
 596                 stlen = size - head;
 597         }
 598         else {
 599                 remain = tail - head - 1;
 600                 stlen = remain;
 601         }
 602         count = MIN(remain, count);
 603 
 604         txwinon(ch);
 605         while (count > 0) {
 606                 stlen = MIN(count, stlen);
 607                 memcpy(ch->txptr + head, buf, stlen);
 608                 buf += stlen;
 609                 count -= stlen;
 610                 total += stlen;
 611                 head += stlen;
 612                 if (head >= size) {
 613                         head = 0;
 614                         stlen = tail;
 615                 }
 616         }
 617         ch->statusflags |= TXBUSY;
 618         globalwinon(ch);
 619         bc->tin = head;
 620         if ((ch->statusflags & LOWWAIT) == 0) {
 621                 ch->statusflags |= LOWWAIT;
 622                 bc->ilow = 1;
 623         }
 624         memoff(ch);
 625         restore_flags(flags);
 626 
 627         return(total);
 628 }
 629 
 630 
 631 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
     /* [previous][next][first][last][top][bottom][index][help] */
 632 {
 633         pcxe_write(tty, 0, &c, 1);
 634         return;
 635 }
 636 
 637 
 638 static int pcxe_write_room(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 639 {
 640         struct channel *ch;
 641         int remain;
 642 
 643         remain = 0;
 644         if ((ch=chan(tty))!=NULL) {
 645                 volatile struct board_chan *bc;
 646                 unsigned int head, tail;
 647                 unsigned long flags;
 648 
 649                 save_flags(flags);
 650                 cli();
 651                 globalwinon(ch);
 652 
 653                 bc = ch->brdchan;
 654                 head = bc->tin & (ch->txbufsize - 1);
 655                 tail = bc->tout;
 656                 if (tail != bc->tout)
 657                         tail = bc->tout;
 658                 tail &= (ch->txbufsize - 1);
 659 
 660                 if((remain = tail - head - 1) < 0 )
 661                         remain += ch->txbufsize;
 662 
 663                 if (remain && (ch->statusflags & LOWWAIT) == 0) {
 664                         ch->statusflags |= LOWWAIT;
 665                         bc->ilow = 1;
 666                 }
 667                 memoff(ch);
 668                 restore_flags(flags);
 669         }
 670 
 671         return remain;
 672 }
 673 
 674 
 675 static int pcxe_chars_in_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 676 {
 677         int chars;
 678         unsigned int ctail, head, tail;
 679         int remain;
 680         unsigned long flags;
 681         struct channel *ch;
 682         volatile struct board_chan *bc;
 683 
 684         if ((ch=chan(tty))==NULL)
 685                 return(0);
 686 
 687         save_flags(flags);
 688         cli();
 689         globalwinon(ch);
 690 
 691         bc = ch->brdchan;
 692         tail = bc->tout;
 693         head = bc->tin;
 694         ctail = ch->mailbox->cout;
 695         if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
 696                 chars = 0;
 697         else {
 698                 head = bc->tin & (ch->txbufsize - 1);
 699                 tail &= (ch->txbufsize - 1);
 700                 if((remain = tail - head - 1) < 0 )
 701                         remain += ch->txbufsize;
 702 
 703                 chars = (int)(ch->txbufsize - remain);
 704 
 705                 /* 
 706                  * Make it possible to wakeup anything waiting for output
 707                  * in tty_ioctl.c, etc.
 708                  */
 709                 if(!(ch->statusflags & EMPTYWAIT))
 710                         setup_empty_event(tty,ch);
 711         }
 712 
 713         memoff(ch);
 714         restore_flags(flags);
 715 
 716         return(chars);
 717 }
 718 
 719 
 720 static void pcxe_flush_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 721 {
 722         unsigned int tail;
 723         volatile struct board_chan *bc;
 724         struct channel *ch;
 725         unsigned long flags;
 726 
 727         if ((ch=chan(tty))==NULL)
 728                 return;
 729 
 730         save_flags(flags);
 731         cli();
 732 
 733         globalwinon(ch);
 734         bc = ch->brdchan;
 735         tail = bc->tout;
 736         fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
 737 
 738         memoff(ch);
 739         restore_flags(flags);
 740 
 741         wake_up_interruptible(&tty->write_wait);
 742         if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
 743                 (tty->ldisc.write_wakeup)(tty);
 744 }
 745 
 746 static void pcxe_flush_chars(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 747 {
 748         struct channel * ch;
 749 
 750         if ((ch=chan(tty))!=NULL) {
 751                 unsigned long flags;
 752 
 753                 save_flags(flags);
 754                 cli();
 755                 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
 756                         setup_empty_event(tty,ch);
 757                 restore_flags(flags);
 758         }
 759 }
 760 
 761 /* Flag if lilo configuration option is used. If so the
 762  * default settings are removed
 763  */
 764 
 765 static int liloconfig=0;
 766 
 767 void pcxx_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 768 {
 769 
 770         struct board_info board;
 771         int               i, j, last;
 772         char              *temp, *t2;
 773         unsigned          len;
 774 
 775 #if 0
 776         if (!numcards)
 777                 memset(&boards, 0, sizeof(boards));
 778 #endif
 779         if (liloconfig==0) { liloconfig=1;numcards=0; }
 780 
 781         memset(&board, 0, sizeof(board));
 782 
 783         for(last=0,i=1;i<=ints[0];i++)
 784                 switch(i)
 785                 {
 786                         case 1:
 787                                 board.status = ints[i];
 788                                 last = i;
 789                                 break;
 790 
 791                         case 2:
 792                                 board.type = ints[i];
 793                                 last = i;
 794                                 break;
 795 
 796                         case 3:
 797                                 board.altpin = ints[i];
 798                                 last = i;
 799                                 break;
 800 
 801                         case 4:
 802                                 board.numports = ints[i];
 803                                 last = i;
 804                                 break;
 805 
 806                         case 5:
 807                                 board.port = ints[i];
 808                                 last = i;
 809                                 break;
 810 
 811                         case 6:
 812                                 board.membase = ints[i];
 813                                 last = i;
 814                                 break;
 815 
 816                         default:
 817                                 printk("PC/Xx: Too many integer parms\n");
 818                                 return;
 819                 }
 820 
 821         
 822         while (str && *str) 
 823         {
 824                 /* find the next comma or terminator */
 825                 temp = str;
 826                 while (*temp && (*temp != ','))
 827                         temp++;
 828 
 829                 if (!*temp)
 830                         temp = NULL;
 831                 else
 832                         *temp++ = 0;
 833 
 834                 i = last + 1;
 835 
 836                 switch(i)
 837                 {
 838                         case 1:
 839                                 len = strlen(str);
 840                                 if (strncmp("Disable", str, len) == 0) 
 841                                         board.status = 0;
 842                                 else
 843                                         if (strncmp("Enable", str, len) == 0)
 844                                                 board.status = 1;
 845                                         else
 846                                         {
 847                                                 printk("PC/Xx: Invalid status %s\n", str);
 848                                                 return;
 849                                         }
 850                                 last = i;
 851                                 break;
 852 
 853                         case 2:
 854                                 for(j=0;j<PCXX_NUM_TYPES;j++)
 855                                         if (strcmp(board_desc[j], str) == 0)
 856                                                 break;
 857 
 858                                 if (i<PCXX_NUM_TYPES) 
 859                                         board.type = j;
 860                                 else
 861                                 {
 862                                         printk("PC/Xx: Invalid board name: %s\n", str);
 863                                         return;
 864                                 }
 865                                 last = i;
 866                                 break;
 867 
 868                         case 3:
 869                                 len = strlen(str);
 870                                 if (strncmp("Disable", str, len) == 0) 
 871                                         board.altpin = 0;
 872                                 else
 873                                         if (strncmp("Enable", str, len) == 0)
 874                                                 board.altpin = 1;
 875                                         else
 876                                         {
 877                                                 printk("PC/Xx: Invalid altpin %s\n", str);
 878                                                 return;
 879                                         }
 880                                 last = i;
 881                                 break;
 882 
 883                         case 4:
 884                                 t2 = str;
 885                                 while (isdigit(*t2))
 886                                         t2++;
 887 
 888                                 if (*t2)
 889                                 {
 890                                         printk("PC/Xx: Invalid port count %s\n", str);
 891                                         return;
 892                                 }
 893 
 894                                 board.numports = simple_strtoul(str, NULL, 0);
 895                                 last = i;
 896                                 break;
 897 
 898                         case 5:
 899                                 t2 = str;
 900                                 while (isxdigit(*t2))
 901                                         t2++;
 902 
 903                                 if (*t2)
 904                                 {
 905                                         printk("PC/Xx: Invalid port count %s\n", str);
 906                                         return;
 907                                 }
 908 
 909                                 board.port = simple_strtoul(str, NULL, 16);
 910                                 last = i;
 911                                 break;
 912 
 913                         case 6:
 914                                 t2 = str;
 915                                 while (isxdigit(*t2))
 916                                         t2++;
 917 
 918                                 if (*t2)
 919                                 {
 920                                         printk("PC/Xx: Invalid memory base %s\n", str);
 921                                         return;
 922                                 }
 923 
 924                                 board.membase = simple_strtoul(str, NULL, 16);
 925                                 last = i;
 926                                 break;
 927 
 928                         default:
 929                                 printk("PC/Xx: Too many string parms\n");
 930                                 return;
 931                 }
 932                 str = temp;
 933         }
 934 
 935         if (last < 6)  
 936         {
 937                 printk("PC/Xx: Insufficient parms specified\n");
 938                 return;
 939         }
 940  
 941         /* I should REALLY validate the stuff here */
 942 
 943         memcpy(&boards[numcards],&board, sizeof(board));
 944         printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n", 
 945                 numcards, board_desc[board.type], board_mem[board.type], 
 946                 board.numports, board.port, (unsigned int) board.membase);
 947 
 948         /* keep track of my initial minor number */
 949         if (numcards)
 950                 boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
 951         else
 952                 boards[numcards].first_minor = 0;
 953 
 954         /* yeha!  string parameter was successful! */
 955         numcards++;
 956 }
 957 
 958 
 959 int pcxe_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 960 {
 961 #if 0
 962         ulong save_loops_per_sec;
 963 #endif
 964 
 965         ulong flags, memory_seg=0, memory_size;
 966         int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
 967         unchar *fepos, *memaddr, *bios, v;
 968         volatile struct global_data *gd;
 969         struct board_info *bd;
 970         volatile struct board_chan *bc;
 971         struct channel *ch;
 972 
 973         printk("%s\n", banner);
 974 
 975         if (numcards <= 0)
 976         {
 977                 printk("PC/Xx: No cards configured, exiting.\n");
 978                 return(0);
 979         }
 980 
 981         for (i=0;i<numcards;i++)
 982                 nbdevs += boards[i].numports;
 983 
 984         if (nbdevs <= 0)
 985         {
 986                 printk("PC/Xx: No devices activated, exiting.\n");
 987                 return(0);
 988         }
 989 
 990         /*
 991          * this turns out to be more memory efficient, as there are no 
 992          * unused spaces.
 993          */
 994         digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
 995         if (!digi_channels)
 996                 panic("Unable to allocate digi_channel struct");
 997 
 998         pcxe_table =  kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
 999         if (!pcxe_table)
1000                 panic("Unable to allocate pcxe_table struct");
1001 
1002         pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
1003         if (!pcxe_termios)
1004                 panic("Unable to allocate pcxe_termios struct");
1005 
1006         pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
1007         if (!pcxe_termios_locked)
1008                 panic("Unable to allocate pcxe_termios_locked struct");
1009 
1010 
1011         init_bh(DIGI_BH,do_pcxe_bh);
1012         enable_bh(DIGI_BH);
1013 
1014         timer_table[DIGI_TIMER].fn = pcxxpoll;
1015         timer_table[DIGI_TIMER].expires = 0;
1016 
1017         memset(&pcxe_driver, 0, sizeof(struct tty_driver));
1018         pcxe_driver.magic = TTY_DRIVER_MAGIC;
1019         pcxe_driver.name = "cud";
1020         pcxe_driver.major = DIGI_MAJOR; 
1021         pcxe_driver.minor_start = 0;
1022 
1023         pcxe_driver.num = nbdevs;
1024 
1025         pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
1026         pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
1027         pcxe_driver.init_termios = tty_std_termios;
1028         pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1029         pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
1030         pcxe_driver.refcount = &pcxe_refcount;
1031 
1032         pcxe_driver.table = pcxe_table;
1033         pcxe_driver.termios = pcxe_termios;
1034         pcxe_driver.termios_locked = pcxe_termios_locked;
1035 
1036         pcxe_driver.open = pcxe_open;
1037         pcxe_driver.close = pcxe_close;
1038         pcxe_driver.write = pcxe_write;
1039         pcxe_driver.put_char = pcxe_put_char;
1040         pcxe_driver.flush_chars = pcxe_flush_chars;
1041         pcxe_driver.write_room = pcxe_write_room;
1042         pcxe_driver.chars_in_buffer = pcxe_chars_in_buffer;
1043         pcxe_driver.flush_buffer = pcxe_flush_buffer;
1044         pcxe_driver.ioctl = pcxe_ioctl;
1045         pcxe_driver.throttle = pcxe_throttle;
1046         pcxe_driver.unthrottle = pcxe_unthrottle;
1047         pcxe_driver.set_termios = pcxe_set_termios;
1048         pcxe_driver.stop = pcxe_stop;
1049         pcxe_driver.start = pcxe_start;
1050         pcxe_driver.hangup = pcxe_hangup;
1051 
1052         pcxe_callout = pcxe_driver;
1053         pcxe_callout.name = "ttyD";
1054         pcxe_callout.major = DIGICU_MAJOR;
1055         pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
1056         pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1057 
1058 #if 0 
1059 
1060 /* strangely enough, this is FALSE */
1061 
1062         /* 
1063          * loops_per_sec hasn't been set at this point :-(, so fake it out... 
1064          * I set it so that I can use the __delay() function.
1065          */
1066         save_loops_per_sec = loops_per_sec;
1067         loops_per_sec = 13L*500000L;
1068 #endif
1069 
1070         save_flags(flags);
1071         cli();
1072 
1073         for(crd=0; crd < numcards; crd++) {
1074                 bd = &boards[crd];
1075                 outb(FEPRST, bd->port);
1076                 pcxxdelay(1);
1077 
1078                 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
1079                         if(i > 1000) {
1080                                 printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
1081                                         bd->port);
1082                                 bd->status = DISABLED;
1083                                 break;
1084                         }
1085                         pcxxdelay(1);
1086                 }
1087                 if(bd->status == DISABLED)
1088                         continue;
1089 
1090                 v = inb(bd->port);
1091 
1092                 if((v & 0x1) == 0x1) {
1093                         if((v & 0x30) == 0) {        /* PC/Xi 64K card */
1094                                 memory_seg = 0xf000;
1095                                 memory_size = 0x10000;
1096                         } 
1097 
1098                         if((v & 0x30) == 0x10) {     /* PC/Xi 128K card */
1099                                 memory_seg = 0xe000;
1100                                 memory_size = 0x20000;
1101                         }
1102                         
1103                         if((v & 0x30) == 0x20) {     /* PC/Xi 256K card */
1104                                 memory_seg = 0xc000;
1105                                 memory_size = 0x40000;
1106                         }
1107 
1108                         if((v & 0x30) == 0x30) {     /* PC/Xi 512K card */
1109                                 memory_seg = 0x8000;
1110                                 memory_size = 0x80000;
1111                         }
1112                         bd->type = PCXI;
1113                 } else {
1114                         if((v & 0x1) == 0x1) {
1115                                 bd->status = DISABLED;   /* PC/Xm unsupported card */
1116                                 printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
1117                                 continue;
1118                         } else {
1119                                 if(v & 0xC0) {    
1120                                         topwin = 0x1f00L;
1121                                         outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
1122                                         outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
1123                                         bd->type = PCXEVE; /* PC/Xe 8K card */
1124                                 } else { 
1125                                         bd->type = PCXE;    /* PC/Xe 64K card */
1126                                 }
1127                                         
1128                                 memory_seg = 0xf000;
1129                                 memory_size = 0x10000;
1130                         }
1131                 }
1132 
1133                 memaddr = (unchar *) bd->membase;
1134 
1135                 outb(FEPRST|FEPMEM, bd->port);
1136 
1137                 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
1138                         if(i > 10000) {
1139                                 printk("PC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
1140                                         board_desc[bd->type], bd->port);
1141                                 bd->status = DISABLED;
1142                                 break;
1143                         }
1144                         pcxxdelay(1);
1145                 }
1146                 if(bd->status == DISABLED)
1147                         continue;
1148 
1149                 memwinon(bd,0);
1150                 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
1151                 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
1152 
1153                 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
1154                                         *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
1155                         printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
1156                                 bd->membase, board_desc[bd->type], bd->port);
1157                         bd->status = DISABLED;
1158                         continue;
1159                 }
1160 
1161                 for(i=0; i < 16; i++) {
1162                         memaddr[MISCGLOBAL+i] = 0;
1163                 }
1164 
1165                 if(bd->type == PCXI || bd->type == PCXE) {
1166                         bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
1167 
1168                         memcpy(bios, pcxx_bios, pcxx_nbios);
1169 
1170                         outb(FEPMEM, bd->port);
1171 
1172                         for(i=0; i <= 10000; i++) {
1173                                 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1174                                         goto load_fep;
1175                                 }
1176                                 pcxxdelay(1);
1177                         }
1178 
1179                         printk("PC/Xx: BIOS download failed on the %s at 0x%x!\n",
1180                                                         board_desc[bd->type], bd->port);
1181                         bd->status = DISABLED;
1182                         continue;
1183                 }
1184 
1185                 if(bd->type == PCXEVE) {
1186                         bios = memaddr + (BIOSCODE & 0x1fff);
1187                         memwinon(bd,0xff);
1188                         
1189                         memcpy(bios, pcxx_bios, pcxx_nbios);
1190 
1191                         outb(FEPCLR, bd->port);
1192                         memwinon(bd,0);
1193 
1194                         for(i=0; i <= 10000; i++) {
1195                                 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1196                                         goto load_fep;
1197                                 }
1198                                 pcxxdelay(1);
1199                         }
1200 
1201                         printk("PC/Xx: BIOS download failed on the %s at 0x%x!\n",
1202                                 board_desc[bd->type], bd->port);
1203                         bd->status = DISABLED;
1204                         continue;
1205                 }
1206 
1207 load_fep:
1208                 fepos = memaddr + FEPCODE;
1209                 if(bd->type == PCXEVE)
1210                         fepos = memaddr + (FEPCODE & 0x1fff);
1211 
1212                 memwinon(bd, (FEPCODE >> 13));
1213                 memcpy(fepos, pcxx_cook, pcxx_ncook);
1214                 memwinon(bd, 0);
1215 
1216                 *(ushort *)((ulong)memaddr + MBOX +  0) = 2;
1217                 *(ushort *)((ulong)memaddr + MBOX +  2) = memory_seg + FEPCODESEG;
1218                 *(ushort *)((ulong)memaddr + MBOX +  4) = 0;
1219                 *(ushort *)((ulong)memaddr + MBOX +  6) = FEPCODESEG;
1220                 *(ushort *)((ulong)memaddr + MBOX +  8) = 0;
1221                 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
1222 
1223                 outb(FEPMEM|FEPINT, bd->port);
1224                 outb(FEPMEM, bd->port);
1225 
1226                 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
1227                         if(i > 2000) {
1228                                 printk("PC/Xx: Command failed for the %s at 0x%x!\n",
1229                                         board_desc[bd->type], bd->port);
1230                                 bd->status = DISABLED;
1231                                 break;
1232                         }
1233                         pcxxdelay(1);
1234                 }
1235 
1236                 if(bd->status == DISABLED)
1237                         continue;
1238 
1239                 *(ushort *)(memaddr + FEPSTAT) = 0;
1240                 *(ushort *)(memaddr + MBOX + 0) = 1;
1241                 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
1242                 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
1243 
1244                 outb(FEPINT, bd->port);
1245                 outb(FEPCLR, bd->port);
1246                 memwinon(bd, 0);
1247 
1248                 for(i=0; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
1249                         if(i > 10000) {
1250                                 printk("PC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
1251                                         board_desc[bd->type], bd->port);
1252                                 bd->status = DISABLED;
1253                                 break;
1254                         }
1255                         pcxxdelay(1);
1256                 }
1257                 if(bd->status == DISABLED)
1258                         continue;
1259 
1260                 ch = digi_channels+bd->first_minor;
1261                 pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
1262 
1263                 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1264                 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1265 
1266                 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1267                         shrinkmem = 1;
1268 
1269                 request_region(bd->port, 4, "PC/Xx");
1270 
1271                 for(i=0; i < bd->numports; i++, ch++, bc++) {
1272                         if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1273                                 ch->brdchan = 0;
1274                                 continue;
1275                         }
1276                         ch->brdchan = bc;
1277                         ch->mailbox = gd;
1278                         ch->tqueue.routine = do_softint;
1279                         ch->tqueue.data = ch;
1280                         ch->board = &boards[crd];
1281 #ifdef DEFAULT_HW_FLOW
1282                         ch->digiext.digi_flags = RTSPACE|CTSPACE;
1283 #endif
1284                         if(boards[crd].altpin) {
1285                                 ch->dsr = CD;
1286                                 ch->dcd = DSR;
1287                                 ch->digiext.digi_flags |= DIGI_ALTPIN;
1288                         } else { 
1289                                 ch->dcd = CD;
1290                                 ch->dsr = DSR;
1291                         }
1292 
1293                         ch->magic = PCXX_MAGIC;
1294                         ch->boardnum = crd;
1295                         ch->channelnum = i;
1296 
1297                         ch->dev = bd->first_minor + i;
1298                         ch->tty = 0;
1299 
1300                         if(shrinkmem) {
1301                                 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1302                                 shrinkmem = 0;
1303                         }
1304                         
1305                         if(bd->type != PCXEVE) {
1306                                 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1307                                 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1308                                 ch->txwin = ch->rxwin = 0;
1309                         } else {
1310                                 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1311                                 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1312                                 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1313                                 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1314                         }
1315 
1316                         ch->txbufsize = bc->tmax + 1;
1317                         ch->rxbufsize = bc->rmax + 1;
1318 
1319                         ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1320 
1321                         lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1322                         fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1323                         fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1324                         fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1325 
1326                         bc->edelay = 100;
1327                         bc->idata = 1;
1328 
1329                         ch->startc = bc->startc;
1330                         ch->stopc = bc->stopc;
1331                         ch->startca = bc->startca;
1332                         ch->stopca = bc->stopca;
1333 
1334                         ch->fepcflag = 0;
1335                         ch->fepiflag = 0;
1336                         ch->fepoflag = 0;
1337                         ch->fepstartc = 0;
1338                         ch->fepstopc = 0;
1339                         ch->fepstartca = 0;
1340                         ch->fepstopca = 0;
1341 
1342                         ch->close_delay = 50;
1343                         ch->count = 0;
1344                         ch->blocked_open = 0;
1345                         ch->callout_termios = pcxe_callout.init_termios;
1346                         ch->normal_termios = pcxe_driver.init_termios;
1347                         ch->open_wait = 0;
1348                         ch->close_wait = 0;
1349                 }
1350 
1351                 printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
1352                         board_desc[bd->type], board_mem[bd->type], bd->port, 
1353                         bd->membase, bd->numports);
1354 
1355                 memwinoff(bd, 0);
1356         }
1357 
1358         if(tty_register_driver(&pcxe_driver))
1359                 panic("Couldn't register PC/Xe driver");
1360 
1361         if(tty_register_driver(&pcxe_callout))
1362                 panic("Couldn't register PC/Xe callout");
1363 
1364 #if 0
1365         loops_per_sec = save_loops_per_sec;  /* reset it to what it should be */
1366 #endif
1367 
1368         /*
1369          * Start up the poller to check for events on all enabled boards
1370          */
1371         timer_active |= 1 << DIGI_TIMER;
1372         restore_flags(flags);
1373 
1374         return 0;
1375 }
1376 
1377 
1378 static void pcxxpoll(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1379 {
1380         unsigned long flags;
1381         int crd;
1382         volatile unsigned int head, tail;
1383         struct channel *ch;
1384         struct board_info *bd;
1385 
1386         save_flags(flags);
1387         cli();
1388 
1389         for(crd=0; crd < numcards; crd++) {
1390                 bd = &boards[crd];
1391 
1392                 ch = digi_channels+bd->first_minor;
1393 
1394                 if(bd->status == DISABLED)
1395                         continue;
1396 
1397                 assertmemoff(ch);
1398 
1399                 globalwinon(ch);
1400                 head = ch->mailbox->ein;
1401                 tail = ch->mailbox->eout;
1402 
1403                 if(head != tail)
1404                         doevent(crd);
1405 
1406                 memoff(ch);
1407         }
1408 
1409         timer_table[DIGI_TIMER].fn = pcxxpoll;
1410         timer_table[DIGI_TIMER].expires = jiffies + HZ/25;
1411         timer_active |= 1 << DIGI_TIMER;
1412         restore_flags(flags);
1413 }
1414 
1415 static void doevent(int crd)
     /* [previous][next][first][last][top][bottom][index][help] */
1416 {
1417         volatile struct board_info *bd;
1418         static struct tty_struct *tty;
1419         volatile struct board_chan *bc;
1420         volatile unchar *eventbuf;
1421         volatile unsigned int head;
1422         volatile unsigned int tail;
1423         struct channel *ch;
1424         struct channel *chan0;
1425         int channel, event, mstat, lstat;
1426 
1427         bd = &boards[crd];
1428 
1429         chan0 = digi_channels+bd->first_minor;
1430         pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
1431 
1432 
1433         assertgwinon(chan0);
1434 
1435         while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1436                 assertgwinon(chan0);
1437                 eventbuf = (volatile unchar *)bd->membase + tail + ISTART;
1438                 channel = eventbuf[0];
1439                 event = eventbuf[1];
1440                 mstat = eventbuf[2];
1441                 lstat = eventbuf[3];
1442 
1443                 ch=chan0+channel;
1444 
1445                 if ((unsigned)channel >= bd->numports || !ch) { 
1446                         printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1447                         printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1448                                         crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1449                         if(channel >= bd->numports)
1450                                 ch = chan0;
1451                         bc = ch->brdchan;
1452                         goto next;
1453                 }
1454                 if ((bc = ch->brdchan) == NULL)
1455                         goto next;
1456 
1457                 if (event & DATA_IND) {
1458                         receive_data(ch);
1459                         assertgwinon(ch);
1460                 }
1461 
1462                 if (event & MODEMCHG_IND) {
1463                         ch->imodem = mstat;
1464                         if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) {
1465                                 if (ch->asyncflags & ASYNC_CHECK_CD) {
1466                                         if (mstat & ch->dcd) {
1467                                                 wake_up_interruptible(&ch->open_wait);
1468                                         } else {
1469                                                 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1470                                         }
1471                                 }
1472                         }
1473                 }
1474 
1475                 tty = ch->tty;
1476 
1477                 if (tty) {
1478 
1479                         if (event & BREAK_IND) {
1480                                 tty->flip.count++;
1481                                 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1482                                 *tty->flip.char_buf_ptr++ = 0;
1483 #if 0
1484                                 if (ch->asyncflags & ASYNC_SAK)
1485                                         do_SAK(tty);
1486 #endif
1487                                 tty_schedule_flip(tty); 
1488                         }
1489 
1490                         if (event & LOWTX_IND) {
1491                                 if (ch->statusflags & LOWWAIT) {
1492                                         ch->statusflags &= ~LOWWAIT;
1493                                         if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1494                                                 tty->ldisc.write_wakeup)
1495                                                 (tty->ldisc.write_wakeup)(tty);
1496                                         wake_up_interruptible(&tty->write_wait);
1497                                 }
1498                         }
1499 
1500                         if (event & EMPTYTX_IND) {
1501                                 ch->statusflags &= ~TXBUSY;
1502                                 if (ch->statusflags & EMPTYWAIT) {
1503                                         ch->statusflags &= ~EMPTYWAIT;
1504                                         if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1505                                                 tty->ldisc.write_wakeup)
1506                                                 (tty->ldisc.write_wakeup)(tty);
1507                                         wake_up_interruptible(&tty->write_wait);
1508                                 }
1509                         }
1510                 }
1511 
1512         next:
1513                 globalwinon(ch);
1514                 if(!bc) printk("bc == NULL in doevent!\n");
1515                 else bc->idata = 1;
1516 
1517                 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1518                 globalwinon(chan0);
1519         }
1520 
1521 }
1522 
1523 
1524 /*
1525  * pcxxdelay - delays a specified number of milliseconds
1526  */
1527 static void pcxxdelay(int msec)
     /* [previous][next][first][last][top][bottom][index][help] */
1528 {
1529         while(msec-- > 0)
1530                 __delay(loops_per_sec/1000);
1531 }
1532 
1533 
1534 static void 
1535 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
     /* [previous][next][first][last][top][bottom][index][help] */
1536                                                 int bytecmd)
1537 {
1538         unchar *memaddr;
1539         unsigned int head, tail;
1540         long count;
1541         int n;
1542 
1543         if(ch->board->status == DISABLED)
1544                 return;
1545 
1546         assertgwinon(ch);
1547 
1548         memaddr = (unchar *)ch->board->membase;
1549         head = ch->mailbox->cin;
1550 
1551         if(head >= (CMAX-CSTART) || (head & 03)) {
1552                 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1553                 return;
1554         }
1555 
1556         if(bytecmd) {
1557                 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1558 
1559                 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1560 
1561                 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1562                 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1563         } else {
1564                 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1565 
1566                 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1567                 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1568         }
1569 
1570         head = (head+4) & (CMAX-CSTART-4);
1571         ch->mailbox->cin = head;
1572 
1573         count = FEPTIMEOUT;
1574 
1575         while(1) {
1576                 count--;
1577                 if(count == 0) {
1578                         printk("Fep not responding in fepcmd()\n");
1579                         return;
1580                 }
1581 
1582                 head = ch->mailbox->cin;
1583                 tail = ch->mailbox->cout;
1584 
1585                 n = (head-tail) & (CMAX-CSTART-4);
1586 
1587                 if(n <= ncmds * (sizeof(short)*4))
1588                         break;
1589         }
1590 }
1591 
1592 
1593 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
     /* [previous][next][first][last][top][bottom][index][help] */
1594 {
1595         unsigned res = 0;
1596 #ifdef SPEED_HACK
1597         /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
1598         if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
1599         if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
1600 #endif
1601         if (cflag & CBAUDEX)
1602         {
1603                 ch->digiext.digi_flags |= DIGI_FAST;
1604                 res |= FEP_HUPCL;
1605                 /* This gets strange but if we dont do this we will get 78600
1606                  * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
1607                  * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
1608                  * do 115K
1609                  */
1610                 if (cflag & B115200) res|=1;
1611         }
1612         else ch->digiext.digi_flags &= ~DIGI_FAST;
1613         res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE);
1614         return res;
1615 }
1616 
1617 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
     /* [previous][next][first][last][top][bottom][index][help] */
1618 {
1619         unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1620         
1621         if(ch->digiext.digi_flags & DIGI_AIXON)
1622                 res |= IAIXON;
1623         return res;
1624 }
1625 
1626 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
     /* [previous][next][first][last][top][bottom][index][help] */
1627 {
1628         unsigned res = 0;
1629 
1630         if(cflag & CRTSCTS) {
1631                 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1632                 res |= (CTS | RTS);
1633         }
1634         if(ch->digiext.digi_flags & RTSPACE)
1635                 res |= RTS;
1636         if(ch->digiext.digi_flags & DTRPACE)
1637                 res |= DTR;
1638         if(ch->digiext.digi_flags & CTSPACE)
1639                 res |= CTS;
1640         if(ch->digiext.digi_flags & DSRPACE)
1641                 res |= ch->dsr;
1642         if(ch->digiext.digi_flags & DCDPACE)
1643                 res |= ch->dcd;
1644 
1645         if (res & RTS)
1646                 ch->digiext.digi_flags |= RTSPACE;
1647         if (res & CTS)
1648                 ch->digiext.digi_flags |= CTSPACE;
1649 
1650         return res;
1651 }
1652 
1653 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
1654 {
1655         volatile struct board_chan *bc;
1656         unsigned int head;
1657         unsigned mval, hflow, cflag, iflag;
1658         struct termios *ts;
1659 
1660         bc = ch->brdchan;
1661         assertgwinon(ch);
1662         ts = tty->termios;
1663 
1664         if((ts->c_cflag & CBAUD) == 0) {
1665                 head = bc->rin;
1666                 bc->rout = head;
1667                 head = bc->tin;
1668                 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1669                 mval = 0;
1670         } else {
1671 
1672                 cflag = termios2digi_c(ch, ts->c_cflag);
1673 
1674                 if(cflag != ch->fepcflag) {
1675                         ch->fepcflag = cflag;
1676                         fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1677                 }
1678 
1679                 if(cflag & CLOCAL)
1680                         ch->asyncflags &= ~ASYNC_CHECK_CD;
1681                 else {
1682                         ch->asyncflags |= ASYNC_CHECK_CD;
1683                 }
1684 
1685                 mval = DTR | RTS;
1686         }
1687 
1688         iflag = termios2digi_i(ch, ts->c_iflag);
1689 
1690         if(iflag != ch->fepiflag) {
1691                 ch->fepiflag = iflag;
1692                 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1693         }
1694 
1695         bc->mint = ch->dcd;
1696         if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1697                 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1698                         bc->mint = 0;
1699 
1700         ch->imodem = bc->mstat;
1701 
1702         hflow = termios2digi_h(ch, ts->c_cflag);
1703 
1704         if(hflow != ch->hflow) {
1705                 ch->hflow = hflow;
1706                 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1707         }
1708 
1709         /* mval ^= ch->modemfake & (mval ^ ch->modem); */
1710 
1711         if(ch->omodem != mval) {
1712                 ch->omodem = mval;
1713                 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1714         }
1715 
1716         if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1717                 ch->fepstartc = ch->startc;
1718                 ch->fepstopc = ch->stopc;
1719                 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1720         }
1721 
1722         if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1723                 ch->fepstartca = ch->startca;
1724                 ch->fepstopca = ch->stopca;
1725                 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1726         }
1727 }
1728 
1729 
1730 static void receive_data(struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
1731 {
1732         volatile struct board_chan *bc;
1733         struct tty_struct *tty;
1734         unsigned int tail, head, wrapmask;
1735         int n;
1736         int piece;
1737         struct termios *ts=0;
1738         unchar *rptr;
1739         int rc;
1740         int wrapgap;
1741 
1742     globalwinon(ch);
1743 
1744         if (ch->statusflags & RXSTOPPED)
1745                 return;
1746 
1747         tty = ch->tty;
1748         if(tty)
1749                 ts = tty->termios;
1750 
1751         bc = ch->brdchan;
1752 
1753         if(!bc) {
1754                 printk("bc is NULL in receive_data!\n");
1755                 return;
1756         }
1757 
1758         wrapmask = ch->rxbufsize - 1;
1759 
1760         head = bc->rin;
1761         head &= wrapmask;
1762         tail = bc->rout & wrapmask;
1763 
1764         n = (head-tail) & wrapmask;
1765 
1766         if(n == 0)
1767                 return;
1768 
1769         /*
1770          * If CREAD bit is off or device not open, set TX tail to head
1771          */
1772         if(!tty || !ts || !(ts->c_cflag & CREAD)) {
1773                 bc->rout = head;
1774                 return;
1775         }
1776 
1777         if(tty->flip.count == TTY_FLIPBUF_SIZE) {
1778                 /* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
1779                 return;
1780         }
1781 
1782         if(bc->orun) {
1783                 bc->orun = 0;
1784                 printk("overrun! DigiBoard device minor=%d\n",MINOR(tty->device));
1785         }
1786 
1787         rxwinon(ch);
1788         rptr = tty->flip.char_buf_ptr;
1789         rc = tty->flip.count;
1790         while(n > 0) {
1791                 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
1792                 piece = (wrapgap < n) ? wrapgap : n;
1793 
1794                 /*
1795                  * Make sure we don't overflow the buffer
1796                  */
1797 
1798                 if ((rc + piece) > TTY_FLIPBUF_SIZE)
1799                         piece = TTY_FLIPBUF_SIZE - rc;
1800 
1801                 if (piece == 0)
1802                         break;
1803 
1804                 memcpy(rptr, ch->rxptr + tail, piece);
1805                 rptr += piece;
1806                 rc += piece;
1807                 tail = (tail + piece) & wrapmask;
1808                 n -= piece;
1809         }
1810         tty->flip.count = rc;
1811         tty->flip.char_buf_ptr = rptr;
1812     globalwinon(ch);
1813         bc->rout = tail;
1814 
1815         /* Must be called with global data */
1816         tty_schedule_flip(ch->tty); 
1817         return;
1818 }
1819 
1820 
1821 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
1822                     unsigned int cmd, unsigned long arg)
1823 {
1824         int error;
1825         struct channel *ch = (struct channel *) tty->driver_data;
1826         volatile struct board_chan *bc;
1827         int retval;
1828         unsigned int mflag, mstat;
1829         unsigned char startc, stopc;
1830         unsigned long flags;
1831         digiflow_t dflow;
1832 
1833         if(ch)
1834                 bc = ch->brdchan;
1835         else {
1836                 printk("ch is NULL in pcxe_ioctl!\n");
1837                 return(-EINVAL);
1838         }
1839 
1840         save_flags(flags);
1841 
1842         switch(cmd) {
1843                 case TCSBRK:    /* SVID version: non-zero arg --> no break */
1844                         retval = tty_check_change(tty);
1845                         if(retval)
1846                                 return retval;
1847                         setup_empty_event(tty,ch);              
1848                         tty_wait_until_sent(tty, 0);
1849                         if(!arg)
1850                                 digi_send_break(ch, HZ/4);    /* 1/4 second */
1851                         return 0;
1852 
1853                 case TCSBRKP:   /* support for POSIX tcsendbreak() */
1854                         retval = tty_check_change(tty);
1855                         if(retval)
1856                                 return retval;
1857                         setup_empty_event(tty,ch);              
1858                         tty_wait_until_sent(tty, 0);
1859                         digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
1860                         return 0;
1861 
1862                 case TIOCGSOFTCAR:
1863                         error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
1864                         if(error)
1865                                 return error;
1866                         put_fs_long(C_CLOCAL(tty) ? 1 : 0,
1867                                     (unsigned long *) arg);
1868                         return 0;
1869 
1870                 case TIOCSSOFTCAR:
1871                         arg = get_fs_long((unsigned long *) arg);
1872                         tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
1873                         return 0;
1874 
1875                 case TIOCMODG:
1876                 case TIOCMGET:
1877                         mflag = 0;
1878 
1879                         cli();
1880                         globalwinon(ch);
1881                         mstat = bc->mstat;
1882                         memoff(ch);
1883                         restore_flags(flags);
1884 
1885                         if(mstat & DTR)
1886                                 mflag |= TIOCM_DTR;
1887                         if(mstat & RTS)
1888                                 mflag |= TIOCM_RTS;
1889                         if(mstat & CTS)
1890                                 mflag |= TIOCM_CTS;
1891                         if(mstat & ch->dsr)
1892                                 mflag |= TIOCM_DSR;
1893                         if(mstat & RI)
1894                                 mflag |= TIOCM_RI;
1895                         if(mstat & ch->dcd)
1896                                 mflag |= TIOCM_CD;
1897 
1898                         error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
1899                         if(error)
1900                                 return error;
1901                         put_fs_long(mflag, (unsigned long *) arg);
1902                         break;
1903 
1904                 case TIOCMBIS:
1905                 case TIOCMBIC:
1906                 case TIOCMODS:
1907                 case TIOCMSET:
1908                         mstat = get_fs_long((unsigned long *) arg);
1909 
1910                         mflag = 0;
1911                         if(mstat & TIOCM_DTR)
1912                                 mflag |= DTR;
1913                         if(mstat & TIOCM_RTS)
1914                                 mflag |= RTS;
1915 
1916                         switch(cmd) {
1917                                 case TIOCMODS:
1918                                 case TIOCMSET:
1919                                         ch->modemfake = DTR|RTS;
1920                                         ch->modem = mflag;
1921                                         break;
1922 
1923                                 case TIOCMBIS:
1924                                         ch->modemfake |= mflag;
1925                                         ch->modem |= mflag;
1926                                         break;
1927 
1928                                 case TIOCMBIC:
1929                                         ch->modemfake &= ~mflag;
1930                                         ch->modem &= ~mflag;
1931                                         break;
1932                         }
1933 
1934                         cli();
1935                         globalwinon(ch);
1936                         pcxxparam(tty,ch);
1937                         memoff(ch);
1938                         restore_flags(flags);
1939                         break;
1940 
1941                 case TIOCSDTR:
1942                         cli();
1943                         ch->omodem |= DTR;
1944                         globalwinon(ch);
1945                         fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
1946                         memoff(ch);
1947                         restore_flags(flags);
1948                         break;
1949 
1950                 case TIOCCDTR:
1951                         ch->omodem &= ~DTR;
1952                         cli();
1953                         globalwinon(ch);
1954                         fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
1955                         memoff(ch);
1956                         restore_flags(flags);
1957                         break;
1958 
1959                 case DIGI_GETA:
1960                         if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
1961                                 return(error);
1962 
1963                         memcpy_tofs((char*)arg, &ch->digiext, sizeof(digi_t));
1964                         break;
1965 
1966                 case DIGI_SETAW:
1967                 case DIGI_SETAF:
1968                         if(cmd == DIGI_SETAW) {
1969                                 setup_empty_event(tty,ch);              
1970                                 tty_wait_until_sent(tty, 0);
1971                         }
1972                         else {
1973                                 if(tty->ldisc.flush_buffer)
1974                                         tty->ldisc.flush_buffer(tty);
1975                         }
1976 
1977                         /* Fall Thru */
1978 
1979                 case DIGI_SETA:
1980                         if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
1981                                 return(error);
1982 
1983                         memcpy_fromfs(&ch->digiext, (char*)arg, sizeof(digi_t));
1984 #ifdef DEBUG_IOCTL
1985                         printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
1986 #endif
1987                         
1988                         if(ch->digiext.digi_flags & DIGI_ALTPIN) {
1989                                 ch->dcd = DSR;
1990                                 ch->dsr = CD;
1991                         } else {
1992                                 ch->dcd = CD;
1993                                 ch->dsr = DSR;
1994                         }
1995                 
1996                         cli();
1997                         globalwinon(ch);
1998                         pcxxparam(tty,ch);
1999                         memoff(ch);
2000                         restore_flags(flags);
2001                         break;
2002 
2003                 case DIGI_GETFLOW:
2004                 case DIGI_GETAFLOW:
2005                         cli();  
2006                         globalwinon(ch);
2007                         if(cmd == DIGI_GETFLOW) {
2008                                 dflow.startc = bc->startc;
2009                                 dflow.stopc = bc->stopc;
2010                         } else {
2011                                 dflow.startc = bc->startca;
2012                                 dflow.stopc = bc->stopca;
2013                         }
2014                         memoff(ch);
2015                         restore_flags(flags);
2016 
2017                         if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
2018                                 return(error);
2019 
2020                         memcpy_tofs((char*)arg, &dflow, sizeof(dflow));
2021                         break;
2022 
2023                 case DIGI_SETAFLOW:
2024                 case DIGI_SETFLOW:
2025                         if(cmd == DIGI_SETFLOW) {
2026                                 startc = ch->startc;
2027                                 stopc = ch->stopc;
2028                         } else {
2029                                 startc = ch->startca;
2030                                 stopc = ch->stopca;
2031                         }
2032 
2033                         if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
2034                                 return(error);
2035 
2036                         memcpy_fromfs(&dflow, (char*)arg, sizeof(dflow));
2037 
2038                         if(dflow.startc != startc || dflow.stopc != stopc) {
2039                                 cli();
2040                                 globalwinon(ch);
2041 
2042                                 if(cmd == DIGI_SETFLOW) {
2043                                         ch->fepstartc = ch->startc = dflow.startc;
2044                                         ch->fepstopc = ch->stopc = dflow.stopc;
2045                                         fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
2046                                 } else {
2047                                         ch->fepstartca = ch->startca = dflow.startc;
2048                                         ch->fepstopca  = ch->stopca = dflow.stopc;
2049                                         fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
2050                                 }
2051 
2052                                 if(ch->statusflags & TXSTOPPED)
2053                                         pcxe_start(tty);
2054 
2055                                 memoff(ch);
2056                                 restore_flags(flags);
2057                         }
2058                         break;
2059 
2060                 default:
2061                         return -ENOIOCTLCMD;
2062         }
2063 
2064         return 0;
2065 }
2066 
2067 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
     /* [previous][next][first][last][top][bottom][index][help] */
2068 {
2069         struct channel *info;
2070 
2071         if ((info=chan(tty))!=NULL) {
2072                 unsigned long flags;
2073                 save_flags(flags);
2074                 cli();
2075                 globalwinon(info);
2076                 pcxxparam(tty,info);
2077                 memoff(info);
2078 
2079                 if ((old_termios->c_cflag & CRTSCTS) &&
2080                         ((tty->termios->c_cflag & CRTSCTS) == 0))
2081                         tty->hw_stopped = 0;
2082                 if(!(old_termios->c_cflag & CLOCAL) &&
2083                         (tty->termios->c_cflag & CLOCAL))
2084                         wake_up_interruptible(&info->open_wait);
2085                 restore_flags(flags);
2086         }
2087 }
2088 
2089 
2090 static void do_pcxe_bh(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2091 {
2092         run_task_queue(&tq_pcxx);
2093 }
2094 
2095 
2096 static void do_softint(void *private_)
     /* [previous][next][first][last][top][bottom][index][help] */
2097 {
2098         struct channel *info = (struct channel *) private_;
2099         
2100         if(info && info->magic == PCXX_MAGIC) {
2101                 struct tty_struct *tty = info->tty;
2102                 if (tty && tty->driver_data) {
2103                         if(clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
2104                                 tty_hangup(tty);
2105                                 wake_up_interruptible(&info->open_wait);
2106                                 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
2107                         }
2108                 }
2109         }
2110 }
2111 
2112 
2113 static void pcxe_stop(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
2114 {
2115         struct channel *info;
2116 
2117         if ((info=chan(tty))!=NULL) {
2118                 unsigned long flags;
2119                 save_flags(flags); 
2120                 cli();
2121                 if ((info->statusflags & TXSTOPPED) == 0) {
2122                         globalwinon(info);
2123                         fepcmd(info, PAUSETX, 0, 0, 0, 0);
2124                         info->statusflags |= TXSTOPPED;
2125                         memoff(info);
2126                 }
2127                 restore_flags(flags);
2128         }
2129 }
2130 
2131 static void pcxe_throttle(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
2132 {
2133         struct channel *info;
2134 
2135         if ((info=chan(tty))!=NULL) {
2136                 unsigned long flags;
2137                 save_flags(flags);
2138                 cli();
2139                 if ((info->statusflags & RXSTOPPED) == 0) {
2140                         globalwinon(info);
2141                         fepcmd(info, PAUSERX, 0, 0, 0, 0);
2142                         info->statusflags |= RXSTOPPED;
2143                         memoff(info);
2144                 }
2145                 restore_flags(flags);
2146         }
2147 }
2148 
2149 static void pcxe_unthrottle(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
2150 {
2151         struct channel *info;
2152 
2153         if ((info=chan(tty)) != NULL) {
2154                 unsigned long flags;
2155 
2156                 /* Just in case output was resumed because of a change in Digi-flow */
2157                 save_flags(flags);
2158                 cli();
2159                 if(info->statusflags & RXSTOPPED) {
2160                         volatile struct board_chan *bc;
2161                         globalwinon(info);
2162                         bc = info->brdchan;
2163                         fepcmd(info, RESUMERX, 0, 0, 0, 0);
2164                         info->statusflags &= ~RXSTOPPED;
2165                         memoff(info);
2166                 }
2167                 restore_flags(flags);
2168         }
2169 }
2170 
2171 
2172 static void pcxe_start(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
2173 {
2174         struct channel *info;
2175 
2176         if ((info=chan(tty))!=NULL) {
2177                 unsigned long flags;
2178 
2179                 save_flags(flags);
2180                 cli();
2181                 /* Just in case output was resumed because of a change in Digi-flow */
2182                 if(info->statusflags & TXSTOPPED) {
2183                         volatile struct board_chan *bc;
2184                         globalwinon(info);
2185                         bc = info->brdchan;
2186                         if(info->statusflags & LOWWAIT)
2187                                 bc->ilow = 1;
2188                         fepcmd(info, RESUMETX, 0, 0, 0, 0);
2189                         info->statusflags &= ~TXSTOPPED;
2190                         memoff(info);
2191                 }
2192                 restore_flags(flags);
2193         }
2194 }
2195 
2196 
2197 void digi_send_break(struct channel *ch, int msec)
     /* [previous][next][first][last][top][bottom][index][help] */
2198 {
2199         unsigned long flags;
2200 
2201         save_flags(flags);
2202         cli();
2203         globalwinon(ch);
2204 
2205         /* 
2206          * Maybe I should send an infinite break here, schedule() for
2207          * msec amount of time, and then stop the break.  This way,
2208          * the user can't screw up the FEP by causing digi_send_break()
2209          * to be called (i.e. via an ioctl()) more than once in msec amount 
2210          * of time.  Try this for now...
2211          */
2212 
2213         fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2214         memoff(ch);
2215 
2216         restore_flags(flags);
2217 }
2218 
2219 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
     /* [previous][next][first][last][top][bottom][index][help] */
2220 {
2221         volatile struct board_chan *bc;
2222         unsigned long flags;
2223 
2224         save_flags(flags);
2225         cli();
2226         globalwinon(ch);
2227         ch->statusflags |= EMPTYWAIT;
2228         bc = ch->brdchan;
2229         bc->iempty = 1;
2230         memoff(ch);
2231         restore_flags(flags);
2232 }

/* [previous][next][first][last][top][bottom][index][help] */