Import 2.3.16
[davej-history.git] / drivers / char / pcxx.c
blobad5a4270ebf122a46a52aaa8fd0d65fe17830f62
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>
83 #define VERSION "1.6.1"
85 #include "digi.h"
86 #include "fep.h"
87 #include "pcxx.h"
88 #include "digi_fep.h"
89 #include "digi_bios.h"
92 * Define one default setting if no digi= config line is used.
93 * Default is altpin = disabled, 16 ports, I/O 200h, Memory 0D0000h
95 static struct board_info boards[MAX_DIGI_BOARDS] = { {
96 /* Board is enabled */ ENABLED,
97 /* Type is auto-detected */ 0,
98 /* altping is disabled */ DISABLED,
99 /* number of ports = 16 */ 16,
100 /* io address is 0x200 */ 0x200,
101 /* card memory at 0xd0000 */ 0xd0000,
102 /* first minor device no. */ 0
103 } };
105 static int verbose = 0;
106 static int debug = 0;
108 #ifdef MODULE
109 /* Variables for insmod */
110 static int io[] = {0, 0, 0, 0};
111 static int membase[] = {0, 0, 0, 0};
112 static int memsize[] = {0, 0, 0, 0};
113 static int altpin[] = {0, 0, 0, 0};
114 static int numports[] = {0, 0, 0, 0};
116 # if (LINUX_VERSION_CODE > 0x020111)
117 MODULE_AUTHOR("Bernhard Kaindl");
118 MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
119 MODULE_PARM(verbose, "i");
120 MODULE_PARM(debug, "i");
121 MODULE_PARM(io, "1-4i");
122 MODULE_PARM(membase, "1-4i");
123 MODULE_PARM(memsize, "1-4i");
124 MODULE_PARM(altpin, "1-4i");
125 MODULE_PARM(numports, "1-4i");
126 # endif
128 #endif MODULE
130 static int numcards = 1;
131 static int nbdevs = 0;
133 static struct channel *digi_channels;
134 static struct tty_struct **pcxe_table;
135 static struct termios **pcxe_termios;
136 static struct termios **pcxe_termios_locked;
138 int pcxx_ncook=sizeof(pcxx_cook);
139 int pcxx_nbios=sizeof(pcxx_bios);
141 #define MIN(a,b) ((a) < (b) ? (a) : (b))
142 #define pcxxassert(x, msg) if(!(x)) pcxx_error(__LINE__, msg)
144 #define FEPTIMEOUT 200000
145 #define SERIAL_TYPE_NORMAL 1
146 #define SERIAL_TYPE_CALLOUT 2
147 #define PCXE_EVENT_HANGUP 1
149 struct tty_driver pcxe_driver;
150 struct tty_driver pcxe_callout;
151 static int pcxe_refcount;
153 DECLARE_TASK_QUEUE(tq_pcxx);
155 static void pcxxpoll(void);
156 static void pcxxdelay(int);
157 static void fepcmd(struct channel *, int, int, int, int, int);
158 static void pcxe_put_char(struct tty_struct *, unsigned char);
159 static void pcxe_flush_chars(struct tty_struct *);
160 static void pcxx_error(int, char *);
161 static void pcxe_close(struct tty_struct *, struct file *);
162 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
163 static void pcxe_set_termios(struct tty_struct *, struct termios *);
164 static int pcxe_write(struct tty_struct *, int, const unsigned char *, int);
165 static int pcxe_write_room(struct tty_struct *);
166 static int pcxe_chars_in_buffer(struct tty_struct *);
167 static void pcxe_flush_buffer(struct tty_struct *);
168 static void doevent(int);
169 static void receive_data(struct channel *);
170 static void pcxxparam(struct tty_struct *, struct channel *ch);
171 static void do_softint(void *);
172 static inline void pcxe_sched_event(struct channel *, int);
173 static void do_pcxe_bh(void);
174 static void pcxe_start(struct tty_struct *);
175 static void pcxe_stop(struct tty_struct *);
176 static void pcxe_throttle(struct tty_struct *);
177 static void pcxe_unthrottle(struct tty_struct *);
178 static void digi_send_break(struct channel *ch, int msec);
179 static void shutdown(struct channel *);
180 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
181 static inline void memwinon(struct board_info *b, unsigned int win);
182 static inline void memwinoff(struct board_info *b, unsigned int win);
183 static inline void globalwinon(struct channel *ch);
184 static inline void rxwinon(struct channel *ch);
185 static inline void txwinon(struct channel *ch);
186 static inline void memoff(struct channel *ch);
187 static inline void assertgwinon(struct channel *ch);
188 static inline void assertmemoff(struct channel *ch);
190 #define TZ_BUFSZ 4096
192 /* function definitions */
193 #ifdef MODULE
196 * pcxe_init() is our init_module():
198 #define pcxe_init init_module
200 void cleanup_module(void);
203 /*****************************************************************************/
205 void cleanup_module()
208 unsigned long flags;
209 int crd, i;
210 int e1, e2;
211 struct board_info *bd;
212 struct channel *ch;
214 printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION);
216 save_flags(flags);
217 cli();
218 timer_active &= ~(1 << DIGI_TIMER);
219 timer_table[DIGI_TIMER].fn = NULL;
220 timer_table[DIGI_TIMER].expires = 0;
221 remove_bh(DIGI_BH);
223 if ((e1 = tty_unregister_driver(&pcxe_driver)))
224 printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
225 if ((e2 = tty_unregister_driver(&pcxe_callout)))
226 printk("SERIAL: failed to unregister callout driver (%d)\n",e2);
228 for(crd=0; crd < numcards; crd++) {
229 bd = &boards[crd];
230 ch = digi_channels+bd->first_minor;
231 for(i=0; i < bd->numports; i++, ch++) {
232 kfree(ch->tmp_buf);
234 release_region(bd->port, 4);
236 kfree(digi_channels);
237 kfree(pcxe_termios_locked);
238 kfree(pcxe_termios);
239 kfree(pcxe_table);
240 restore_flags(flags);
242 #endif
244 static inline struct channel *chan(register struct tty_struct *tty)
246 if (tty) {
247 register struct channel *ch=(struct channel *)tty->driver_data;
248 if (ch >= digi_channels && ch < digi_channels+nbdevs) {
249 if (ch->magic==PCXX_MAGIC)
250 return ch;
253 return NULL;
256 /* These inline routines are to turn board memory on and off */
257 static inline void memwinon(struct board_info *b, unsigned int win)
259 if(b->type == PCXEVE)
260 outb_p(FEPWIN|win, b->port+1);
261 else
262 outb_p(inb(b->port)|FEPMEM, b->port);
265 static inline void memwinoff(struct board_info *b, unsigned int win)
267 outb_p(inb(b->port)&~FEPMEM, b->port);
268 if(b->type == PCXEVE)
269 outb_p(0, b->port + 1);
272 static inline void globalwinon(struct channel *ch)
274 if(ch->board->type == PCXEVE)
275 outb_p(FEPWIN, ch->board->port+1);
276 else
277 outb_p(FEPMEM, ch->board->port);
280 static inline void rxwinon(struct channel *ch)
282 if(ch->rxwin == 0)
283 outb_p(FEPMEM, ch->board->port);
284 else
285 outb_p(ch->rxwin, ch->board->port+1);
288 static inline void txwinon(struct channel *ch)
290 if(ch->txwin == 0)
291 outb_p(FEPMEM, ch->board->port);
292 else
293 outb_p(ch->txwin, ch->board->port+1);
296 static inline void memoff(struct channel *ch)
298 outb_p(0, ch->board->port);
299 if(ch->board->type == PCXEVE)
300 outb_p(0, ch->board->port+1);
303 static inline void assertgwinon(struct channel *ch)
305 if(ch->board->type != PCXEVE)
306 pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
309 static inline void assertmemoff(struct channel *ch)
311 if(ch->board->type != PCXEVE)
312 pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
315 static inline void pcxe_sched_event(struct channel *info, int event)
317 info->event |= 1 << event;
318 queue_task(&info->tqueue, &tq_pcxx);
319 mark_bh(DIGI_BH);
322 static void pcxx_error(int line, char *msg)
324 printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
327 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
329 DECLARE_WAITQUEUE(wait, current);
330 int retval = 0;
331 int do_clocal = 0;
333 if (info->asyncflags & ASYNC_CALLOUT_ACTIVE) {
334 if (info->normal_termios.c_cflag & CLOCAL)
335 do_clocal = 1;
336 } else {
337 if (tty->termios->c_cflag & CLOCAL)
338 do_clocal = 1;
342 * Block waiting for the carrier detect and the line to become free
345 retval = 0;
346 add_wait_queue(&info->open_wait, &wait);
347 info->count--;
348 info->blocked_open++;
350 for (;;) {
351 cli();
352 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0) {
353 globalwinon(info);
354 info->omodem |= DTR|RTS;
355 fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
356 memoff(info);
358 sti();
359 set_current_state(TASK_INTERRUPTIBLE);
360 if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
361 if(info->asyncflags & ASYNC_HUP_NOTIFY)
362 retval = -EAGAIN;
363 else
364 retval = -ERESTARTSYS;
365 break;
367 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0 &&
368 (info->asyncflags & ASYNC_CLOSING) == 0 &&
369 (do_clocal || (info->imodem & info->dcd)))
370 break;
371 if(signal_pending(current)) {
372 retval = -ERESTARTSYS;
373 break;
375 schedule();
377 current->state = TASK_RUNNING;
378 remove_wait_queue(&info->open_wait, &wait);
380 if(!tty_hung_up_p(filp))
381 info->count++;
382 info->blocked_open--;
384 return retval;
388 int pcxe_open(struct tty_struct *tty, struct file * filp)
390 volatile struct board_chan *bc;
391 struct channel *ch;
392 unsigned long flags;
393 int line;
394 int boardnum;
395 int retval;
397 line = MINOR(tty->device) - tty->driver.minor_start;
399 if(line < 0 || line >= nbdevs) {
400 printk("line out of range in pcxe_open\n");
401 tty->driver_data = NULL;
402 return(-ENODEV);
405 for(boardnum=0;boardnum<numcards;boardnum++)
406 if ((line >= boards[boardnum].first_minor) &&
407 (line < boards[boardnum].first_minor + boards[boardnum].numports))
408 break;
410 if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
411 (line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
412 tty->driver_data = NULL; /* Mark this device as 'down' */
413 return(-ENODEV);
416 ch = digi_channels+line;
418 if(ch->brdchan == 0) {
419 tty->driver_data = NULL;
420 return(-ENODEV);
423 /* flag the kernel that there is somebody using this guy */
424 MOD_INC_USE_COUNT;
426 * If the device is in the middle of being closed, then block
427 * until it's done, and then try again.
429 if(ch->asyncflags & ASYNC_CLOSING) {
430 interruptible_sleep_on(&ch->close_wait);
431 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
432 return -EAGAIN;
433 else
434 return -ERESTARTSYS;
437 save_flags(flags);
438 cli();
439 ch->count++;
440 tty->driver_data = ch;
441 ch->tty = tty;
443 if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
444 unsigned int head;
446 globalwinon(ch);
447 ch->statusflags = 0;
448 bc=ch->brdchan;
449 ch->imodem = bc->mstat;
450 head = bc->rin;
451 bc->rout = head;
452 ch->tty = tty;
453 pcxxparam(tty,ch);
454 ch->imodem = bc->mstat;
455 bc->idata = 1;
456 ch->omodem = DTR|RTS;
457 fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
458 memoff(ch);
459 ch->asyncflags |= ASYNC_INITIALIZED;
461 restore_flags(flags);
463 if(ch->asyncflags & ASYNC_CLOSING) {
464 interruptible_sleep_on(&ch->close_wait);
465 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
466 return -EAGAIN;
467 else
468 return -ERESTARTSYS;
471 * If this is a callout device, then just make sure the normal
472 * device isn't being used.
474 if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
475 if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
476 return -EBUSY;
477 if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) {
478 if ((ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
479 (ch->session != current->session))
480 return -EBUSY;
481 if((ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
482 (ch->pgrp != current->pgrp))
483 return -EBUSY;
485 ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
487 else {
488 if (filp->f_flags & O_NONBLOCK) {
489 if(ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
490 return -EBUSY;
492 else {
493 /* this has to be set in order for the "block until
494 * CD" code to work correctly. i'm not sure under
495 * what circumstances asyncflags should be set to
496 * ASYNC_NORMAL_ACTIVE though
497 * brian@ilinx.com
499 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
500 if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
501 return retval;
503 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
506 save_flags(flags);
507 cli();
508 if((ch->count == 1) && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
509 if(tty->driver.subtype == SERIAL_TYPE_NORMAL)
510 *tty->termios = ch->normal_termios;
511 else
512 *tty->termios = ch->callout_termios;
513 globalwinon(ch);
514 pcxxparam(tty,ch);
515 memoff(ch);
518 ch->session = current->session;
519 ch->pgrp = current->pgrp;
520 restore_flags(flags);
521 return 0;
524 static void shutdown(struct channel *info)
526 unsigned long flags;
527 volatile struct board_chan *bc;
528 struct tty_struct *tty;
530 if (!(info->asyncflags & ASYNC_INITIALIZED))
531 return;
533 save_flags(flags);
534 cli();
535 globalwinon(info);
537 bc = info->brdchan;
538 if(bc)
539 bc->idata = 0;
541 tty = info->tty;
544 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
546 if(tty->termios->c_cflag & HUPCL) {
547 info->omodem &= ~(RTS|DTR);
548 fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
551 memoff(info);
552 info->asyncflags &= ~ASYNC_INITIALIZED;
553 restore_flags(flags);
557 static void pcxe_close(struct tty_struct * tty, struct file * filp)
559 struct channel *info;
561 if ((info=chan(tty))!=NULL) {
562 unsigned long flags;
563 save_flags(flags);
564 cli();
566 if(tty_hung_up_p(filp)) {
567 /* flag that somebody is done with this module */
568 MOD_DEC_USE_COUNT;
569 restore_flags(flags);
570 return;
572 /* this check is in serial.c, it won't hurt to do it here too */
573 if ((tty->count == 1) && (info->count != 1)) {
575 * Uh, oh. tty->count is 1, which means that the tty
576 * structure will be freed. Info->count should always
577 * be one in these conditions. If it's greater than
578 * one, we've got real problems, since it means the
579 * serial port won't be shutdown.
581 printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
582 info->count = 1;
584 if (info->count-- > 1) {
585 restore_flags(flags);
586 MOD_DEC_USE_COUNT;
587 return;
589 if (info->count < 0) {
590 info->count = 0;
593 info->asyncflags |= ASYNC_CLOSING;
596 * Save the termios structure, since this port may have
597 * separate termios for callout and dialin.
599 if(info->asyncflags & ASYNC_NORMAL_ACTIVE)
600 info->normal_termios = *tty->termios;
601 if(info->asyncflags & ASYNC_CALLOUT_ACTIVE)
602 info->callout_termios = *tty->termios;
603 tty->closing = 1;
604 if(info->asyncflags & ASYNC_INITIALIZED) {
605 setup_empty_event(tty,info);
606 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
609 if(tty->driver.flush_buffer)
610 tty->driver.flush_buffer(tty);
611 if(tty->ldisc.flush_buffer)
612 tty->ldisc.flush_buffer(tty);
613 shutdown(info);
614 tty->closing = 0;
615 info->event = 0;
616 info->tty = NULL;
617 #ifndef MODULE
618 /* ldiscs[] is not available in a MODULE
619 ** worth noting that while I'm not sure what this hunk of code is supposed
620 ** to do, it is not present in the serial.c driver. Hmmm. If you know,
621 ** please send me a note. brian@ilinx.com
622 ** Don't know either what this is supposed to do clameter@waterf.org.
624 if(tty->ldisc.num != ldiscs[N_TTY].num) {
625 if(tty->ldisc.close)
626 (tty->ldisc.close)(tty);
627 tty->ldisc = ldiscs[N_TTY];
628 tty->termios->c_line = N_TTY;
629 if(tty->ldisc.open)
630 (tty->ldisc.open)(tty);
632 #endif
633 if(info->blocked_open) {
634 if(info->close_delay) {
635 current->state = TASK_INTERRUPTIBLE;
636 schedule_timeout(info->close_delay);
638 wake_up_interruptible(&info->open_wait);
640 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
641 ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
642 wake_up_interruptible(&info->close_wait);
643 MOD_DEC_USE_COUNT;
644 restore_flags(flags);
649 void pcxe_hangup(struct tty_struct *tty)
651 struct channel *ch;
653 if ((ch=chan(tty))!=NULL) {
654 unsigned long flags;
656 save_flags(flags);
657 cli();
658 shutdown(ch);
659 ch->event = 0;
660 ch->count = 0;
661 ch->tty = NULL;
662 ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
663 wake_up_interruptible(&ch->open_wait);
664 restore_flags(flags);
670 static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
672 struct channel *ch;
673 volatile struct board_chan *bc;
674 int total, remain, size, stlen;
675 unsigned int head, tail;
676 unsigned long flags;
678 /* printk("Entering pcxe_write()\n"); */
680 if ((ch=chan(tty))==NULL)
681 return 0;
683 bc = ch->brdchan;
684 size = ch->txbufsize;
686 if (from_user) {
688 save_flags(flags);
689 cli();
690 globalwinon(ch);
691 head = bc->tin & (size - 1);
692 /* It seems to be necessary to make sure that the value is stable here somehow
693 This is a rather odd pice of code here. */
695 { tail = bc->tout;
696 } while (tail != bc->tout);
698 tail &= (size - 1);
699 stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
700 count = MIN(stlen, count);
701 if (count) {
702 if (verify_area(VERIFY_READ, (char*)buf, count))
703 count=0;
704 else copy_from_user(ch->tmp_buf, buf, count);
706 buf = ch->tmp_buf;
707 memoff(ch);
708 restore_flags(flags);
712 * All data is now local
715 total = 0;
716 save_flags(flags);
717 cli();
718 globalwinon(ch);
719 head = bc->tin & (size - 1);
720 tail = bc->tout;
721 if (tail != bc->tout)
722 tail = bc->tout;
723 tail &= (size - 1);
724 if (head >= tail) {
725 remain = size - (head - tail) - 1;
726 stlen = size - head;
728 else {
729 remain = tail - head - 1;
730 stlen = remain;
732 count = MIN(remain, count);
734 txwinon(ch);
735 while (count > 0) {
736 stlen = MIN(count, stlen);
737 memcpy(ch->txptr + head, buf, stlen);
738 buf += stlen;
739 count -= stlen;
740 total += stlen;
741 head += stlen;
742 if (head >= size) {
743 head = 0;
744 stlen = tail;
747 ch->statusflags |= TXBUSY;
748 globalwinon(ch);
749 bc->tin = head;
750 if ((ch->statusflags & LOWWAIT) == 0) {
751 ch->statusflags |= LOWWAIT;
752 bc->ilow = 1;
754 memoff(ch);
755 restore_flags(flags);
757 return(total);
761 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
763 pcxe_write(tty, 0, &c, 1);
764 return;
768 static int pcxe_write_room(struct tty_struct *tty)
770 struct channel *ch;
771 int remain;
773 remain = 0;
774 if ((ch=chan(tty))!=NULL) {
775 volatile struct board_chan *bc;
776 unsigned int head, tail;
777 unsigned long flags;
779 save_flags(flags);
780 cli();
781 globalwinon(ch);
783 bc = ch->brdchan;
784 head = bc->tin & (ch->txbufsize - 1);
785 tail = bc->tout;
786 if (tail != bc->tout)
787 tail = bc->tout;
788 tail &= (ch->txbufsize - 1);
790 if((remain = tail - head - 1) < 0 )
791 remain += ch->txbufsize;
793 if (remain && (ch->statusflags & LOWWAIT) == 0) {
794 ch->statusflags |= LOWWAIT;
795 bc->ilow = 1;
797 memoff(ch);
798 restore_flags(flags);
801 return remain;
805 static int pcxe_chars_in_buffer(struct tty_struct *tty)
807 int chars;
808 unsigned int ctail, head, tail;
809 int remain;
810 unsigned long flags;
811 struct channel *ch;
812 volatile struct board_chan *bc;
814 if ((ch=chan(tty))==NULL)
815 return(0);
817 save_flags(flags);
818 cli();
819 globalwinon(ch);
821 bc = ch->brdchan;
822 tail = bc->tout;
823 head = bc->tin;
824 ctail = ch->mailbox->cout;
825 if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
826 chars = 0;
827 else {
828 head = bc->tin & (ch->txbufsize - 1);
829 tail &= (ch->txbufsize - 1);
830 if((remain = tail - head - 1) < 0 )
831 remain += ch->txbufsize;
833 chars = (int)(ch->txbufsize - remain);
836 * Make it possible to wakeup anything waiting for output
837 * in tty_ioctl.c, etc.
839 if(!(ch->statusflags & EMPTYWAIT))
840 setup_empty_event(tty,ch);
843 memoff(ch);
844 restore_flags(flags);
846 return(chars);
850 static void pcxe_flush_buffer(struct tty_struct *tty)
852 unsigned int tail;
853 volatile struct board_chan *bc;
854 struct channel *ch;
855 unsigned long flags;
857 if ((ch=chan(tty))==NULL)
858 return;
860 save_flags(flags);
861 cli();
863 globalwinon(ch);
864 bc = ch->brdchan;
865 tail = bc->tout;
866 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
868 memoff(ch);
869 restore_flags(flags);
871 wake_up_interruptible(&tty->write_wait);
872 if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
873 (tty->ldisc.write_wakeup)(tty);
876 static void pcxe_flush_chars(struct tty_struct *tty)
878 struct channel * ch;
880 if ((ch=chan(tty))!=NULL) {
881 unsigned long flags;
883 save_flags(flags);
884 cli();
885 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
886 setup_empty_event(tty,ch);
887 restore_flags(flags);
891 #ifndef MODULE
894 * Driver setup function when linked into the kernel to optionally parse multible
895 * "digi="-lines and initialize the driver at boot time. No probing.
897 void __init pcxx_setup(char *str, int *ints)
900 struct board_info board;
901 int i, j, last;
902 char *temp, *t2;
903 unsigned len;
905 numcards=0;
907 memset(&board, 0, sizeof(board));
909 for(last=0,i=1;i<=ints[0];i++)
910 switch(i)
912 case 1:
913 board.status = ints[i];
914 last = i;
915 break;
917 case 2:
918 board.type = ints[i];
919 last = i;
920 break;
922 case 3:
923 board.altpin = ints[i];
924 last = i;
925 break;
927 case 4:
928 board.numports = ints[i];
929 last = i;
930 break;
932 case 5:
933 board.port = ints[i];
934 last = i;
935 break;
937 case 6:
938 board.membase = ints[i];
939 last = i;
940 break;
942 default:
943 printk("PC/Xx: Too many integer parms\n");
944 return;
947 while (str && *str)
949 /* find the next comma or terminator */
950 temp = str;
951 while (*temp && (*temp != ','))
952 temp++;
954 if (!*temp)
955 temp = NULL;
956 else
957 *temp++ = 0;
959 i = last + 1;
961 switch(i)
963 case 1:
964 len = strlen(str);
965 if (strncmp("Disable", str, len) == 0)
966 board.status = 0;
967 else
968 if (strncmp("Enable", str, len) == 0)
969 board.status = 1;
970 else
972 printk("PC/Xx: Invalid status %s\n", str);
973 return;
975 last = i;
976 break;
978 case 2:
979 for(j=0;j<PCXX_NUM_TYPES;j++)
980 if (strcmp(board_desc[j], str) == 0)
981 break;
983 if (i<PCXX_NUM_TYPES)
984 board.type = j;
985 else
987 printk("PC/Xx: Invalid board name: %s\n", str);
988 return;
990 last = i;
991 break;
993 case 3:
994 len = strlen(str);
995 if (strncmp("Disable", str, len) == 0)
996 board.altpin = 0;
997 else
998 if (strncmp("Enable", str, len) == 0)
999 board.altpin = 1;
1000 else
1002 printk("PC/Xx: Invalid altpin %s\n", str);
1003 return;
1005 last = i;
1006 break;
1008 case 4:
1009 t2 = str;
1010 while (isdigit(*t2))
1011 t2++;
1013 if (*t2)
1015 printk("PC/Xx: Invalid port count %s\n", str);
1016 return;
1019 board.numports = simple_strtoul(str, NULL, 0);
1020 last = i;
1021 break;
1023 case 5:
1024 t2 = str;
1025 while (isxdigit(*t2))
1026 t2++;
1028 if (*t2)
1030 printk("PC/Xx: Invalid io port address %s\n", str);
1031 return;
1034 board.port = simple_strtoul(str, NULL, 16);
1035 last = i;
1036 break;
1038 case 6:
1039 t2 = str;
1040 while (isxdigit(*t2))
1041 t2++;
1043 if (*t2)
1045 printk("PC/Xx: Invalid memory base %s\n", str);
1046 return;
1049 board.membase = simple_strtoul(str, NULL, 16);
1050 last = i;
1051 break;
1053 default:
1054 printk("PC/Xx: Too many string parms\n");
1055 return;
1057 str = temp;
1060 if (last < 6)
1062 printk("PC/Xx: Insufficient parms specified\n");
1063 return;
1066 /* I should REALLY validate the stuff here */
1068 memcpy(&boards[numcards],&board, sizeof(board));
1069 printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n",
1070 numcards, board_desc[board.type], board_mem[board.type],
1071 board.numports, board.port, (unsigned int) board.membase);
1073 /* keep track of my initial minor number */
1074 if (numcards)
1075 boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
1076 else
1077 boards[numcards].first_minor = 0;
1079 /* yeha! string parameter was successful! */
1080 numcards++;
1082 #endif
1085 * function to initialize the driver with the given parameters, which are either
1086 * the default values from this file or the parameters given at boot.
1088 int __init pcxe_init(void)
1090 ulong memory_seg=0, memory_size=0;
1091 int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
1092 unchar *fepos, *memaddr, *bios, v;
1093 volatile struct global_data *gd;
1094 volatile struct board_chan *bc;
1095 struct board_info *bd;
1096 struct channel *ch;
1098 printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
1100 #ifdef MODULE
1101 for (i = 0; i < 4; i++) {
1102 if (io[i]) {
1103 numcards = 0;
1104 break;
1107 if (numcards == 0) {
1108 int first_minor = 0;
1110 for (i = 0; i < 4; i++) {
1111 if (io[i] == 0) {
1112 boards[i].port = 0;
1113 boards[i].status = DISABLED;
1115 else {
1116 boards[i].port = (ushort)io[i];
1117 boards[i].status = ENABLED;
1118 boards[i].first_minor = first_minor;
1119 numcards=i+1;
1121 if (membase[i])
1122 boards[i].membase = (ulong)membase[i];
1123 else
1124 boards[i].membase = 0xD0000;
1126 if (memsize[i])
1127 boards[i].memsize = (ulong)(memsize[i] * 1024);
1128 else
1129 boards[i].memsize = 0;
1131 if (altpin[i])
1132 boards[i].altpin = ON;
1133 else
1134 boards[i].altpin = OFF;
1136 if (numports[i])
1137 boards[i].numports = (ushort)numports[i];
1138 else
1139 boards[i].numports = 16;
1141 first_minor += boards[i].numports;
1144 #endif
1146 if (numcards <= 0)
1148 printk("PC/Xx: No cards configured, driver not active.\n");
1149 return -EIO;
1151 #if 1
1152 if (debug)
1153 for (i = 0; i < numcards; i++) {
1154 printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
1155 i+1,
1156 boards[i].status,
1157 boards[i].port,
1158 boards[i].membase,
1159 boards[i].memsize,
1160 boards[i].altpin,
1161 boards[i].numports,
1162 boards[i].first_minor);
1164 #endif
1166 for (i=0;i<numcards;i++)
1167 nbdevs += boards[i].numports;
1169 if (nbdevs <= 0)
1171 printk("PC/Xx: No devices activated, driver not active.\n");
1172 return -EIO;
1176 * this turns out to be more memory efficient, as there are no
1177 * unused spaces.
1179 digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
1180 if (!digi_channels)
1181 panic("Unable to allocate digi_channel struct");
1182 memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
1184 pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
1185 if (!pcxe_table)
1186 panic("Unable to allocate pcxe_table struct");
1187 memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs);
1189 pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
1190 if (!pcxe_termios)
1191 panic("Unable to allocate pcxe_termios struct");
1192 memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs);
1194 pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
1195 if (!pcxe_termios_locked)
1196 panic("Unable to allocate pcxe_termios_locked struct");
1197 memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs);
1199 init_bh(DIGI_BH,do_pcxe_bh);
1200 enable_bh(DIGI_BH);
1202 timer_table[DIGI_TIMER].fn = pcxxpoll;
1203 timer_table[DIGI_TIMER].expires = 0;
1205 memset(&pcxe_driver, 0, sizeof(struct tty_driver));
1206 pcxe_driver.magic = TTY_DRIVER_MAGIC;
1207 pcxe_driver.name = "ttyD";
1208 pcxe_driver.major = DIGI_MAJOR;
1209 pcxe_driver.minor_start = 0;
1211 pcxe_driver.num = nbdevs;
1213 pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
1214 pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
1215 pcxe_driver.init_termios = tty_std_termios;
1216 pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1217 pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
1218 pcxe_driver.refcount = &pcxe_refcount;
1220 pcxe_driver.table = pcxe_table;
1221 pcxe_driver.termios = pcxe_termios;
1222 pcxe_driver.termios_locked = pcxe_termios_locked;
1224 pcxe_driver.open = pcxe_open;
1225 pcxe_driver.close = pcxe_close;
1226 pcxe_driver.write = pcxe_write;
1227 pcxe_driver.put_char = pcxe_put_char;
1228 pcxe_driver.flush_chars = pcxe_flush_chars;
1229 pcxe_driver.write_room = pcxe_write_room;
1230 pcxe_driver.chars_in_buffer = pcxe_chars_in_buffer;
1231 pcxe_driver.flush_buffer = pcxe_flush_buffer;
1232 pcxe_driver.ioctl = pcxe_ioctl;
1233 pcxe_driver.throttle = pcxe_throttle;
1234 pcxe_driver.unthrottle = pcxe_unthrottle;
1235 pcxe_driver.set_termios = pcxe_set_termios;
1236 pcxe_driver.stop = pcxe_stop;
1237 pcxe_driver.start = pcxe_start;
1238 pcxe_driver.hangup = pcxe_hangup;
1240 pcxe_callout = pcxe_driver;
1241 pcxe_callout.name = "cud";
1242 pcxe_callout.major = DIGICU_MAJOR;
1243 pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
1244 pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1246 for(crd=0; crd < numcards; crd++) {
1247 bd = &boards[crd];
1248 outb(FEPRST, bd->port);
1249 pcxxdelay(1);
1251 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
1252 if(i > 100) {
1253 printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
1254 bd->port);
1255 bd->status = DISABLED;
1256 break;
1258 #ifdef MODULE
1259 schedule();
1260 #endif
1261 pcxxdelay(10);
1263 if(bd->status == DISABLED)
1264 continue;
1266 v = inb(bd->port);
1268 if((v & 0x1) == 0x1) {
1269 if((v & 0x30) == 0) { /* PC/Xi 64K card */
1270 memory_seg = 0xf000;
1271 memory_size = 0x10000;
1274 if((v & 0x30) == 0x10) { /* PC/Xi 128K card */
1275 memory_seg = 0xe000;
1276 memory_size = 0x20000;
1279 if((v & 0x30) == 0x20) { /* PC/Xi 256K card */
1280 memory_seg = 0xc000;
1281 memory_size = 0x40000;
1284 if((v & 0x30) == 0x30) { /* PC/Xi 512K card */
1285 memory_seg = 0x8000;
1286 memory_size = 0x80000;
1288 bd->type = PCXI;
1289 } else {
1290 if((v & 0x1) == 0x1) {
1291 bd->status = DISABLED; /* PC/Xm unsupported card */
1292 printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
1293 continue;
1294 } else {
1295 if(v & 0xC0) {
1296 topwin = 0x1f00L;
1297 outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
1298 outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
1299 bd->type = PCXEVE; /* PC/Xe 8K card */
1300 } else {
1301 bd->type = PCXE; /* PC/Xe 64K card */
1304 memory_seg = 0xf000;
1305 memory_size = 0x10000;
1308 if (verbose)
1309 printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
1310 crd+1, board_desc[bd->type], memory_size/1024,
1311 bd->port,bd->membase,bd->membase+memory_size-1);
1313 if (boards[crd].memsize == 0)
1314 boards[crd].memsize = memory_size;
1315 else
1316 if (boards[crd].memsize != memory_size) {
1317 printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
1318 boards[crd].memsize, boards[crd].memsize / 1024,
1319 memory_size, memory_size / 1024);
1320 continue;
1323 memaddr = (unchar *)phys_to_virt(bd->membase);
1325 if (verbose)
1326 printk("Resetting board and testing memory access:");
1328 outb(FEPRST|FEPMEM, bd->port);
1330 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
1331 if(i > 1000) {
1332 printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
1333 board_desc[bd->type], bd->port);
1334 bd->status = DISABLED;
1335 break;
1337 #ifdef MODULE
1338 schedule();
1339 #endif
1340 pcxxdelay(1);
1342 if(bd->status == DISABLED)
1343 continue;
1345 memwinon(bd,0);
1346 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
1347 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
1349 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
1350 *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
1351 printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
1352 bd->membase, board_desc[bd->type], bd->port);
1353 bd->status = DISABLED;
1354 continue;
1356 if (verbose)
1357 printk(" done.\n");
1359 for(i=0; i < 16; i++) {
1360 memaddr[MISCGLOBAL+i] = 0;
1363 if(bd->type == PCXI || bd->type == PCXE) {
1364 bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
1366 if (verbose)
1367 printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
1369 memcpy(bios, pcxx_bios, pcxx_nbios);
1371 if (verbose)
1372 printk(" done.\n");
1374 outb(FEPMEM, bd->port);
1376 if (verbose)
1377 printk("Waiting for BIOS to become ready");
1379 for(i=1; i <= 30; i++) {
1380 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1381 goto load_fep;
1383 if (verbose) {
1384 printk(".");
1385 if (i % 50 == 0)
1386 printk("\n");
1388 #ifdef MODULE
1389 schedule();
1390 #endif
1391 pcxxdelay(50);
1394 printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
1395 bd->port, bd->membase, bd->membase+bd->memsize);
1396 bd->status = DISABLED;
1397 continue;
1400 if(bd->type == PCXEVE) {
1401 bios = memaddr + (BIOSCODE & 0x1fff);
1402 memwinon(bd,0xff);
1404 memcpy(bios, pcxx_bios, pcxx_nbios);
1406 outb(FEPCLR, bd->port);
1407 memwinon(bd,0);
1409 for(i=0; i <= 1000; i++) {
1410 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1411 goto load_fep;
1413 if (verbose) {
1414 printk(".");
1415 if (i % 50 == 0)
1416 printk("\n");
1418 #ifdef MODULE
1419 schedule();
1420 #endif
1421 pcxxdelay(10);
1424 printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
1425 board_desc[bd->type], bd->port);
1426 bd->status = DISABLED;
1427 continue;
1430 load_fep:
1431 fepos = memaddr + FEPCODE;
1432 if(bd->type == PCXEVE)
1433 fepos = memaddr + (FEPCODE & 0x1fff);
1435 if (verbose)
1436 printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
1438 memwinon(bd, (FEPCODE >> 13));
1439 memcpy(fepos, pcxx_cook, pcxx_ncook);
1440 memwinon(bd, 0);
1442 if (verbose)
1443 printk(" done.\n");
1445 *(ushort *)((ulong)memaddr + MBOX + 0) = 2;
1446 *(ushort *)((ulong)memaddr + MBOX + 2) = memory_seg + FEPCODESEG;
1447 *(ushort *)((ulong)memaddr + MBOX + 4) = 0;
1448 *(ushort *)((ulong)memaddr + MBOX + 6) = FEPCODESEG;
1449 *(ushort *)((ulong)memaddr + MBOX + 8) = 0;
1450 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
1452 outb(FEPMEM|FEPINT, bd->port);
1453 outb(FEPMEM, bd->port);
1455 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
1456 if(i > 2000) {
1457 printk("PC/Xx: Command failed for the %s at 0x%x!\n",
1458 board_desc[bd->type], bd->port);
1459 bd->status = DISABLED;
1460 break;
1462 #ifdef MODULE
1463 schedule();
1464 #endif
1465 pcxxdelay(1);
1468 if(bd->status == DISABLED)
1469 continue;
1471 if (verbose)
1472 printk("Waiting for FEP/OS to become ready");
1474 *(ushort *)(memaddr + FEPSTAT) = 0;
1475 *(ushort *)(memaddr + MBOX + 0) = 1;
1476 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
1477 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
1479 outb(FEPINT, bd->port);
1480 outb(FEPCLR, bd->port);
1481 memwinon(bd, 0);
1483 for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
1484 if(i > 1000) {
1485 printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
1486 board_desc[bd->type], bd->port);
1487 bd->status = DISABLED;
1488 break;
1490 if (verbose) {
1491 printk(".");
1492 if (i % 50 == 0)
1493 printk("\n%5d",i/50);
1495 #ifdef MODULE
1496 schedule();
1497 #endif
1498 pcxxdelay(1);
1500 if(bd->status == DISABLED)
1501 continue;
1503 if (verbose)
1504 printk(" ok.\n");
1506 ch = digi_channels+bd->first_minor;
1507 pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
1509 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1510 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1512 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1513 shrinkmem = 1;
1515 request_region(bd->port, 4, "PC/Xx");
1517 for(i=0; i < bd->numports; i++, ch++, bc++) {
1518 if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1519 ch->brdchan = 0;
1520 continue;
1522 ch->brdchan = bc;
1523 ch->mailbox = gd;
1524 ch->tqueue.routine = do_softint;
1525 ch->tqueue.data = ch;
1526 ch->board = &boards[crd];
1527 #ifdef DEFAULT_HW_FLOW
1528 ch->digiext.digi_flags = RTSPACE|CTSPACE;
1529 #endif
1530 if(boards[crd].altpin) {
1531 ch->dsr = CD;
1532 ch->dcd = DSR;
1533 ch->digiext.digi_flags |= DIGI_ALTPIN;
1534 } else {
1535 ch->dcd = CD;
1536 ch->dsr = DSR;
1539 ch->magic = PCXX_MAGIC;
1540 ch->boardnum = crd;
1541 ch->channelnum = i;
1543 ch->dev = bd->first_minor + i;
1544 ch->tty = 0;
1546 if(shrinkmem) {
1547 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1548 shrinkmem = 0;
1551 if(bd->type != PCXEVE) {
1552 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1553 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1554 ch->txwin = ch->rxwin = 0;
1555 } else {
1556 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1557 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1558 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1559 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1562 ch->txbufsize = bc->tmax + 1;
1563 ch->rxbufsize = bc->rmax + 1;
1564 ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1565 lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1566 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1567 fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1568 fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1570 bc->edelay = 100;
1571 bc->idata = 1;
1573 ch->startc = bc->startc;
1574 ch->stopc = bc->stopc;
1575 ch->startca = bc->startca;
1576 ch->stopca = bc->stopca;
1578 ch->fepcflag = 0;
1579 ch->fepiflag = 0;
1580 ch->fepoflag = 0;
1581 ch->fepstartc = 0;
1582 ch->fepstopc = 0;
1583 ch->fepstartca = 0;
1584 ch->fepstopca = 0;
1586 ch->close_delay = 50;
1587 ch->count = 0;
1588 ch->blocked_open = 0;
1589 ch->callout_termios = pcxe_callout.init_termios;
1590 ch->normal_termios = pcxe_driver.init_termios;
1591 ch->open_wait = 0;
1592 ch->close_wait = 0;
1593 ch->asyncflags = 0;
1596 if (verbose)
1597 printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
1598 crd+1, board_desc[bd->type], board_mem[bd->type], bd->port,
1599 bd->membase, bd->numports);
1600 else
1601 printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
1602 board_desc[bd->type], board_mem[bd->type], bd->port,
1603 bd->membase, bd->numports);
1605 memwinoff(bd, 0);
1606 enabled_cards++;
1609 if (enabled_cards <= 0) {
1610 printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
1611 return -EIO;
1614 if(tty_register_driver(&pcxe_driver))
1615 panic("Couldn't register PC/Xe driver");
1617 if(tty_register_driver(&pcxe_callout))
1618 panic("Couldn't register PC/Xe callout");
1621 * Start up the poller to check for events on all enabled boards
1623 timer_active |= 1 << DIGI_TIMER;
1625 if (verbose)
1626 printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
1628 return 0;
1632 static void pcxxpoll(void)
1634 unsigned long flags;
1635 int crd;
1636 volatile unsigned int head, tail;
1637 struct channel *ch;
1638 struct board_info *bd;
1640 save_flags(flags);
1641 cli();
1643 for(crd=0; crd < numcards; crd++) {
1644 bd = &boards[crd];
1646 ch = digi_channels+bd->first_minor;
1648 if(bd->status == DISABLED)
1649 continue;
1651 assertmemoff(ch);
1653 globalwinon(ch);
1654 head = ch->mailbox->ein;
1655 tail = ch->mailbox->eout;
1657 if(head != tail)
1658 doevent(crd);
1660 memoff(ch);
1663 timer_table[DIGI_TIMER].fn = pcxxpoll;
1664 timer_table[DIGI_TIMER].expires = jiffies + HZ/25;
1665 timer_active |= 1 << DIGI_TIMER;
1666 restore_flags(flags);
1669 static void doevent(int crd)
1671 volatile struct board_info *bd;
1672 static struct tty_struct *tty;
1673 volatile struct board_chan *bc;
1674 volatile unchar *eventbuf;
1675 volatile unsigned int head;
1676 volatile unsigned int tail;
1677 struct channel *ch;
1678 struct channel *chan0;
1679 int channel, event, mstat, lstat;
1681 bd = &boards[crd];
1683 chan0 = digi_channels+bd->first_minor;
1684 pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
1687 assertgwinon(chan0);
1689 while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1690 assertgwinon(chan0);
1691 eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
1692 channel = eventbuf[0];
1693 event = eventbuf[1];
1694 mstat = eventbuf[2];
1695 lstat = eventbuf[3];
1697 ch=chan0+channel;
1699 if ((unsigned)channel >= bd->numports || !ch) {
1700 printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1701 printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1702 crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1703 if(channel >= bd->numports)
1704 ch = chan0;
1705 bc = ch->brdchan;
1706 goto next;
1708 if ((bc = ch->brdchan) == NULL)
1709 goto next;
1711 if (event & DATA_IND) {
1712 receive_data(ch);
1713 assertgwinon(ch);
1716 if (event & MODEMCHG_IND) {
1717 ch->imodem = mstat;
1718 if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) {
1719 if (ch->asyncflags & ASYNC_CHECK_CD) {
1720 if (mstat & ch->dcd) {
1721 wake_up_interruptible(&ch->open_wait);
1722 } else {
1723 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1729 tty = ch->tty;
1731 if (tty) {
1733 if (event & BREAK_IND) {
1734 tty->flip.count++;
1735 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1736 *tty->flip.char_buf_ptr++ = 0;
1737 #if 0
1738 if (ch->asyncflags & ASYNC_SAK)
1739 do_SAK(tty);
1740 #endif
1741 tty_schedule_flip(tty);
1744 if (event & LOWTX_IND) {
1745 if (ch->statusflags & LOWWAIT) {
1746 ch->statusflags &= ~LOWWAIT;
1747 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1748 tty->ldisc.write_wakeup)
1749 (tty->ldisc.write_wakeup)(tty);
1750 wake_up_interruptible(&tty->write_wait);
1754 if (event & EMPTYTX_IND) {
1755 ch->statusflags &= ~TXBUSY;
1756 if (ch->statusflags & EMPTYWAIT) {
1757 ch->statusflags &= ~EMPTYWAIT;
1758 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1759 tty->ldisc.write_wakeup)
1760 (tty->ldisc.write_wakeup)(tty);
1761 wake_up_interruptible(&tty->write_wait);
1766 next:
1767 globalwinon(ch);
1768 if(!bc) printk("bc == NULL in doevent!\n");
1769 else bc->idata = 1;
1771 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1772 globalwinon(chan0);
1779 * pcxxdelay - delays a specified number of milliseconds
1781 static void pcxxdelay(int msec)
1783 while(msec-- > 0)
1784 __delay(loops_per_sec/1000);
1788 static void
1789 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
1790 int bytecmd)
1792 unchar *memaddr;
1793 unsigned int head, tail;
1794 long count;
1795 int n;
1797 if(ch->board->status == DISABLED)
1798 return;
1800 assertgwinon(ch);
1802 memaddr = (unchar *)phys_to_virt(ch->board->membase);
1803 head = ch->mailbox->cin;
1805 if(head >= (CMAX-CSTART) || (head & 03)) {
1806 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1807 return;
1810 if(bytecmd) {
1811 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1813 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1815 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1816 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1817 } else {
1818 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1820 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1821 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1824 head = (head+4) & (CMAX-CSTART-4);
1825 ch->mailbox->cin = head;
1827 count = FEPTIMEOUT;
1829 while(1) {
1830 count--;
1831 if(count == 0) {
1832 printk("Fep not responding in fepcmd()\n");
1833 return;
1836 head = ch->mailbox->cin;
1837 tail = ch->mailbox->cout;
1839 n = (head-tail) & (CMAX-CSTART-4);
1841 if(n <= ncmds * (sizeof(short)*4))
1842 break;
1843 /* Seems not to be good here: schedule(); */
1848 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
1850 unsigned res = 0;
1851 #ifdef SPEED_HACK
1852 /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
1853 if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
1854 if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
1855 #endif
1856 if (cflag & CBAUDEX)
1858 ch->digiext.digi_flags |= DIGI_FAST;
1859 res |= FEP_HUPCL;
1860 /* This gets strange but if we don't do this we will get 78600
1861 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
1862 * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
1863 * do 115K
1865 if (cflag & B115200) res|=1;
1867 else ch->digiext.digi_flags &= ~DIGI_FAST;
1868 res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
1869 return res;
1872 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
1874 unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1876 if(ch->digiext.digi_flags & DIGI_AIXON)
1877 res |= IAIXON;
1878 return res;
1881 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
1883 unsigned res = 0;
1885 if(cflag & CRTSCTS) {
1886 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1887 res |= (CTS | RTS);
1889 if(ch->digiext.digi_flags & RTSPACE)
1890 res |= RTS;
1891 if(ch->digiext.digi_flags & DTRPACE)
1892 res |= DTR;
1893 if(ch->digiext.digi_flags & CTSPACE)
1894 res |= CTS;
1895 if(ch->digiext.digi_flags & DSRPACE)
1896 res |= ch->dsr;
1897 if(ch->digiext.digi_flags & DCDPACE)
1898 res |= ch->dcd;
1900 if (res & RTS)
1901 ch->digiext.digi_flags |= RTSPACE;
1902 if (res & CTS)
1903 ch->digiext.digi_flags |= CTSPACE;
1905 return res;
1908 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
1910 volatile struct board_chan *bc;
1911 unsigned int head;
1912 unsigned mval, hflow, cflag, iflag;
1913 struct termios *ts;
1915 bc = ch->brdchan;
1916 assertgwinon(ch);
1917 ts = tty->termios;
1919 if((ts->c_cflag & CBAUD) == 0) {
1920 head = bc->rin;
1921 bc->rout = head;
1922 head = bc->tin;
1923 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1924 mval = 0;
1925 } else {
1927 cflag = termios2digi_c(ch, ts->c_cflag);
1929 if(cflag != ch->fepcflag) {
1930 ch->fepcflag = cflag;
1931 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1934 if(cflag & CLOCAL)
1935 ch->asyncflags &= ~ASYNC_CHECK_CD;
1936 else {
1937 ch->asyncflags |= ASYNC_CHECK_CD;
1940 mval = DTR | RTS;
1943 iflag = termios2digi_i(ch, ts->c_iflag);
1945 if(iflag != ch->fepiflag) {
1946 ch->fepiflag = iflag;
1947 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1950 bc->mint = ch->dcd;
1951 if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1952 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1953 bc->mint = 0;
1955 ch->imodem = bc->mstat;
1957 hflow = termios2digi_h(ch, ts->c_cflag);
1959 if(hflow != ch->hflow) {
1960 ch->hflow = hflow;
1961 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1964 /* mval ^= ch->modemfake & (mval ^ ch->modem); */
1966 if(ch->omodem != mval) {
1967 ch->omodem = mval;
1968 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1971 if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1972 ch->fepstartc = ch->startc;
1973 ch->fepstopc = ch->stopc;
1974 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1977 if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1978 ch->fepstartca = ch->startca;
1979 ch->fepstopca = ch->stopca;
1980 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1985 static void receive_data(struct channel *ch)
1987 volatile struct board_chan *bc;
1988 struct tty_struct *tty;
1989 unsigned int tail, head, wrapmask;
1990 int n;
1991 int piece;
1992 struct termios *ts=0;
1993 unchar *rptr;
1994 int rc;
1995 int wrapgap;
1997 globalwinon(ch);
1999 if (ch->statusflags & RXSTOPPED)
2000 return;
2002 tty = ch->tty;
2003 if(tty)
2004 ts = tty->termios;
2006 bc = ch->brdchan;
2008 if(!bc) {
2009 printk("bc is NULL in receive_data!\n");
2010 return;
2013 wrapmask = ch->rxbufsize - 1;
2015 head = bc->rin;
2016 head &= wrapmask;
2017 tail = bc->rout & wrapmask;
2019 n = (head-tail) & wrapmask;
2021 if(n == 0)
2022 return;
2025 * If CREAD bit is off or device not open, set TX tail to head
2027 if(!tty || !ts || !(ts->c_cflag & CREAD)) {
2028 bc->rout = head;
2029 return;
2032 if(tty->flip.count == TTY_FLIPBUF_SIZE) {
2033 /* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
2034 return;
2037 if(bc->orun) {
2038 bc->orun = 0;
2039 printk("overrun! DigiBoard device minor=%d\n",MINOR(tty->device));
2042 rxwinon(ch);
2043 rptr = tty->flip.char_buf_ptr;
2044 rc = tty->flip.count;
2045 while(n > 0) {
2046 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
2047 piece = (wrapgap < n) ? wrapgap : n;
2050 * Make sure we don't overflow the buffer
2053 if ((rc + piece) > TTY_FLIPBUF_SIZE)
2054 piece = TTY_FLIPBUF_SIZE - rc;
2056 if (piece == 0)
2057 break;
2059 memcpy(rptr, ch->rxptr + tail, piece);
2060 rptr += piece;
2061 rc += piece;
2062 tail = (tail + piece) & wrapmask;
2063 n -= piece;
2065 tty->flip.count = rc;
2066 tty->flip.char_buf_ptr = rptr;
2067 globalwinon(ch);
2068 bc->rout = tail;
2070 /* Must be called with global data */
2071 tty_schedule_flip(ch->tty);
2072 return;
2076 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
2077 unsigned int cmd, unsigned long arg)
2079 int error;
2080 struct channel *ch = (struct channel *) tty->driver_data;
2081 volatile struct board_chan *bc;
2082 int retval;
2083 unsigned int mflag, mstat;
2084 unsigned char startc, stopc;
2085 unsigned long flags;
2086 digiflow_t dflow;
2088 if(ch)
2089 bc = ch->brdchan;
2090 else {
2091 printk("ch is NULL in pcxe_ioctl!\n");
2092 return(-EINVAL);
2095 save_flags(flags);
2097 switch(cmd) {
2098 case TCSBRK: /* SVID version: non-zero arg --> no break */
2099 retval = tty_check_change(tty);
2100 if(retval)
2101 return retval;
2102 setup_empty_event(tty,ch);
2103 tty_wait_until_sent(tty, 0);
2104 if(!arg)
2105 digi_send_break(ch, HZ/4); /* 1/4 second */
2106 return 0;
2108 case TCSBRKP: /* support for POSIX tcsendbreak() */
2109 retval = tty_check_change(tty);
2110 if(retval)
2111 return retval;
2112 setup_empty_event(tty,ch);
2113 tty_wait_until_sent(tty, 0);
2114 digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
2115 return 0;
2117 case TIOCGSOFTCAR:
2118 return put_user(C_CLOCAL(tty) ? 1 : 0,
2119 (unsigned int *) arg);
2121 case TIOCSSOFTCAR:
2123 unsigned int value;
2124 error = get_user( value, (unsigned int *) arg);
2125 if (error)
2126 return error;
2127 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
2129 return 0;
2131 case TIOCMODG:
2132 case TIOCMGET:
2133 mflag = 0;
2135 cli();
2136 globalwinon(ch);
2137 mstat = bc->mstat;
2138 memoff(ch);
2139 restore_flags(flags);
2141 if(mstat & DTR)
2142 mflag |= TIOCM_DTR;
2143 if(mstat & RTS)
2144 mflag |= TIOCM_RTS;
2145 if(mstat & CTS)
2146 mflag |= TIOCM_CTS;
2147 if(mstat & ch->dsr)
2148 mflag |= TIOCM_DSR;
2149 if(mstat & RI)
2150 mflag |= TIOCM_RI;
2151 if(mstat & ch->dcd)
2152 mflag |= TIOCM_CD;
2154 error = put_user(mflag, (unsigned int *) arg);
2155 if(error)
2156 return error;
2157 break;
2159 case TIOCMBIS:
2160 case TIOCMBIC:
2161 case TIOCMODS:
2162 case TIOCMSET:
2163 error = get_user(mstat, (unsigned int *) arg);
2164 if(error)
2165 return error;
2167 mflag = 0;
2168 if(mstat & TIOCM_DTR)
2169 mflag |= DTR;
2170 if(mstat & TIOCM_RTS)
2171 mflag |= RTS;
2173 switch(cmd) {
2174 case TIOCMODS:
2175 case TIOCMSET:
2176 ch->modemfake = DTR|RTS;
2177 ch->modem = mflag;
2178 break;
2180 case TIOCMBIS:
2181 ch->modemfake |= mflag;
2182 ch->modem |= mflag;
2183 break;
2185 case TIOCMBIC:
2186 ch->modemfake &= ~mflag;
2187 ch->modem &= ~mflag;
2188 break;
2191 cli();
2192 globalwinon(ch);
2193 pcxxparam(tty,ch);
2194 memoff(ch);
2195 restore_flags(flags);
2196 break;
2198 case TIOCSDTR:
2199 cli();
2200 ch->omodem |= DTR;
2201 globalwinon(ch);
2202 fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
2203 memoff(ch);
2204 restore_flags(flags);
2205 break;
2207 case TIOCCDTR:
2208 ch->omodem &= ~DTR;
2209 cli();
2210 globalwinon(ch);
2211 fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
2212 memoff(ch);
2213 restore_flags(flags);
2214 break;
2216 case DIGI_GETA:
2217 if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
2218 return(error);
2220 copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));
2221 break;
2223 case DIGI_SETAW:
2224 case DIGI_SETAF:
2225 if(cmd == DIGI_SETAW) {
2226 setup_empty_event(tty,ch);
2227 tty_wait_until_sent(tty, 0);
2229 else {
2230 if(tty->ldisc.flush_buffer)
2231 tty->ldisc.flush_buffer(tty);
2234 /* Fall Thru */
2236 case DIGI_SETA:
2237 if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
2238 return(error);
2240 copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));
2241 #ifdef DEBUG_IOCTL
2242 printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
2243 #endif
2245 if(ch->digiext.digi_flags & DIGI_ALTPIN) {
2246 ch->dcd = DSR;
2247 ch->dsr = CD;
2248 } else {
2249 ch->dcd = CD;
2250 ch->dsr = DSR;
2253 cli();
2254 globalwinon(ch);
2255 pcxxparam(tty,ch);
2256 memoff(ch);
2257 restore_flags(flags);
2258 break;
2260 case DIGI_GETFLOW:
2261 case DIGI_GETAFLOW:
2262 cli();
2263 globalwinon(ch);
2264 if(cmd == DIGI_GETFLOW) {
2265 dflow.startc = bc->startc;
2266 dflow.stopc = bc->stopc;
2267 } else {
2268 dflow.startc = bc->startca;
2269 dflow.stopc = bc->stopca;
2271 memoff(ch);
2272 restore_flags(flags);
2274 if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
2275 return(error);
2277 copy_to_user((char*)arg, &dflow, sizeof(dflow));
2278 break;
2280 case DIGI_SETAFLOW:
2281 case DIGI_SETFLOW:
2282 if(cmd == DIGI_SETFLOW) {
2283 startc = ch->startc;
2284 stopc = ch->stopc;
2285 } else {
2286 startc = ch->startca;
2287 stopc = ch->stopca;
2290 if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
2291 return(error);
2293 copy_from_user(&dflow, (char*)arg, sizeof(dflow));
2295 if(dflow.startc != startc || dflow.stopc != stopc) {
2296 cli();
2297 globalwinon(ch);
2299 if(cmd == DIGI_SETFLOW) {
2300 ch->fepstartc = ch->startc = dflow.startc;
2301 ch->fepstopc = ch->stopc = dflow.stopc;
2302 fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
2303 } else {
2304 ch->fepstartca = ch->startca = dflow.startc;
2305 ch->fepstopca = ch->stopca = dflow.stopc;
2306 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
2309 if(ch->statusflags & TXSTOPPED)
2310 pcxe_start(tty);
2312 memoff(ch);
2313 restore_flags(flags);
2315 break;
2317 default:
2318 return -ENOIOCTLCMD;
2321 return 0;
2324 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
2326 struct channel *info;
2328 if ((info=chan(tty))!=NULL) {
2329 unsigned long flags;
2330 save_flags(flags);
2331 cli();
2332 globalwinon(info);
2333 pcxxparam(tty,info);
2334 memoff(info);
2336 if ((old_termios->c_cflag & CRTSCTS) &&
2337 ((tty->termios->c_cflag & CRTSCTS) == 0))
2338 tty->hw_stopped = 0;
2339 if(!(old_termios->c_cflag & CLOCAL) &&
2340 (tty->termios->c_cflag & CLOCAL))
2341 wake_up_interruptible(&info->open_wait);
2342 restore_flags(flags);
2347 static void do_pcxe_bh(void)
2349 run_task_queue(&tq_pcxx);
2353 static void do_softint(void *private_)
2355 struct channel *info = (struct channel *) private_;
2357 if(info && info->magic == PCXX_MAGIC) {
2358 struct tty_struct *tty = info->tty;
2359 if (tty && tty->driver_data) {
2360 if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
2361 tty_hangup(tty);
2362 wake_up_interruptible(&info->open_wait);
2363 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
2370 static void pcxe_stop(struct tty_struct *tty)
2372 struct channel *info;
2374 if ((info=chan(tty))!=NULL) {
2375 unsigned long flags;
2376 save_flags(flags);
2377 cli();
2378 if ((info->statusflags & TXSTOPPED) == 0) {
2379 globalwinon(info);
2380 fepcmd(info, PAUSETX, 0, 0, 0, 0);
2381 info->statusflags |= TXSTOPPED;
2382 memoff(info);
2384 restore_flags(flags);
2388 static void pcxe_throttle(struct tty_struct * tty)
2390 struct channel *info;
2392 if ((info=chan(tty))!=NULL) {
2393 unsigned long flags;
2394 save_flags(flags);
2395 cli();
2396 if ((info->statusflags & RXSTOPPED) == 0) {
2397 globalwinon(info);
2398 fepcmd(info, PAUSERX, 0, 0, 0, 0);
2399 info->statusflags |= RXSTOPPED;
2400 memoff(info);
2402 restore_flags(flags);
2406 static void pcxe_unthrottle(struct tty_struct *tty)
2408 struct channel *info;
2410 if ((info=chan(tty)) != NULL) {
2411 unsigned long flags;
2413 /* Just in case output was resumed because of a change in Digi-flow */
2414 save_flags(flags);
2415 cli();
2416 if(info->statusflags & RXSTOPPED) {
2417 volatile struct board_chan *bc;
2418 globalwinon(info);
2419 bc = info->brdchan;
2420 fepcmd(info, RESUMERX, 0, 0, 0, 0);
2421 info->statusflags &= ~RXSTOPPED;
2422 memoff(info);
2424 restore_flags(flags);
2429 static void pcxe_start(struct tty_struct *tty)
2431 struct channel *info;
2433 if ((info=chan(tty))!=NULL) {
2434 unsigned long flags;
2436 save_flags(flags);
2437 cli();
2438 /* Just in case output was resumed because of a change in Digi-flow */
2439 if(info->statusflags & TXSTOPPED) {
2440 volatile struct board_chan *bc;
2441 globalwinon(info);
2442 bc = info->brdchan;
2443 if(info->statusflags & LOWWAIT)
2444 bc->ilow = 1;
2445 fepcmd(info, RESUMETX, 0, 0, 0, 0);
2446 info->statusflags &= ~TXSTOPPED;
2447 memoff(info);
2449 restore_flags(flags);
2454 void digi_send_break(struct channel *ch, int msec)
2456 unsigned long flags;
2458 save_flags(flags);
2459 cli();
2460 globalwinon(ch);
2463 * Maybe I should send an infinite break here, schedule() for
2464 * msec amount of time, and then stop the break. This way,
2465 * the user can't screw up the FEP by causing digi_send_break()
2466 * to be called (i.e. via an ioctl()) more than once in msec amount
2467 * of time. Try this for now...
2470 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2471 memoff(ch);
2473 restore_flags(flags);
2476 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
2478 volatile struct board_chan *bc;
2479 unsigned long flags;
2481 save_flags(flags);
2482 cli();
2483 globalwinon(ch);
2484 ch->statusflags |= EMPTYWAIT;
2485 bc = ch->brdchan;
2486 bc->iempty = 1;
2487 memoff(ch);
2488 restore_flags(flags);