* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / char / pcxx.c
blob36db3299d5a306a90ae7d02b7820cb389bc2b873
1 /*
2 * linux/drivers/char/pcxe.c
3 *
4 * Written by Troy De Jongh, November, 1994
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.
10 * This driver is for the DigiBoard PC/Xe and PC/Xi line of products.
12 * This driver does NOT support DigiBoard's fastcook FEP option and
13 * does not support the transparent print (i.e. digiprint) option.
15 * This Driver is currently maintained by Christoph Lameter (clameter@fuller.edu)
16 * Please contact the mailing list for problems first.
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)
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 * 1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing.
34 * David Nugent: Bug in pcxe_open.
35 * Brian J. Murrell: Modem Control fixes, Majors correctly assigned
36 * 1.6.1 April 6, 1997 Bernhard Kaindl: fixed virtual memory access for 2.1
37 * i386-kernels and use on other archtitectures, Allowing use
38 * as module, added module parameters, added switch to enable
39 * verbose messages to assist user during card configuration.
40 * Currently only tested on a PC/Xi card, but should work on Xe
41 * and Xeve also.
45 #undef SPEED_HACK
46 /* If you define SPEED_HACK then you get the following Baudrate translation
47 19200 = 57600
48 38400 = 115K
49 The driver supports the native 57.6K and 115K Baudrates under Linux, but
50 some distributions like Slackware 3.0 don't like these high baudrates.
53 #include <linux/module.h>
54 #include <linux/mm.h>
55 #include <linux/ioport.h>
56 #include <linux/errno.h>
57 #include <linux/signal.h>
58 #include <linux/sched.h>
59 #include <linux/timer.h>
60 #include <linux/interrupt.h>
61 #include <linux/tty.h>
62 #include <linux/tty_flip.h>
63 #include <linux/major.h>
64 #include <linux/string.h>
65 #include <linux/fcntl.h>
66 #include <linux/ptrace.h>
67 #include <linux/delay.h>
68 #include <linux/serial.h>
69 #include <linux/tty_driver.h>
70 #include <linux/malloc.h>
71 #include <linux/init.h>
72 #include <linux/version.h>
74 #ifndef MODULE
75 #include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
76 #endif
78 #include <asm/system.h>
79 #include <asm/io.h>
80 #include <asm/uaccess.h>
81 #include <asm/bitops.h>
82 #include <asm/semaphore.h>
84 #define VERSION "1.6.1"
86 #include "digi.h"
87 #include "fep.h"
88 #include "pcxx.h"
89 #include "digi_fep.h"
90 #include "digi_bios.h"
93 * Define one default setting if no digi= config line is used.
94 * Default is altpin = disabled, 16 ports, I/O 200h, Memory 0D0000h
96 static struct board_info boards[MAX_DIGI_BOARDS] = { {
97 /* Board is enabled */ ENABLED,
98 /* Type is auto-detected */ 0,
99 /* altping is disabled */ DISABLED,
100 /* number of ports = 16 */ 16,
101 /* io address is 0x200 */ 0x200,
102 /* card memory at 0xd0000 */ 0xd0000,
103 /* first minor device no. */ 0
104 } };
106 static int verbose = 0;
107 static int debug = 0;
109 #ifdef MODULE
110 /* Variables for insmod */
111 static int io[] = {0, 0, 0, 0};
112 static int membase[] = {0, 0, 0, 0};
113 static int memsize[] = {0, 0, 0, 0};
114 static int altpin[] = {0, 0, 0, 0};
115 static int numports[] = {0, 0, 0, 0};
117 # if (LINUX_VERSION_CODE > 0x020111)
118 MODULE_AUTHOR("Bernhard Kaindl");
119 MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
120 MODULE_PARM(verbose, "i");
121 MODULE_PARM(debug, "i");
122 MODULE_PARM(io, "1-4i");
123 MODULE_PARM(membase, "1-4i");
124 MODULE_PARM(memsize, "1-4i");
125 MODULE_PARM(altpin, "1-4i");
126 MODULE_PARM(numports, "1-4i");
127 # endif
129 #endif MODULE
131 static int numcards = 1;
132 static int nbdevs = 0;
134 static struct channel *digi_channels;
135 static struct tty_struct **pcxe_table;
136 static struct termios **pcxe_termios;
137 static struct termios **pcxe_termios_locked;
139 int pcxx_ncook=sizeof(pcxx_cook);
140 int pcxx_nbios=sizeof(pcxx_bios);
142 #define MIN(a,b) ((a) < (b) ? (a) : (b))
143 #define pcxxassert(x, msg) if(!(x)) pcxx_error(__LINE__, msg)
145 #define FEPTIMEOUT 200000
146 #define SERIAL_TYPE_NORMAL 1
147 #define SERIAL_TYPE_CALLOUT 2
148 #define PCXE_EVENT_HANGUP 1
150 struct tty_driver pcxe_driver;
151 struct tty_driver pcxe_callout;
152 static int pcxe_refcount;
154 DECLARE_TASK_QUEUE(tq_pcxx);
156 static void pcxxpoll(void);
157 static void pcxxdelay(int);
158 static void fepcmd(struct channel *, int, int, int, int, int);
159 static void pcxe_put_char(struct tty_struct *, unsigned char);
160 static void pcxe_flush_chars(struct tty_struct *);
161 static void pcxx_error(int, char *);
162 static void pcxe_close(struct tty_struct *, struct file *);
163 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
164 static void pcxe_set_termios(struct tty_struct *, struct termios *);
165 static int pcxe_write(struct tty_struct *, int, const unsigned char *, int);
166 static int pcxe_write_room(struct tty_struct *);
167 static int pcxe_chars_in_buffer(struct tty_struct *);
168 static void pcxe_flush_buffer(struct tty_struct *);
169 static void doevent(int);
170 static void receive_data(struct channel *);
171 static void pcxxparam(struct tty_struct *, struct channel *ch);
172 static void do_softint(void *);
173 static inline void pcxe_sched_event(struct channel *, int);
174 static void do_pcxe_bh(void);
175 static void pcxe_start(struct tty_struct *);
176 static void pcxe_stop(struct tty_struct *);
177 static void pcxe_throttle(struct tty_struct *);
178 static void pcxe_unthrottle(struct tty_struct *);
179 static void digi_send_break(struct channel *ch, int msec);
180 static void shutdown(struct channel *);
181 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
182 static inline void memwinon(struct board_info *b, unsigned int win);
183 static inline void memwinoff(struct board_info *b, unsigned int win);
184 static inline void globalwinon(struct channel *ch);
185 static inline void rxwinon(struct channel *ch);
186 static inline void txwinon(struct channel *ch);
187 static inline void memoff(struct channel *ch);
188 static inline void assertgwinon(struct channel *ch);
189 static inline void assertmemoff(struct channel *ch);
191 #define TZ_BUFSZ 4096
193 /* function definitions */
194 #ifdef MODULE
197 * pcxe_init() is our init_module():
199 #define pcxe_init init_module
201 void cleanup_module(void);
204 /*****************************************************************************/
206 void cleanup_module()
209 unsigned long flags;
210 int crd, i;
211 int e1, e2;
212 struct board_info *bd;
213 struct channel *ch;
215 printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION);
217 save_flags(flags);
218 cli();
219 timer_active &= ~(1 << DIGI_TIMER);
220 timer_table[DIGI_TIMER].fn = NULL;
221 timer_table[DIGI_TIMER].expires = 0;
222 remove_bh(DIGI_BH);
224 if ((e1 = tty_unregister_driver(&pcxe_driver)))
225 printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
226 if ((e2 = tty_unregister_driver(&pcxe_callout)))
227 printk("SERIAL: failed to unregister callout driver (%d)\n",e2);
229 for(crd=0; crd < numcards; crd++) {
230 bd = &boards[crd];
231 ch = digi_channels+bd->first_minor;
232 for(i=0; i < bd->numports; i++, ch++) {
233 kfree(ch->tmp_buf);
235 release_region(bd->port, 4);
237 kfree(digi_channels);
238 kfree(pcxe_termios_locked);
239 kfree(pcxe_termios);
240 kfree(pcxe_table);
241 restore_flags(flags);
243 #endif
245 static inline struct channel *chan(register struct tty_struct *tty)
247 if (tty) {
248 register struct channel *ch=(struct channel *)tty->driver_data;
249 if (ch >= digi_channels && ch < digi_channels+nbdevs) {
250 if (ch->magic==PCXX_MAGIC)
251 return ch;
254 return NULL;
257 /* These inline routines are to turn board memory on and off */
258 static inline void memwinon(struct board_info *b, unsigned int win)
260 if(b->type == PCXEVE)
261 outb_p(FEPWIN|win, b->port+1);
262 else
263 outb_p(inb(b->port)|FEPMEM, b->port);
266 static inline void memwinoff(struct board_info *b, unsigned int win)
268 outb_p(inb(b->port)&~FEPMEM, b->port);
269 if(b->type == PCXEVE)
270 outb_p(0, b->port + 1);
273 static inline void globalwinon(struct channel *ch)
275 if(ch->board->type == PCXEVE)
276 outb_p(FEPWIN, ch->board->port+1);
277 else
278 outb_p(FEPMEM, ch->board->port);
281 static inline void rxwinon(struct channel *ch)
283 if(ch->rxwin == 0)
284 outb_p(FEPMEM, ch->board->port);
285 else
286 outb_p(ch->rxwin, ch->board->port+1);
289 static inline void txwinon(struct channel *ch)
291 if(ch->txwin == 0)
292 outb_p(FEPMEM, ch->board->port);
293 else
294 outb_p(ch->txwin, ch->board->port+1);
297 static inline void memoff(struct channel *ch)
299 outb_p(0, ch->board->port);
300 if(ch->board->type == PCXEVE)
301 outb_p(0, ch->board->port+1);
304 static inline void assertgwinon(struct channel *ch)
306 if(ch->board->type != PCXEVE)
307 pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
310 static inline void assertmemoff(struct channel *ch)
312 if(ch->board->type != PCXEVE)
313 pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
316 static inline void pcxe_sched_event(struct channel *info, int event)
318 info->event |= 1 << event;
319 queue_task(&info->tqueue, &tq_pcxx);
320 mark_bh(DIGI_BH);
323 static void pcxx_error(int line, char *msg)
325 printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
328 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
330 DECLARE_WAITQUEUE(wait, current);
331 int retval = 0;
332 int do_clocal = 0;
334 if (info->asyncflags & ASYNC_CALLOUT_ACTIVE) {
335 if (info->normal_termios.c_cflag & CLOCAL)
336 do_clocal = 1;
337 } else {
338 if (tty->termios->c_cflag & CLOCAL)
339 do_clocal = 1;
343 * Block waiting for the carrier detect and the line to become free
346 retval = 0;
347 add_wait_queue(&info->open_wait, &wait);
348 info->count--;
349 info->blocked_open++;
351 for (;;) {
352 cli();
353 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0) {
354 globalwinon(info);
355 info->omodem |= DTR|RTS;
356 fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
357 memoff(info);
359 sti();
360 set_current_state(TASK_INTERRUPTIBLE);
361 if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
362 if(info->asyncflags & ASYNC_HUP_NOTIFY)
363 retval = -EAGAIN;
364 else
365 retval = -ERESTARTSYS;
366 break;
368 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0 &&
369 (info->asyncflags & ASYNC_CLOSING) == 0 &&
370 (do_clocal || (info->imodem & info->dcd)))
371 break;
372 if(signal_pending(current)) {
373 retval = -ERESTARTSYS;
374 break;
376 schedule();
378 current->state = TASK_RUNNING;
379 remove_wait_queue(&info->open_wait, &wait);
381 if(!tty_hung_up_p(filp))
382 info->count++;
383 info->blocked_open--;
385 return retval;
389 int pcxe_open(struct tty_struct *tty, struct file * filp)
391 volatile struct board_chan *bc;
392 struct channel *ch;
393 unsigned long flags;
394 int line;
395 int boardnum;
396 int retval;
398 line = MINOR(tty->device) - tty->driver.minor_start;
400 if(line < 0 || line >= nbdevs) {
401 printk("line out of range in pcxe_open\n");
402 tty->driver_data = NULL;
403 return(-ENODEV);
406 for(boardnum=0;boardnum<numcards;boardnum++)
407 if ((line >= boards[boardnum].first_minor) &&
408 (line < boards[boardnum].first_minor + boards[boardnum].numports))
409 break;
411 if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
412 (line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
413 tty->driver_data = NULL; /* Mark this device as 'down' */
414 return(-ENODEV);
417 ch = digi_channels+line;
419 if(ch->brdchan == 0) {
420 tty->driver_data = NULL;
421 return(-ENODEV);
424 /* flag the kernel that there is somebody using this guy */
425 MOD_INC_USE_COUNT;
427 * If the device is in the middle of being closed, then block
428 * until it's done, and then try again.
430 if(ch->asyncflags & ASYNC_CLOSING) {
431 interruptible_sleep_on(&ch->close_wait);
432 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
433 return -EAGAIN;
434 else
435 return -ERESTARTSYS;
438 save_flags(flags);
439 cli();
440 ch->count++;
441 tty->driver_data = ch;
442 ch->tty = tty;
444 if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
445 unsigned int head;
447 globalwinon(ch);
448 ch->statusflags = 0;
449 bc=ch->brdchan;
450 ch->imodem = bc->mstat;
451 head = bc->rin;
452 bc->rout = head;
453 ch->tty = tty;
454 pcxxparam(tty,ch);
455 ch->imodem = bc->mstat;
456 bc->idata = 1;
457 ch->omodem = DTR|RTS;
458 fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
459 memoff(ch);
460 ch->asyncflags |= ASYNC_INITIALIZED;
462 restore_flags(flags);
464 if(ch->asyncflags & ASYNC_CLOSING) {
465 interruptible_sleep_on(&ch->close_wait);
466 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
467 return -EAGAIN;
468 else
469 return -ERESTARTSYS;
472 * If this is a callout device, then just make sure the normal
473 * device isn't being used.
475 if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
476 if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
477 return -EBUSY;
478 if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) {
479 if ((ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
480 (ch->session != current->session))
481 return -EBUSY;
482 if((ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
483 (ch->pgrp != current->pgrp))
484 return -EBUSY;
486 ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
488 else {
489 if (filp->f_flags & O_NONBLOCK) {
490 if(ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
491 return -EBUSY;
493 else {
494 /* this has to be set in order for the "block until
495 * CD" code to work correctly. i'm not sure under
496 * what circumstances asyncflags should be set to
497 * ASYNC_NORMAL_ACTIVE though
498 * brian@ilinx.com
500 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
501 if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
502 return retval;
504 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
507 save_flags(flags);
508 cli();
509 if((ch->count == 1) && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
510 if(tty->driver.subtype == SERIAL_TYPE_NORMAL)
511 *tty->termios = ch->normal_termios;
512 else
513 *tty->termios = ch->callout_termios;
514 globalwinon(ch);
515 pcxxparam(tty,ch);
516 memoff(ch);
519 ch->session = current->session;
520 ch->pgrp = current->pgrp;
521 restore_flags(flags);
522 return 0;
525 static void shutdown(struct channel *info)
527 unsigned long flags;
528 volatile struct board_chan *bc;
529 struct tty_struct *tty;
531 if (!(info->asyncflags & ASYNC_INITIALIZED))
532 return;
534 save_flags(flags);
535 cli();
536 globalwinon(info);
538 bc = info->brdchan;
539 if(bc)
540 bc->idata = 0;
542 tty = info->tty;
545 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
547 if(tty->termios->c_cflag & HUPCL) {
548 info->omodem &= ~(RTS|DTR);
549 fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
552 memoff(info);
553 info->asyncflags &= ~ASYNC_INITIALIZED;
554 restore_flags(flags);
558 static void pcxe_close(struct tty_struct * tty, struct file * filp)
560 struct channel *info;
562 if ((info=chan(tty))!=NULL) {
563 unsigned long flags;
564 save_flags(flags);
565 cli();
567 if(tty_hung_up_p(filp)) {
568 /* flag that somebody is done with this module */
569 MOD_DEC_USE_COUNT;
570 restore_flags(flags);
571 return;
573 /* this check is in serial.c, it won't hurt to do it here too */
574 if ((tty->count == 1) && (info->count != 1)) {
576 * Uh, oh. tty->count is 1, which means that the tty
577 * structure will be freed. Info->count should always
578 * be one in these conditions. If it's greater than
579 * one, we've got real problems, since it means the
580 * serial port won't be shutdown.
582 printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
583 info->count = 1;
585 if (info->count-- > 1) {
586 restore_flags(flags);
587 MOD_DEC_USE_COUNT;
588 return;
590 if (info->count < 0) {
591 info->count = 0;
594 info->asyncflags |= ASYNC_CLOSING;
597 * Save the termios structure, since this port may have
598 * separate termios for callout and dialin.
600 if(info->asyncflags & ASYNC_NORMAL_ACTIVE)
601 info->normal_termios = *tty->termios;
602 if(info->asyncflags & ASYNC_CALLOUT_ACTIVE)
603 info->callout_termios = *tty->termios;
604 tty->closing = 1;
605 if(info->asyncflags & ASYNC_INITIALIZED) {
606 setup_empty_event(tty,info);
607 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
610 if(tty->driver.flush_buffer)
611 tty->driver.flush_buffer(tty);
612 if(tty->ldisc.flush_buffer)
613 tty->ldisc.flush_buffer(tty);
614 shutdown(info);
615 tty->closing = 0;
616 info->event = 0;
617 info->tty = NULL;
618 #ifndef MODULE
619 /* ldiscs[] is not available in a MODULE
620 ** worth noting that while I'm not sure what this hunk of code is supposed
621 ** to do, it is not present in the serial.c driver. Hmmm. If you know,
622 ** please send me a note. brian@ilinx.com
623 ** Don't know either what this is supposed to do clameter@waterf.org.
625 if(tty->ldisc.num != ldiscs[N_TTY].num) {
626 if(tty->ldisc.close)
627 (tty->ldisc.close)(tty);
628 tty->ldisc = ldiscs[N_TTY];
629 tty->termios->c_line = N_TTY;
630 if(tty->ldisc.open)
631 (tty->ldisc.open)(tty);
633 #endif
634 if(info->blocked_open) {
635 if(info->close_delay) {
636 current->state = TASK_INTERRUPTIBLE;
637 schedule_timeout(info->close_delay);
639 wake_up_interruptible(&info->open_wait);
641 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
642 ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
643 wake_up_interruptible(&info->close_wait);
644 MOD_DEC_USE_COUNT;
645 restore_flags(flags);
650 void pcxe_hangup(struct tty_struct *tty)
652 struct channel *ch;
654 if ((ch=chan(tty))!=NULL) {
655 unsigned long flags;
657 save_flags(flags);
658 cli();
659 shutdown(ch);
660 ch->event = 0;
661 ch->count = 0;
662 ch->tty = NULL;
663 ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
664 wake_up_interruptible(&ch->open_wait);
665 restore_flags(flags);
671 static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
673 struct channel *ch;
674 volatile struct board_chan *bc;
675 int total, remain, size, stlen;
676 unsigned int head, tail;
677 unsigned long flags;
679 /* printk("Entering pcxe_write()\n"); */
681 if ((ch=chan(tty))==NULL)
682 return 0;
684 bc = ch->brdchan;
685 size = ch->txbufsize;
687 if (from_user) {
689 save_flags(flags);
690 cli();
691 globalwinon(ch);
692 head = bc->tin & (size - 1);
693 /* It seems to be necessary to make sure that the value is stable here somehow
694 This is a rather odd pice of code here. */
696 { tail = bc->tout;
697 } while (tail != bc->tout);
699 tail &= (size - 1);
700 stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
701 count = MIN(stlen, count);
702 if (count) {
703 if (verify_area(VERIFY_READ, (char*)buf, count))
704 count=0;
705 else copy_from_user(ch->tmp_buf, buf, count);
707 buf = ch->tmp_buf;
708 memoff(ch);
709 restore_flags(flags);
713 * All data is now local
716 total = 0;
717 save_flags(flags);
718 cli();
719 globalwinon(ch);
720 head = bc->tin & (size - 1);
721 tail = bc->tout;
722 if (tail != bc->tout)
723 tail = bc->tout;
724 tail &= (size - 1);
725 if (head >= tail) {
726 remain = size - (head - tail) - 1;
727 stlen = size - head;
729 else {
730 remain = tail - head - 1;
731 stlen = remain;
733 count = MIN(remain, count);
735 txwinon(ch);
736 while (count > 0) {
737 stlen = MIN(count, stlen);
738 memcpy(ch->txptr + head, buf, stlen);
739 buf += stlen;
740 count -= stlen;
741 total += stlen;
742 head += stlen;
743 if (head >= size) {
744 head = 0;
745 stlen = tail;
748 ch->statusflags |= TXBUSY;
749 globalwinon(ch);
750 bc->tin = head;
751 if ((ch->statusflags & LOWWAIT) == 0) {
752 ch->statusflags |= LOWWAIT;
753 bc->ilow = 1;
755 memoff(ch);
756 restore_flags(flags);
758 return(total);
762 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
764 pcxe_write(tty, 0, &c, 1);
765 return;
769 static int pcxe_write_room(struct tty_struct *tty)
771 struct channel *ch;
772 int remain;
774 remain = 0;
775 if ((ch=chan(tty))!=NULL) {
776 volatile struct board_chan *bc;
777 unsigned int head, tail;
778 unsigned long flags;
780 save_flags(flags);
781 cli();
782 globalwinon(ch);
784 bc = ch->brdchan;
785 head = bc->tin & (ch->txbufsize - 1);
786 tail = bc->tout;
787 if (tail != bc->tout)
788 tail = bc->tout;
789 tail &= (ch->txbufsize - 1);
791 if((remain = tail - head - 1) < 0 )
792 remain += ch->txbufsize;
794 if (remain && (ch->statusflags & LOWWAIT) == 0) {
795 ch->statusflags |= LOWWAIT;
796 bc->ilow = 1;
798 memoff(ch);
799 restore_flags(flags);
802 return remain;
806 static int pcxe_chars_in_buffer(struct tty_struct *tty)
808 int chars;
809 unsigned int ctail, head, tail;
810 int remain;
811 unsigned long flags;
812 struct channel *ch;
813 volatile struct board_chan *bc;
815 if ((ch=chan(tty))==NULL)
816 return(0);
818 save_flags(flags);
819 cli();
820 globalwinon(ch);
822 bc = ch->brdchan;
823 tail = bc->tout;
824 head = bc->tin;
825 ctail = ch->mailbox->cout;
826 if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
827 chars = 0;
828 else {
829 head = bc->tin & (ch->txbufsize - 1);
830 tail &= (ch->txbufsize - 1);
831 if((remain = tail - head - 1) < 0 )
832 remain += ch->txbufsize;
834 chars = (int)(ch->txbufsize - remain);
837 * Make it possible to wakeup anything waiting for output
838 * in tty_ioctl.c, etc.
840 if(!(ch->statusflags & EMPTYWAIT))
841 setup_empty_event(tty,ch);
844 memoff(ch);
845 restore_flags(flags);
847 return(chars);
851 static void pcxe_flush_buffer(struct tty_struct *tty)
853 unsigned int tail;
854 volatile struct board_chan *bc;
855 struct channel *ch;
856 unsigned long flags;
858 if ((ch=chan(tty))==NULL)
859 return;
861 save_flags(flags);
862 cli();
864 globalwinon(ch);
865 bc = ch->brdchan;
866 tail = bc->tout;
867 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
869 memoff(ch);
870 restore_flags(flags);
872 wake_up_interruptible(&tty->write_wait);
873 if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
874 (tty->ldisc.write_wakeup)(tty);
877 static void pcxe_flush_chars(struct tty_struct *tty)
879 struct channel * ch;
881 if ((ch=chan(tty))!=NULL) {
882 unsigned long flags;
884 save_flags(flags);
885 cli();
886 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
887 setup_empty_event(tty,ch);
888 restore_flags(flags);
892 #ifndef MODULE
895 * Driver setup function when linked into the kernel to optionally parse multible
896 * "digi="-lines and initialize the driver at boot time. No probing.
898 void __init pcxx_setup(char *str, int *ints)
901 struct board_info board;
902 int i, j, last;
903 char *temp, *t2;
904 unsigned len;
906 numcards=0;
908 memset(&board, 0, sizeof(board));
910 for(last=0,i=1;i<=ints[0];i++)
911 switch(i)
913 case 1:
914 board.status = ints[i];
915 last = i;
916 break;
918 case 2:
919 board.type = ints[i];
920 last = i;
921 break;
923 case 3:
924 board.altpin = ints[i];
925 last = i;
926 break;
928 case 4:
929 board.numports = ints[i];
930 last = i;
931 break;
933 case 5:
934 board.port = ints[i];
935 last = i;
936 break;
938 case 6:
939 board.membase = ints[i];
940 last = i;
941 break;
943 default:
944 printk("PC/Xx: Too many integer parms\n");
945 return;
948 while (str && *str)
950 /* find the next comma or terminator */
951 temp = str;
952 while (*temp && (*temp != ','))
953 temp++;
955 if (!*temp)
956 temp = NULL;
957 else
958 *temp++ = 0;
960 i = last + 1;
962 switch(i)
964 case 1:
965 len = strlen(str);
966 if (strncmp("Disable", str, len) == 0)
967 board.status = 0;
968 else
969 if (strncmp("Enable", str, len) == 0)
970 board.status = 1;
971 else
973 printk("PC/Xx: Invalid status %s\n", str);
974 return;
976 last = i;
977 break;
979 case 2:
980 for(j=0;j<PCXX_NUM_TYPES;j++)
981 if (strcmp(board_desc[j], str) == 0)
982 break;
984 if (i<PCXX_NUM_TYPES)
985 board.type = j;
986 else
988 printk("PC/Xx: Invalid board name: %s\n", str);
989 return;
991 last = i;
992 break;
994 case 3:
995 len = strlen(str);
996 if (strncmp("Disable", str, len) == 0)
997 board.altpin = 0;
998 else
999 if (strncmp("Enable", str, len) == 0)
1000 board.altpin = 1;
1001 else
1003 printk("PC/Xx: Invalid altpin %s\n", str);
1004 return;
1006 last = i;
1007 break;
1009 case 4:
1010 t2 = str;
1011 while (isdigit(*t2))
1012 t2++;
1014 if (*t2)
1016 printk("PC/Xx: Invalid port count %s\n", str);
1017 return;
1020 board.numports = simple_strtoul(str, NULL, 0);
1021 last = i;
1022 break;
1024 case 5:
1025 t2 = str;
1026 while (isxdigit(*t2))
1027 t2++;
1029 if (*t2)
1031 printk("PC/Xx: Invalid io port address %s\n", str);
1032 return;
1035 board.port = simple_strtoul(str, NULL, 16);
1036 last = i;
1037 break;
1039 case 6:
1040 t2 = str;
1041 while (isxdigit(*t2))
1042 t2++;
1044 if (*t2)
1046 printk("PC/Xx: Invalid memory base %s\n", str);
1047 return;
1050 board.membase = simple_strtoul(str, NULL, 16);
1051 last = i;
1052 break;
1054 default:
1055 printk("PC/Xx: Too many string parms\n");
1056 return;
1058 str = temp;
1061 if (last < 6)
1063 printk("PC/Xx: Insufficient parms specified\n");
1064 return;
1067 /* I should REALLY validate the stuff here */
1069 memcpy(&boards[numcards],&board, sizeof(board));
1070 printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n",
1071 numcards, board_desc[board.type], board_mem[board.type],
1072 board.numports, board.port, (unsigned int) board.membase);
1074 /* keep track of my initial minor number */
1075 if (numcards)
1076 boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
1077 else
1078 boards[numcards].first_minor = 0;
1080 /* yeha! string parameter was successful! */
1081 numcards++;
1083 #endif
1086 * function to initialize the driver with the given parameters, which are either
1087 * the default values from this file or the parameters given at boot.
1089 int __init pcxe_init(void)
1091 ulong memory_seg=0, memory_size=0;
1092 int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
1093 unchar *fepos, *memaddr, *bios, v;
1094 volatile struct global_data *gd;
1095 volatile struct board_chan *bc;
1096 struct board_info *bd;
1097 struct channel *ch;
1099 printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
1101 #ifdef MODULE
1102 for (i = 0; i < 4; i++) {
1103 if (io[i]) {
1104 numcards = 0;
1105 break;
1108 if (numcards == 0) {
1109 int first_minor = 0;
1111 for (i = 0; i < 4; i++) {
1112 if (io[i] == 0) {
1113 boards[i].port = 0;
1114 boards[i].status = DISABLED;
1116 else {
1117 boards[i].port = (ushort)io[i];
1118 boards[i].status = ENABLED;
1119 boards[i].first_minor = first_minor;
1120 numcards=i+1;
1122 if (membase[i])
1123 boards[i].membase = (ulong)membase[i];
1124 else
1125 boards[i].membase = 0xD0000;
1127 if (memsize[i])
1128 boards[i].memsize = (ulong)(memsize[i] * 1024);
1129 else
1130 boards[i].memsize = 0;
1132 if (altpin[i])
1133 boards[i].altpin = ON;
1134 else
1135 boards[i].altpin = OFF;
1137 if (numports[i])
1138 boards[i].numports = (ushort)numports[i];
1139 else
1140 boards[i].numports = 16;
1142 first_minor += boards[i].numports;
1145 #endif
1147 if (numcards <= 0)
1149 printk("PC/Xx: No cards configured, driver not active.\n");
1150 return -EIO;
1152 #if 1
1153 if (debug)
1154 for (i = 0; i < numcards; i++) {
1155 printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
1156 i+1,
1157 boards[i].status,
1158 boards[i].port,
1159 boards[i].membase,
1160 boards[i].memsize,
1161 boards[i].altpin,
1162 boards[i].numports,
1163 boards[i].first_minor);
1165 #endif
1167 for (i=0;i<numcards;i++)
1168 nbdevs += boards[i].numports;
1170 if (nbdevs <= 0)
1172 printk("PC/Xx: No devices activated, driver not active.\n");
1173 return -EIO;
1177 * this turns out to be more memory efficient, as there are no
1178 * unused spaces.
1180 digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
1181 if (!digi_channels)
1182 panic("Unable to allocate digi_channel struct");
1183 memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
1185 pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
1186 if (!pcxe_table)
1187 panic("Unable to allocate pcxe_table struct");
1188 memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs);
1190 pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
1191 if (!pcxe_termios)
1192 panic("Unable to allocate pcxe_termios struct");
1193 memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs);
1195 pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
1196 if (!pcxe_termios_locked)
1197 panic("Unable to allocate pcxe_termios_locked struct");
1198 memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs);
1200 init_bh(DIGI_BH,do_pcxe_bh);
1201 enable_bh(DIGI_BH);
1203 timer_table[DIGI_TIMER].fn = pcxxpoll;
1204 timer_table[DIGI_TIMER].expires = 0;
1206 memset(&pcxe_driver, 0, sizeof(struct tty_driver));
1207 pcxe_driver.magic = TTY_DRIVER_MAGIC;
1208 pcxe_driver.name = "ttyD";
1209 pcxe_driver.major = DIGI_MAJOR;
1210 pcxe_driver.minor_start = 0;
1212 pcxe_driver.num = nbdevs;
1214 pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
1215 pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
1216 pcxe_driver.init_termios = tty_std_termios;
1217 pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1218 pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
1219 pcxe_driver.refcount = &pcxe_refcount;
1221 pcxe_driver.table = pcxe_table;
1222 pcxe_driver.termios = pcxe_termios;
1223 pcxe_driver.termios_locked = pcxe_termios_locked;
1225 pcxe_driver.open = pcxe_open;
1226 pcxe_driver.close = pcxe_close;
1227 pcxe_driver.write = pcxe_write;
1228 pcxe_driver.put_char = pcxe_put_char;
1229 pcxe_driver.flush_chars = pcxe_flush_chars;
1230 pcxe_driver.write_room = pcxe_write_room;
1231 pcxe_driver.chars_in_buffer = pcxe_chars_in_buffer;
1232 pcxe_driver.flush_buffer = pcxe_flush_buffer;
1233 pcxe_driver.ioctl = pcxe_ioctl;
1234 pcxe_driver.throttle = pcxe_throttle;
1235 pcxe_driver.unthrottle = pcxe_unthrottle;
1236 pcxe_driver.set_termios = pcxe_set_termios;
1237 pcxe_driver.stop = pcxe_stop;
1238 pcxe_driver.start = pcxe_start;
1239 pcxe_driver.hangup = pcxe_hangup;
1241 pcxe_callout = pcxe_driver;
1242 pcxe_callout.name = "cud";
1243 pcxe_callout.major = DIGICU_MAJOR;
1244 pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
1245 pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1247 for(crd=0; crd < numcards; crd++) {
1248 bd = &boards[crd];
1249 outb(FEPRST, bd->port);
1250 pcxxdelay(1);
1252 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
1253 if(i > 100) {
1254 printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
1255 bd->port);
1256 bd->status = DISABLED;
1257 break;
1259 #ifdef MODULE
1260 schedule();
1261 #endif
1262 pcxxdelay(10);
1264 if(bd->status == DISABLED)
1265 continue;
1267 v = inb(bd->port);
1269 if((v & 0x1) == 0x1) {
1270 if((v & 0x30) == 0) { /* PC/Xi 64K card */
1271 memory_seg = 0xf000;
1272 memory_size = 0x10000;
1275 if((v & 0x30) == 0x10) { /* PC/Xi 128K card */
1276 memory_seg = 0xe000;
1277 memory_size = 0x20000;
1280 if((v & 0x30) == 0x20) { /* PC/Xi 256K card */
1281 memory_seg = 0xc000;
1282 memory_size = 0x40000;
1285 if((v & 0x30) == 0x30) { /* PC/Xi 512K card */
1286 memory_seg = 0x8000;
1287 memory_size = 0x80000;
1289 bd->type = PCXI;
1290 } else {
1291 if((v & 0x1) == 0x1) {
1292 bd->status = DISABLED; /* PC/Xm unsupported card */
1293 printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
1294 continue;
1295 } else {
1296 if(v & 0xC0) {
1297 topwin = 0x1f00L;
1298 outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
1299 outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
1300 bd->type = PCXEVE; /* PC/Xe 8K card */
1301 } else {
1302 bd->type = PCXE; /* PC/Xe 64K card */
1305 memory_seg = 0xf000;
1306 memory_size = 0x10000;
1309 if (verbose)
1310 printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
1311 crd+1, board_desc[bd->type], memory_size/1024,
1312 bd->port,bd->membase,bd->membase+memory_size-1);
1314 if (boards[crd].memsize == 0)
1315 boards[crd].memsize = memory_size;
1316 else
1317 if (boards[crd].memsize != memory_size) {
1318 printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
1319 boards[crd].memsize, boards[crd].memsize / 1024,
1320 memory_size, memory_size / 1024);
1321 continue;
1324 memaddr = (unchar *)phys_to_virt(bd->membase);
1326 if (verbose)
1327 printk("Resetting board and testing memory access:");
1329 outb(FEPRST|FEPMEM, bd->port);
1331 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
1332 if(i > 1000) {
1333 printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
1334 board_desc[bd->type], bd->port);
1335 bd->status = DISABLED;
1336 break;
1338 #ifdef MODULE
1339 schedule();
1340 #endif
1341 pcxxdelay(1);
1343 if(bd->status == DISABLED)
1344 continue;
1346 memwinon(bd,0);
1347 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
1348 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
1350 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
1351 *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
1352 printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
1353 bd->membase, board_desc[bd->type], bd->port);
1354 bd->status = DISABLED;
1355 continue;
1357 if (verbose)
1358 printk(" done.\n");
1360 for(i=0; i < 16; i++) {
1361 memaddr[MISCGLOBAL+i] = 0;
1364 if(bd->type == PCXI || bd->type == PCXE) {
1365 bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
1367 if (verbose)
1368 printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
1370 memcpy(bios, pcxx_bios, pcxx_nbios);
1372 if (verbose)
1373 printk(" done.\n");
1375 outb(FEPMEM, bd->port);
1377 if (verbose)
1378 printk("Waiting for BIOS to become ready");
1380 for(i=1; i <= 30; i++) {
1381 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1382 goto load_fep;
1384 if (verbose) {
1385 printk(".");
1386 if (i % 50 == 0)
1387 printk("\n");
1389 #ifdef MODULE
1390 schedule();
1391 #endif
1392 pcxxdelay(50);
1395 printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
1396 bd->port, bd->membase, bd->membase+bd->memsize);
1397 bd->status = DISABLED;
1398 continue;
1401 if(bd->type == PCXEVE) {
1402 bios = memaddr + (BIOSCODE & 0x1fff);
1403 memwinon(bd,0xff);
1405 memcpy(bios, pcxx_bios, pcxx_nbios);
1407 outb(FEPCLR, bd->port);
1408 memwinon(bd,0);
1410 for(i=0; i <= 1000; i++) {
1411 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1412 goto load_fep;
1414 if (verbose) {
1415 printk(".");
1416 if (i % 50 == 0)
1417 printk("\n");
1419 #ifdef MODULE
1420 schedule();
1421 #endif
1422 pcxxdelay(10);
1425 printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
1426 board_desc[bd->type], bd->port);
1427 bd->status = DISABLED;
1428 continue;
1431 load_fep:
1432 fepos = memaddr + FEPCODE;
1433 if(bd->type == PCXEVE)
1434 fepos = memaddr + (FEPCODE & 0x1fff);
1436 if (verbose)
1437 printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
1439 memwinon(bd, (FEPCODE >> 13));
1440 memcpy(fepos, pcxx_cook, pcxx_ncook);
1441 memwinon(bd, 0);
1443 if (verbose)
1444 printk(" done.\n");
1446 *(ushort *)((ulong)memaddr + MBOX + 0) = 2;
1447 *(ushort *)((ulong)memaddr + MBOX + 2) = memory_seg + FEPCODESEG;
1448 *(ushort *)((ulong)memaddr + MBOX + 4) = 0;
1449 *(ushort *)((ulong)memaddr + MBOX + 6) = FEPCODESEG;
1450 *(ushort *)((ulong)memaddr + MBOX + 8) = 0;
1451 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
1453 outb(FEPMEM|FEPINT, bd->port);
1454 outb(FEPMEM, bd->port);
1456 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
1457 if(i > 2000) {
1458 printk("PC/Xx: Command failed for the %s at 0x%x!\n",
1459 board_desc[bd->type], bd->port);
1460 bd->status = DISABLED;
1461 break;
1463 #ifdef MODULE
1464 schedule();
1465 #endif
1466 pcxxdelay(1);
1469 if(bd->status == DISABLED)
1470 continue;
1472 if (verbose)
1473 printk("Waiting for FEP/OS to become ready");
1475 *(ushort *)(memaddr + FEPSTAT) = 0;
1476 *(ushort *)(memaddr + MBOX + 0) = 1;
1477 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
1478 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
1480 outb(FEPINT, bd->port);
1481 outb(FEPCLR, bd->port);
1482 memwinon(bd, 0);
1484 for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
1485 if(i > 1000) {
1486 printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
1487 board_desc[bd->type], bd->port);
1488 bd->status = DISABLED;
1489 break;
1491 if (verbose) {
1492 printk(".");
1493 if (i % 50 == 0)
1494 printk("\n%5d",i/50);
1496 #ifdef MODULE
1497 schedule();
1498 #endif
1499 pcxxdelay(1);
1501 if(bd->status == DISABLED)
1502 continue;
1504 if (verbose)
1505 printk(" ok.\n");
1507 ch = digi_channels+bd->first_minor;
1508 pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
1510 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1511 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1513 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1514 shrinkmem = 1;
1516 request_region(bd->port, 4, "PC/Xx");
1518 for(i=0; i < bd->numports; i++, ch++, bc++) {
1519 if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1520 ch->brdchan = 0;
1521 continue;
1523 ch->brdchan = bc;
1524 ch->mailbox = gd;
1525 ch->tqueue.routine = do_softint;
1526 ch->tqueue.data = ch;
1527 ch->board = &boards[crd];
1528 #ifdef DEFAULT_HW_FLOW
1529 ch->digiext.digi_flags = RTSPACE|CTSPACE;
1530 #endif
1531 if(boards[crd].altpin) {
1532 ch->dsr = CD;
1533 ch->dcd = DSR;
1534 ch->digiext.digi_flags |= DIGI_ALTPIN;
1535 } else {
1536 ch->dcd = CD;
1537 ch->dsr = DSR;
1540 ch->magic = PCXX_MAGIC;
1541 ch->boardnum = crd;
1542 ch->channelnum = i;
1544 ch->dev = bd->first_minor + i;
1545 ch->tty = 0;
1547 if(shrinkmem) {
1548 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1549 shrinkmem = 0;
1552 if(bd->type != PCXEVE) {
1553 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1554 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1555 ch->txwin = ch->rxwin = 0;
1556 } else {
1557 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1558 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1559 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1560 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1563 ch->txbufsize = bc->tmax + 1;
1564 ch->rxbufsize = bc->rmax + 1;
1565 ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1566 lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1567 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1568 fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1569 fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1571 bc->edelay = 100;
1572 bc->idata = 1;
1574 ch->startc = bc->startc;
1575 ch->stopc = bc->stopc;
1576 ch->startca = bc->startca;
1577 ch->stopca = bc->stopca;
1579 ch->fepcflag = 0;
1580 ch->fepiflag = 0;
1581 ch->fepoflag = 0;
1582 ch->fepstartc = 0;
1583 ch->fepstopc = 0;
1584 ch->fepstartca = 0;
1585 ch->fepstopca = 0;
1587 ch->close_delay = 50;
1588 ch->count = 0;
1589 ch->blocked_open = 0;
1590 ch->callout_termios = pcxe_callout.init_termios;
1591 ch->normal_termios = pcxe_driver.init_termios;
1592 init_waitqueue_head(ch->open_wait);
1593 init_waitqueue_head(ch->close_wait);
1594 ch->asyncflags = 0;
1597 if (verbose)
1598 printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
1599 crd+1, board_desc[bd->type], board_mem[bd->type], bd->port,
1600 bd->membase, bd->numports);
1601 else
1602 printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
1603 board_desc[bd->type], board_mem[bd->type], bd->port,
1604 bd->membase, bd->numports);
1606 memwinoff(bd, 0);
1607 enabled_cards++;
1610 if (enabled_cards <= 0) {
1611 printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
1612 return -EIO;
1615 if(tty_register_driver(&pcxe_driver))
1616 panic("Couldn't register PC/Xe driver");
1618 if(tty_register_driver(&pcxe_callout))
1619 panic("Couldn't register PC/Xe callout");
1622 * Start up the poller to check for events on all enabled boards
1624 timer_active |= 1 << DIGI_TIMER;
1626 if (verbose)
1627 printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
1629 return 0;
1633 static void pcxxpoll(void)
1635 unsigned long flags;
1636 int crd;
1637 volatile unsigned int head, tail;
1638 struct channel *ch;
1639 struct board_info *bd;
1641 save_flags(flags);
1642 cli();
1644 for(crd=0; crd < numcards; crd++) {
1645 bd = &boards[crd];
1647 ch = digi_channels+bd->first_minor;
1649 if(bd->status == DISABLED)
1650 continue;
1652 assertmemoff(ch);
1654 globalwinon(ch);
1655 head = ch->mailbox->ein;
1656 tail = ch->mailbox->eout;
1658 if(head != tail)
1659 doevent(crd);
1661 memoff(ch);
1664 timer_table[DIGI_TIMER].fn = pcxxpoll;
1665 timer_table[DIGI_TIMER].expires = jiffies + HZ/25;
1666 timer_active |= 1 << DIGI_TIMER;
1667 restore_flags(flags);
1670 static void doevent(int crd)
1672 volatile struct board_info *bd;
1673 static struct tty_struct *tty;
1674 volatile struct board_chan *bc;
1675 volatile unchar *eventbuf;
1676 volatile unsigned int head;
1677 volatile unsigned int tail;
1678 struct channel *ch;
1679 struct channel *chan0;
1680 int channel, event, mstat, lstat;
1682 bd = &boards[crd];
1684 chan0 = digi_channels+bd->first_minor;
1685 pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
1688 assertgwinon(chan0);
1690 while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1691 assertgwinon(chan0);
1692 eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
1693 channel = eventbuf[0];
1694 event = eventbuf[1];
1695 mstat = eventbuf[2];
1696 lstat = eventbuf[3];
1698 ch=chan0+channel;
1700 if ((unsigned)channel >= bd->numports || !ch) {
1701 printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1702 printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1703 crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1704 if(channel >= bd->numports)
1705 ch = chan0;
1706 bc = ch->brdchan;
1707 goto next;
1709 if ((bc = ch->brdchan) == NULL)
1710 goto next;
1712 if (event & DATA_IND) {
1713 receive_data(ch);
1714 assertgwinon(ch);
1717 if (event & MODEMCHG_IND) {
1718 ch->imodem = mstat;
1719 if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) {
1720 if (ch->asyncflags & ASYNC_CHECK_CD) {
1721 if (mstat & ch->dcd) {
1722 wake_up_interruptible(&ch->open_wait);
1723 } else {
1724 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1730 tty = ch->tty;
1732 if (tty) {
1734 if (event & BREAK_IND) {
1735 tty->flip.count++;
1736 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1737 *tty->flip.char_buf_ptr++ = 0;
1738 #if 0
1739 if (ch->asyncflags & ASYNC_SAK)
1740 do_SAK(tty);
1741 #endif
1742 tty_schedule_flip(tty);
1745 if (event & LOWTX_IND) {
1746 if (ch->statusflags & LOWWAIT) {
1747 ch->statusflags &= ~LOWWAIT;
1748 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1749 tty->ldisc.write_wakeup)
1750 (tty->ldisc.write_wakeup)(tty);
1751 wake_up_interruptible(&tty->write_wait);
1755 if (event & EMPTYTX_IND) {
1756 ch->statusflags &= ~TXBUSY;
1757 if (ch->statusflags & EMPTYWAIT) {
1758 ch->statusflags &= ~EMPTYWAIT;
1759 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1760 tty->ldisc.write_wakeup)
1761 (tty->ldisc.write_wakeup)(tty);
1762 wake_up_interruptible(&tty->write_wait);
1767 next:
1768 globalwinon(ch);
1769 if(!bc) printk("bc == NULL in doevent!\n");
1770 else bc->idata = 1;
1772 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1773 globalwinon(chan0);
1780 * pcxxdelay - delays a specified number of milliseconds
1782 static void pcxxdelay(int msec)
1784 while(msec-- > 0)
1785 __delay(loops_per_sec/1000);
1789 static void
1790 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
1791 int bytecmd)
1793 unchar *memaddr;
1794 unsigned int head, tail;
1795 long count;
1796 int n;
1798 if(ch->board->status == DISABLED)
1799 return;
1801 assertgwinon(ch);
1803 memaddr = (unchar *)phys_to_virt(ch->board->membase);
1804 head = ch->mailbox->cin;
1806 if(head >= (CMAX-CSTART) || (head & 03)) {
1807 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1808 return;
1811 if(bytecmd) {
1812 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1814 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1816 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1817 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1818 } else {
1819 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1821 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1822 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1825 head = (head+4) & (CMAX-CSTART-4);
1826 ch->mailbox->cin = head;
1828 count = FEPTIMEOUT;
1830 while(1) {
1831 count--;
1832 if(count == 0) {
1833 printk("Fep not responding in fepcmd()\n");
1834 return;
1837 head = ch->mailbox->cin;
1838 tail = ch->mailbox->cout;
1840 n = (head-tail) & (CMAX-CSTART-4);
1842 if(n <= ncmds * (sizeof(short)*4))
1843 break;
1844 /* Seems not to be good here: schedule(); */
1849 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
1851 unsigned res = 0;
1852 #ifdef SPEED_HACK
1853 /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
1854 if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
1855 if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
1856 #endif
1857 if (cflag & CBAUDEX)
1859 ch->digiext.digi_flags |= DIGI_FAST;
1860 res |= FEP_HUPCL;
1861 /* This gets strange but if we don't do this we will get 78600
1862 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
1863 * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
1864 * do 115K
1866 if (cflag & B115200) res|=1;
1868 else ch->digiext.digi_flags &= ~DIGI_FAST;
1869 res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
1870 return res;
1873 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
1875 unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1877 if(ch->digiext.digi_flags & DIGI_AIXON)
1878 res |= IAIXON;
1879 return res;
1882 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
1884 unsigned res = 0;
1886 if(cflag & CRTSCTS) {
1887 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1888 res |= (CTS | RTS);
1890 if(ch->digiext.digi_flags & RTSPACE)
1891 res |= RTS;
1892 if(ch->digiext.digi_flags & DTRPACE)
1893 res |= DTR;
1894 if(ch->digiext.digi_flags & CTSPACE)
1895 res |= CTS;
1896 if(ch->digiext.digi_flags & DSRPACE)
1897 res |= ch->dsr;
1898 if(ch->digiext.digi_flags & DCDPACE)
1899 res |= ch->dcd;
1901 if (res & RTS)
1902 ch->digiext.digi_flags |= RTSPACE;
1903 if (res & CTS)
1904 ch->digiext.digi_flags |= CTSPACE;
1906 return res;
1909 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
1911 volatile struct board_chan *bc;
1912 unsigned int head;
1913 unsigned mval, hflow, cflag, iflag;
1914 struct termios *ts;
1916 bc = ch->brdchan;
1917 assertgwinon(ch);
1918 ts = tty->termios;
1920 if((ts->c_cflag & CBAUD) == 0) {
1921 head = bc->rin;
1922 bc->rout = head;
1923 head = bc->tin;
1924 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1925 mval = 0;
1926 } else {
1928 cflag = termios2digi_c(ch, ts->c_cflag);
1930 if(cflag != ch->fepcflag) {
1931 ch->fepcflag = cflag;
1932 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1935 if(cflag & CLOCAL)
1936 ch->asyncflags &= ~ASYNC_CHECK_CD;
1937 else {
1938 ch->asyncflags |= ASYNC_CHECK_CD;
1941 mval = DTR | RTS;
1944 iflag = termios2digi_i(ch, ts->c_iflag);
1946 if(iflag != ch->fepiflag) {
1947 ch->fepiflag = iflag;
1948 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1951 bc->mint = ch->dcd;
1952 if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1953 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1954 bc->mint = 0;
1956 ch->imodem = bc->mstat;
1958 hflow = termios2digi_h(ch, ts->c_cflag);
1960 if(hflow != ch->hflow) {
1961 ch->hflow = hflow;
1962 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1965 /* mval ^= ch->modemfake & (mval ^ ch->modem); */
1967 if(ch->omodem != mval) {
1968 ch->omodem = mval;
1969 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1972 if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1973 ch->fepstartc = ch->startc;
1974 ch->fepstopc = ch->stopc;
1975 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1978 if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1979 ch->fepstartca = ch->startca;
1980 ch->fepstopca = ch->stopca;
1981 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1986 static void receive_data(struct channel *ch)
1988 volatile struct board_chan *bc;
1989 struct tty_struct *tty;
1990 unsigned int tail, head, wrapmask;
1991 int n;
1992 int piece;
1993 struct termios *ts=0;
1994 unchar *rptr;
1995 int rc;
1996 int wrapgap;
1998 globalwinon(ch);
2000 if (ch->statusflags & RXSTOPPED)
2001 return;
2003 tty = ch->tty;
2004 if(tty)
2005 ts = tty->termios;
2007 bc = ch->brdchan;
2009 if(!bc) {
2010 printk("bc is NULL in receive_data!\n");
2011 return;
2014 wrapmask = ch->rxbufsize - 1;
2016 head = bc->rin;
2017 head &= wrapmask;
2018 tail = bc->rout & wrapmask;
2020 n = (head-tail) & wrapmask;
2022 if(n == 0)
2023 return;
2026 * If CREAD bit is off or device not open, set TX tail to head
2028 if(!tty || !ts || !(ts->c_cflag & CREAD)) {
2029 bc->rout = head;
2030 return;
2033 if(tty->flip.count == TTY_FLIPBUF_SIZE) {
2034 /* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
2035 return;
2038 if(bc->orun) {
2039 bc->orun = 0;
2040 printk("overrun! DigiBoard device minor=%d\n",MINOR(tty->device));
2043 rxwinon(ch);
2044 rptr = tty->flip.char_buf_ptr;
2045 rc = tty->flip.count;
2046 while(n > 0) {
2047 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
2048 piece = (wrapgap < n) ? wrapgap : n;
2051 * Make sure we don't overflow the buffer
2054 if ((rc + piece) > TTY_FLIPBUF_SIZE)
2055 piece = TTY_FLIPBUF_SIZE - rc;
2057 if (piece == 0)
2058 break;
2060 memcpy(rptr, ch->rxptr + tail, piece);
2061 rptr += piece;
2062 rc += piece;
2063 tail = (tail + piece) & wrapmask;
2064 n -= piece;
2066 tty->flip.count = rc;
2067 tty->flip.char_buf_ptr = rptr;
2068 globalwinon(ch);
2069 bc->rout = tail;
2071 /* Must be called with global data */
2072 tty_schedule_flip(ch->tty);
2073 return;
2077 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
2078 unsigned int cmd, unsigned long arg)
2080 int error;
2081 struct channel *ch = (struct channel *) tty->driver_data;
2082 volatile struct board_chan *bc;
2083 int retval;
2084 unsigned int mflag, mstat;
2085 unsigned char startc, stopc;
2086 unsigned long flags;
2087 digiflow_t dflow;
2089 if(ch)
2090 bc = ch->brdchan;
2091 else {
2092 printk("ch is NULL in pcxe_ioctl!\n");
2093 return(-EINVAL);
2096 save_flags(flags);
2098 switch(cmd) {
2099 case TCSBRK: /* SVID version: non-zero arg --> no break */
2100 retval = tty_check_change(tty);
2101 if(retval)
2102 return retval;
2103 setup_empty_event(tty,ch);
2104 tty_wait_until_sent(tty, 0);
2105 if(!arg)
2106 digi_send_break(ch, HZ/4); /* 1/4 second */
2107 return 0;
2109 case TCSBRKP: /* support for POSIX tcsendbreak() */
2110 retval = tty_check_change(tty);
2111 if(retval)
2112 return retval;
2113 setup_empty_event(tty,ch);
2114 tty_wait_until_sent(tty, 0);
2115 digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
2116 return 0;
2118 case TIOCGSOFTCAR:
2119 return put_user(C_CLOCAL(tty) ? 1 : 0,
2120 (unsigned int *) arg);
2122 case TIOCSSOFTCAR:
2124 unsigned int value;
2125 error = get_user( value, (unsigned int *) arg);
2126 if (error)
2127 return error;
2128 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
2130 return 0;
2132 case TIOCMODG:
2133 case TIOCMGET:
2134 mflag = 0;
2136 cli();
2137 globalwinon(ch);
2138 mstat = bc->mstat;
2139 memoff(ch);
2140 restore_flags(flags);
2142 if(mstat & DTR)
2143 mflag |= TIOCM_DTR;
2144 if(mstat & RTS)
2145 mflag |= TIOCM_RTS;
2146 if(mstat & CTS)
2147 mflag |= TIOCM_CTS;
2148 if(mstat & ch->dsr)
2149 mflag |= TIOCM_DSR;
2150 if(mstat & RI)
2151 mflag |= TIOCM_RI;
2152 if(mstat & ch->dcd)
2153 mflag |= TIOCM_CD;
2155 error = put_user(mflag, (unsigned int *) arg);
2156 if(error)
2157 return error;
2158 break;
2160 case TIOCMBIS:
2161 case TIOCMBIC:
2162 case TIOCMODS:
2163 case TIOCMSET:
2164 error = get_user(mstat, (unsigned int *) arg);
2165 if(error)
2166 return error;
2168 mflag = 0;
2169 if(mstat & TIOCM_DTR)
2170 mflag |= DTR;
2171 if(mstat & TIOCM_RTS)
2172 mflag |= RTS;
2174 switch(cmd) {
2175 case TIOCMODS:
2176 case TIOCMSET:
2177 ch->modemfake = DTR|RTS;
2178 ch->modem = mflag;
2179 break;
2181 case TIOCMBIS:
2182 ch->modemfake |= mflag;
2183 ch->modem |= mflag;
2184 break;
2186 case TIOCMBIC:
2187 ch->modemfake &= ~mflag;
2188 ch->modem &= ~mflag;
2189 break;
2192 cli();
2193 globalwinon(ch);
2194 pcxxparam(tty,ch);
2195 memoff(ch);
2196 restore_flags(flags);
2197 break;
2199 case TIOCSDTR:
2200 cli();
2201 ch->omodem |= DTR;
2202 globalwinon(ch);
2203 fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
2204 memoff(ch);
2205 restore_flags(flags);
2206 break;
2208 case TIOCCDTR:
2209 ch->omodem &= ~DTR;
2210 cli();
2211 globalwinon(ch);
2212 fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
2213 memoff(ch);
2214 restore_flags(flags);
2215 break;
2217 case DIGI_GETA:
2218 if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
2219 return(error);
2221 copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));
2222 break;
2224 case DIGI_SETAW:
2225 case DIGI_SETAF:
2226 if(cmd == DIGI_SETAW) {
2227 setup_empty_event(tty,ch);
2228 tty_wait_until_sent(tty, 0);
2230 else {
2231 if(tty->ldisc.flush_buffer)
2232 tty->ldisc.flush_buffer(tty);
2235 /* Fall Thru */
2237 case DIGI_SETA:
2238 if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
2239 return(error);
2241 copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));
2242 #ifdef DEBUG_IOCTL
2243 printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
2244 #endif
2246 if(ch->digiext.digi_flags & DIGI_ALTPIN) {
2247 ch->dcd = DSR;
2248 ch->dsr = CD;
2249 } else {
2250 ch->dcd = CD;
2251 ch->dsr = DSR;
2254 cli();
2255 globalwinon(ch);
2256 pcxxparam(tty,ch);
2257 memoff(ch);
2258 restore_flags(flags);
2259 break;
2261 case DIGI_GETFLOW:
2262 case DIGI_GETAFLOW:
2263 cli();
2264 globalwinon(ch);
2265 if(cmd == DIGI_GETFLOW) {
2266 dflow.startc = bc->startc;
2267 dflow.stopc = bc->stopc;
2268 } else {
2269 dflow.startc = bc->startca;
2270 dflow.stopc = bc->stopca;
2272 memoff(ch);
2273 restore_flags(flags);
2275 if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
2276 return(error);
2278 copy_to_user((char*)arg, &dflow, sizeof(dflow));
2279 break;
2281 case DIGI_SETAFLOW:
2282 case DIGI_SETFLOW:
2283 if(cmd == DIGI_SETFLOW) {
2284 startc = ch->startc;
2285 stopc = ch->stopc;
2286 } else {
2287 startc = ch->startca;
2288 stopc = ch->stopca;
2291 if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
2292 return(error);
2294 copy_from_user(&dflow, (char*)arg, sizeof(dflow));
2296 if(dflow.startc != startc || dflow.stopc != stopc) {
2297 cli();
2298 globalwinon(ch);
2300 if(cmd == DIGI_SETFLOW) {
2301 ch->fepstartc = ch->startc = dflow.startc;
2302 ch->fepstopc = ch->stopc = dflow.stopc;
2303 fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
2304 } else {
2305 ch->fepstartca = ch->startca = dflow.startc;
2306 ch->fepstopca = ch->stopca = dflow.stopc;
2307 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
2310 if(ch->statusflags & TXSTOPPED)
2311 pcxe_start(tty);
2313 memoff(ch);
2314 restore_flags(flags);
2316 break;
2318 default:
2319 return -ENOIOCTLCMD;
2322 return 0;
2325 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
2327 struct channel *info;
2329 if ((info=chan(tty))!=NULL) {
2330 unsigned long flags;
2331 save_flags(flags);
2332 cli();
2333 globalwinon(info);
2334 pcxxparam(tty,info);
2335 memoff(info);
2337 if ((old_termios->c_cflag & CRTSCTS) &&
2338 ((tty->termios->c_cflag & CRTSCTS) == 0))
2339 tty->hw_stopped = 0;
2340 if(!(old_termios->c_cflag & CLOCAL) &&
2341 (tty->termios->c_cflag & CLOCAL))
2342 wake_up_interruptible(&info->open_wait);
2343 restore_flags(flags);
2348 static void do_pcxe_bh(void)
2350 run_task_queue(&tq_pcxx);
2354 static void do_softint(void *private_)
2356 struct channel *info = (struct channel *) private_;
2358 if(info && info->magic == PCXX_MAGIC) {
2359 struct tty_struct *tty = info->tty;
2360 if (tty && tty->driver_data) {
2361 if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
2362 tty_hangup(tty);
2363 wake_up_interruptible(&info->open_wait);
2364 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
2371 static void pcxe_stop(struct tty_struct *tty)
2373 struct channel *info;
2375 if ((info=chan(tty))!=NULL) {
2376 unsigned long flags;
2377 save_flags(flags);
2378 cli();
2379 if ((info->statusflags & TXSTOPPED) == 0) {
2380 globalwinon(info);
2381 fepcmd(info, PAUSETX, 0, 0, 0, 0);
2382 info->statusflags |= TXSTOPPED;
2383 memoff(info);
2385 restore_flags(flags);
2389 static void pcxe_throttle(struct tty_struct * tty)
2391 struct channel *info;
2393 if ((info=chan(tty))!=NULL) {
2394 unsigned long flags;
2395 save_flags(flags);
2396 cli();
2397 if ((info->statusflags & RXSTOPPED) == 0) {
2398 globalwinon(info);
2399 fepcmd(info, PAUSERX, 0, 0, 0, 0);
2400 info->statusflags |= RXSTOPPED;
2401 memoff(info);
2403 restore_flags(flags);
2407 static void pcxe_unthrottle(struct tty_struct *tty)
2409 struct channel *info;
2411 if ((info=chan(tty)) != NULL) {
2412 unsigned long flags;
2414 /* Just in case output was resumed because of a change in Digi-flow */
2415 save_flags(flags);
2416 cli();
2417 if(info->statusflags & RXSTOPPED) {
2418 volatile struct board_chan *bc;
2419 globalwinon(info);
2420 bc = info->brdchan;
2421 fepcmd(info, RESUMERX, 0, 0, 0, 0);
2422 info->statusflags &= ~RXSTOPPED;
2423 memoff(info);
2425 restore_flags(flags);
2430 static void pcxe_start(struct tty_struct *tty)
2432 struct channel *info;
2434 if ((info=chan(tty))!=NULL) {
2435 unsigned long flags;
2437 save_flags(flags);
2438 cli();
2439 /* Just in case output was resumed because of a change in Digi-flow */
2440 if(info->statusflags & TXSTOPPED) {
2441 volatile struct board_chan *bc;
2442 globalwinon(info);
2443 bc = info->brdchan;
2444 if(info->statusflags & LOWWAIT)
2445 bc->ilow = 1;
2446 fepcmd(info, RESUMETX, 0, 0, 0, 0);
2447 info->statusflags &= ~TXSTOPPED;
2448 memoff(info);
2450 restore_flags(flags);
2455 void digi_send_break(struct channel *ch, int msec)
2457 unsigned long flags;
2459 save_flags(flags);
2460 cli();
2461 globalwinon(ch);
2464 * Maybe I should send an infinite break here, schedule() for
2465 * msec amount of time, and then stop the break. This way,
2466 * the user can't screw up the FEP by causing digi_send_break()
2467 * to be called (i.e. via an ioctl()) more than once in msec amount
2468 * of time. Try this for now...
2471 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2472 memoff(ch);
2474 restore_flags(flags);
2477 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
2479 volatile struct board_chan *bc;
2480 unsigned long flags;
2482 save_flags(flags);
2483 cli();
2484 globalwinon(ch);
2485 ch->statusflags |= EMPTYWAIT;
2486 bc = ch->brdchan;
2487 bc->iempty = 1;
2488 memoff(ch);
2489 restore_flags(flags);