2 * linux/drivers/char/pcxx.c
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 General 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 (christoph@lameter.com)
17 * Please contact digi for support issues at digilnux@dgii.com.
18 * Some more information can be found at
19 * http://lameter.com/digi.
21 * 1.5.2 Fall 1995 Bug fixes by David Nugent
22 * 1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory
23 * allocation harmonized with 1.3.X Series.
24 * 1.5.4 March 30, 1996 Christoph Lameter: Fixup for 1.3.81. Use init_bh
25 * instead of direct assignment to kernel arrays.
26 * 1.5.5 April 5, 1996 Major device numbers corrected.
27 * Mike McLagan<mike.mclagan@linux.org>: Add setup
28 * variable handling, instead of using the old pcxxconfig.h
29 * 1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup.
30 * Call out devices changed to /dev/cudxx.
31 * 1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing.
32 * David Nugent: Bug in pcxe_open.
33 * Brian J. Murrell: Modem Control fixes, Majors correctly assigned
34 * 1.6.1 April 6, 1997 Bernhard Kaindl: fixed virtual memory access for 2.1
35 * i386-kernels and use on other archtitectures, Allowing use
36 * as module, added module parameters, added switch to enable
37 * verbose messages to assist user during card configuration.
38 * Currently only tested on a PC/Xi card, but should work on Xe
40 * 1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
41 * get rid of panics, release previously allocated resources
42 * 1.6.3 August, 23, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
43 * cleaned up wrt verify_area.
44 * Christoph Lameter: Update documentation, email addresses
45 * and URLs. Remove some obsolete code.
49 #include <linux/module.h>
51 #include <linux/ioport.h>
52 #include <linux/errno.h>
53 #include <linux/signal.h>
54 #include <linux/sched.h>
55 #include <linux/timer.h>
56 #include <linux/interrupt.h>
57 #include <linux/tty.h>
58 #include <linux/tty_flip.h>
59 #include <linux/major.h>
60 #include <linux/string.h>
61 #include <linux/fcntl.h>
62 #include <linux/ptrace.h>
63 #include <linux/delay.h>
64 #include <linux/serial.h>
65 #include <linux/tty_driver.h>
66 #include <linux/slab.h>
67 #include <linux/init.h>
70 #include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
73 #include <asm/system.h>
75 #include <asm/uaccess.h>
76 #include <asm/bitops.h>
77 #include <asm/semaphore.h>
79 #define VERSION "1.6.3"
85 #include "digi_bios.h"
88 * Define one default setting if no digi= config line is used.
89 * Default is altpin = disabled, 16 ports, I/O 200h, Memory 0D0000h
91 static struct board_info boards[MAX_DIGI_BOARDS] = { {
92 /* Board is enabled */ ENABLED,
93 /* Type is auto-detected */ 0,
94 /* altping is disabled */ DISABLED,
95 /* number of ports = 16 */ 16,
96 /* io address is 0x200 */ 0x200,
97 /* card memory at 0xd0000 */ 0xd0000,
98 /* first minor device no. */ 0
101 static int verbose = 0;
102 static int debug = 0;
105 /* Variables for insmod */
106 static int io[] = {0, 0, 0, 0};
107 static int membase[] = {0, 0, 0, 0};
108 static int memsize[] = {0, 0, 0, 0};
109 static int altpin[] = {0, 0, 0, 0};
110 static int numports[] = {0, 0, 0, 0};
112 MODULE_AUTHOR("Bernhard Kaindl");
113 MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
114 MODULE_LICENSE("GPL");
115 MODULE_PARM(verbose, "i");
116 MODULE_PARM(debug, "i");
117 MODULE_PARM(io, "1-4i");
118 MODULE_PARM(membase, "1-4i");
119 MODULE_PARM(memsize, "1-4i");
120 MODULE_PARM(altpin, "1-4i");
121 MODULE_PARM(numports, "1-4i");
125 static int numcards = 1;
126 static int nbdevs = 0;
128 static struct channel *digi_channels;
130 int pcxx_ncook=sizeof(pcxx_cook);
131 int pcxx_nbios=sizeof(pcxx_bios);
133 #define MIN(a,b) ((a) < (b) ? (a) : (b))
134 #define pcxxassert(x, msg) if(!(x)) pcxx_error(__LINE__, msg)
136 #define FEPTIMEOUT 200000
137 #define SERIAL_TYPE_NORMAL 1
138 #define PCXE_EVENT_HANGUP 1
140 static struct tty_driver *pcxe_driver;
142 static struct timer_list pcxx_timer;
144 static void pcxxpoll(unsigned long dummy);
145 static void fepcmd(struct channel *, int, int, int, int, int);
146 static void pcxe_put_char(struct tty_struct *, unsigned char);
147 static void pcxe_flush_chars(struct tty_struct *);
148 static void pcxx_error(int, char *);
149 static void pcxe_close(struct tty_struct *, struct file *);
150 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
151 static void pcxe_set_termios(struct tty_struct *, struct termios *);
152 static int pcxe_write(struct tty_struct *, int, const unsigned char *, int);
153 static int pcxe_write_room(struct tty_struct *);
154 static int pcxe_chars_in_buffer(struct tty_struct *);
155 static void pcxe_flush_buffer(struct tty_struct *);
156 static void doevent(int);
157 static void receive_data(struct channel *);
158 static void pcxxparam(struct tty_struct *, struct channel *ch);
159 static void do_softint(void *);
160 static inline void pcxe_sched_event(struct channel *, int);
161 static void pcxe_start(struct tty_struct *);
162 static void pcxe_stop(struct tty_struct *);
163 static void pcxe_throttle(struct tty_struct *);
164 static void pcxe_unthrottle(struct tty_struct *);
165 static void digi_send_break(struct channel *ch, int msec);
166 static void shutdown(struct channel *);
167 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
168 static inline void memwinon(struct board_info *b, unsigned int win);
169 static inline void memwinoff(struct board_info *b, unsigned int win);
170 static inline void globalwinon(struct channel *ch);
171 static inline void rxwinon(struct channel *ch);
172 static inline void txwinon(struct channel *ch);
173 static inline void memoff(struct channel *ch);
174 static inline void assertgwinon(struct channel *ch);
175 static inline void assertmemoff(struct channel *ch);
176 static int pcxe_tiocmget(struct tty_struct *tty, struct file *file);
177 static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
178 unsigned int set, unsigned int clear);
180 #define TZ_BUFSZ 4096
182 /* function definitions */
184 /*****************************************************************************/
186 static void cleanup_board_resources(void)
189 struct board_info *bd;
192 for(crd = 0; crd < numcards; crd++) {
194 ch = digi_channels + bd->first_minor;
197 release_region(bd->port, 4);
199 for(i = 0; i < bd->numports; i++, ch++)
205 static void __exit pcxe_cleanup(void)
211 printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION);
215 del_timer_sync(&pcxx_timer);
217 if ((e1 = tty_unregister_driver(pcxe_driver)))
218 printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
220 put_tty_driver(pcxe_driver);
221 cleanup_board_resources();
222 kfree(digi_channels);
223 restore_flags(flags);
227 * pcxe_init() is our init_module():
229 module_init(pcxe_init);
230 module_cleanup(pcxe_cleanup);
232 static inline struct channel *chan(register struct tty_struct *tty)
235 register struct channel *ch=(struct channel *)tty->driver_data;
236 if (ch >= digi_channels && ch < digi_channels+nbdevs) {
237 if (ch->magic==PCXX_MAGIC)
244 /* These inline routines are to turn board memory on and off */
245 static inline void memwinon(struct board_info *b, unsigned int win)
247 if(b->type == PCXEVE)
248 outb_p(FEPWIN|win, b->port+1);
250 outb_p(inb(b->port)|FEPMEM, b->port);
253 static inline void memwinoff(struct board_info *b, unsigned int win)
255 outb_p(inb(b->port)&~FEPMEM, b->port);
256 if(b->type == PCXEVE)
257 outb_p(0, b->port + 1);
260 static inline void globalwinon(struct channel *ch)
262 if(ch->board->type == PCXEVE)
263 outb_p(FEPWIN, ch->board->port+1);
265 outb_p(FEPMEM, ch->board->port);
268 static inline void rxwinon(struct channel *ch)
271 outb_p(FEPMEM, ch->board->port);
273 outb_p(ch->rxwin, ch->board->port+1);
276 static inline void txwinon(struct channel *ch)
279 outb_p(FEPMEM, ch->board->port);
281 outb_p(ch->txwin, ch->board->port+1);
284 static inline void memoff(struct channel *ch)
286 outb_p(0, ch->board->port);
287 if(ch->board->type == PCXEVE)
288 outb_p(0, ch->board->port+1);
291 static inline void assertgwinon(struct channel *ch)
293 if(ch->board->type != PCXEVE)
294 pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
297 static inline void assertmemoff(struct channel *ch)
299 if(ch->board->type != PCXEVE)
300 pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
303 static inline void pcxe_sched_event(struct channel *info, int event)
305 info->event |= 1 << event;
306 schedule_work(&info->tqueue);
309 static void pcxx_error(int line, char *msg)
311 printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
314 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
316 DECLARE_WAITQUEUE(wait, current);
320 if (tty->termios->c_cflag & CLOCAL)
324 * Block waiting for the carrier detect and the line to become free
328 add_wait_queue(&info->open_wait, &wait);
330 info->blocked_open++;
335 info->omodem |= DTR|RTS;
336 fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
339 set_current_state(TASK_INTERRUPTIBLE);
340 if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
341 if(info->asyncflags & ASYNC_HUP_NOTIFY)
344 retval = -ERESTARTSYS;
347 if ((info->asyncflags & ASYNC_CLOSING) == 0 &&
348 (do_clocal || (info->imodem & info->dcd)))
350 if(signal_pending(current)) {
351 retval = -ERESTARTSYS;
356 current->state = TASK_RUNNING;
357 remove_wait_queue(&info->open_wait, &wait);
359 if(!tty_hung_up_p(filp))
361 info->blocked_open--;
367 int pcxe_open(struct tty_struct *tty, struct file * filp)
369 volatile struct board_chan *bc;
378 if(line < 0 || line >= nbdevs) {
379 printk("line out of range in pcxe_open\n");
380 tty->driver_data = NULL;
384 for(boardnum=0;boardnum<numcards;boardnum++)
385 if ((line >= boards[boardnum].first_minor) &&
386 (line < boards[boardnum].first_minor + boards[boardnum].numports))
389 if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
390 (line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
391 tty->driver_data = NULL; /* Mark this device as 'down' */
395 ch = digi_channels+line;
397 if(ch->brdchan == 0) {
398 tty->driver_data = NULL;
403 * If the device is in the middle of being closed, then block
404 * until it's done, and then try again.
406 if(ch->asyncflags & ASYNC_CLOSING) {
407 interruptible_sleep_on(&ch->close_wait);
408 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
417 tty->driver_data = ch;
420 if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
426 ch->imodem = bc->mstat;
431 ch->imodem = bc->mstat;
433 ch->omodem = DTR|RTS;
434 fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
436 ch->asyncflags |= ASYNC_INITIALIZED;
438 restore_flags(flags);
440 if(ch->asyncflags & ASYNC_CLOSING) {
441 interruptible_sleep_on(&ch->close_wait);
442 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
448 if (!(filp->f_flags & O_NONBLOCK)) {
449 /* this has to be set in order for the "block until
450 * CD" code to work correctly. i'm not sure under
451 * what circumstances asyncflags should be set to
452 * ASYNC_NORMAL_ACTIVE though
455 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
456 if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
459 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
464 static void shutdown(struct channel *info)
467 volatile struct board_chan *bc;
468 struct tty_struct *tty;
470 if (!(info->asyncflags & ASYNC_INITIALIZED))
484 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
486 if(tty->termios->c_cflag & HUPCL) {
487 info->omodem &= ~(RTS|DTR);
488 fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
492 info->asyncflags &= ~ASYNC_INITIALIZED;
493 restore_flags(flags);
497 static void pcxe_close(struct tty_struct * tty, struct file * filp)
499 struct channel *info;
501 if ((info=chan(tty))!=NULL) {
506 if(tty_hung_up_p(filp)) {
507 /* flag that somebody is done with this module */
508 restore_flags(flags);
511 /* this check is in serial.c, it won't hurt to do it here too */
512 if ((tty->count == 1) && (info->count != 1)) {
514 * Uh, oh. tty->count is 1, which means that the tty
515 * structure will be freed. Info->count should always
516 * be one in these conditions. If it's greater than
517 * one, we've got real problems, since it means the
518 * serial port won't be shutdown.
520 printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
523 if (info->count-- > 1) {
524 restore_flags(flags);
527 if (info->count < 0) {
531 info->asyncflags |= ASYNC_CLOSING;
534 if(info->asyncflags & ASYNC_INITIALIZED) {
535 setup_empty_event(tty,info);
536 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
539 if(tty->driver->flush_buffer)
540 tty->driver->flush_buffer(tty);
541 if(tty->ldisc.flush_buffer)
542 tty->ldisc.flush_buffer(tty);
548 /* ldiscs[] is not available in a MODULE
549 ** worth noting that while I'm not sure what this hunk of code is supposed
550 ** to do, it is not present in the serial.c driver. Hmmm. If you know,
551 ** please send me a note. brian@ilinx.com
552 ** Don't know either what this is supposed to do christoph@lameter.com.
554 if(tty->ldisc.num != ldiscs[N_TTY].num) {
556 (tty->ldisc.close)(tty);
557 tty->ldisc = ldiscs[N_TTY];
558 tty->termios->c_line = N_TTY;
560 (tty->ldisc.open)(tty);
563 if(info->blocked_open) {
564 if(info->close_delay) {
565 current->state = TASK_INTERRUPTIBLE;
566 schedule_timeout(info->close_delay);
568 wake_up_interruptible(&info->open_wait);
570 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
571 wake_up_interruptible(&info->close_wait);
572 restore_flags(flags);
577 void pcxe_hangup(struct tty_struct *tty)
581 if ((ch=chan(tty))!=NULL) {
590 ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
591 wake_up_interruptible(&ch->open_wait);
592 restore_flags(flags);
598 static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
601 volatile struct board_chan *bc;
602 int total, remain, size, stlen;
603 unsigned int head, tail;
605 /* printk("Entering pcxe_write()\n"); */
607 if ((ch=chan(tty))==NULL)
611 size = ch->txbufsize;
615 down(&ch->tmp_buf_sem);
619 head = bc->tin & (size - 1);
620 /* It seems to be necessary to make sure that the value is stable here somehow
621 This is a rather odd pice of code here. */
625 } while (tail != bc->tout);
628 stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
629 count = MIN(stlen, count);
631 restore_flags(flags);
634 if (copy_from_user(ch->tmp_buf, buf, count))
641 * All data is now local
648 head = bc->tin & (size - 1);
650 if (tail != bc->tout)
654 remain = size - (head - tail) - 1;
658 remain = tail - head - 1;
661 count = MIN(remain, count);
665 stlen = MIN(count, stlen);
666 memcpy(ch->txptr + head, buf, stlen);
676 ch->statusflags |= TXBUSY;
679 if ((ch->statusflags & LOWWAIT) == 0) {
680 ch->statusflags |= LOWWAIT;
684 restore_flags(flags);
687 up(&ch->tmp_buf_sem);
693 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
695 pcxe_write(tty, 0, &c, 1);
700 static int pcxe_write_room(struct tty_struct *tty)
706 if ((ch=chan(tty))!=NULL) {
707 volatile struct board_chan *bc;
708 unsigned int head, tail;
716 head = bc->tin & (ch->txbufsize - 1);
718 if (tail != bc->tout)
720 tail &= (ch->txbufsize - 1);
722 if((remain = tail - head - 1) < 0 )
723 remain += ch->txbufsize;
725 if (remain && (ch->statusflags & LOWWAIT) == 0) {
726 ch->statusflags |= LOWWAIT;
730 restore_flags(flags);
737 static int pcxe_chars_in_buffer(struct tty_struct *tty)
740 unsigned int ctail, head, tail;
744 volatile struct board_chan *bc;
746 if ((ch=chan(tty))==NULL)
756 ctail = ch->mailbox->cout;
757 if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
760 head = bc->tin & (ch->txbufsize - 1);
761 tail &= (ch->txbufsize - 1);
762 if((remain = tail - head - 1) < 0 )
763 remain += ch->txbufsize;
765 chars = (int)(ch->txbufsize - remain);
768 * Make it possible to wakeup anything waiting for output
769 * in tty_ioctl.c, etc.
771 if(!(ch->statusflags & EMPTYWAIT))
772 setup_empty_event(tty,ch);
776 restore_flags(flags);
782 static void pcxe_flush_buffer(struct tty_struct *tty)
785 volatile struct board_chan *bc;
789 if ((ch=chan(tty))==NULL)
798 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
801 restore_flags(flags);
803 wake_up_interruptible(&tty->write_wait);
804 if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
805 (tty->ldisc.write_wakeup)(tty);
808 static void pcxe_flush_chars(struct tty_struct *tty)
812 if ((ch=chan(tty))!=NULL) {
817 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
818 setup_empty_event(tty,ch);
819 restore_flags(flags);
826 * Driver setup function when linked into the kernel to optionally parse multible
827 * "digi="-lines and initialize the driver at boot time. No probing.
829 void __init pcxx_setup(char *str, int *ints)
832 struct board_info board;
839 memset(&board, 0, sizeof(board));
841 for(last=0,i=1;i<=ints[0];i++)
845 board.status = ints[i];
850 board.type = ints[i];
855 board.altpin = ints[i];
860 board.numports = ints[i];
865 board.port = ints[i];
870 board.membase = ints[i];
875 printk("PC/Xx: Too many integer parms\n");
881 /* find the next comma or terminator */
883 while (*temp && (*temp != ','))
897 if (strncmp("Disable", str, len) == 0)
900 if (strncmp("Enable", str, len) == 0)
904 printk("PC/Xx: Invalid status %s\n", str);
911 for(j=0;j<PCXX_NUM_TYPES;j++)
912 if (strcmp(board_desc[j], str) == 0)
915 if (i<PCXX_NUM_TYPES)
919 printk("PC/Xx: Invalid board name: %s\n", str);
927 if (strncmp("Disable", str, len) == 0)
930 if (strncmp("Enable", str, len) == 0)
934 printk("PC/Xx: Invalid altpin %s\n", str);
947 printk("PC/Xx: Invalid port count %s\n", str);
951 board.numports = simple_strtoul(str, NULL, 0);
957 while (isxdigit(*t2))
962 printk("PC/Xx: Invalid io port address %s\n", str);
966 board.port = simple_strtoul(str, NULL, 16);
972 while (isxdigit(*t2))
977 printk("PC/Xx: Invalid memory base %s\n", str);
981 board.membase = simple_strtoul(str, NULL, 16);
986 printk("PC/Xx: Too many string parms\n");
994 printk("PC/Xx: Insufficient parms specified\n");
998 /* I should REALLY validate the stuff here */
1000 memcpy(&boards[numcards],&board, sizeof(board));
1001 printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n",
1002 numcards, board_desc[board.type], board_mem[board.type],
1003 board.numports, board.port, (unsigned int) board.membase);
1005 /* keep track of my initial minor number */
1007 boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
1009 boards[numcards].first_minor = 0;
1011 /* yeha! string parameter was successful! */
1016 module_init(pcxe_init)
1017 module_exit(pcxe_exit)
1019 static struct tty_operations pcxe_ops = {
1021 .close = pcxe_close,
1022 .write = pcxe_write,
1023 .put_char = pcxe_put_char,
1024 .flush_chars = pcxe_flush_chars,
1025 .write_room = pcxe_write_room,
1026 .chars_in_buffer = pcxe_chars_in_buffer,
1027 .flush_buffer = pcxe_flush_buffer,
1028 .ioctl = pcxe_ioctl,
1029 .throttle = pcxe_throttle,
1030 .unthrottle = pcxe_unthrottle,
1031 .set_termios = pcxe_set_termios,
1033 .start = pcxe_start,
1034 .hangup = pcxe_hangup,
1035 .tiocmget = pcxe_tiocmget,
1036 .tiocmset = pcxe_tiocmset,
1040 * function to initialize the driver with the given parameters, which are either
1041 * the default values from this file or the parameters given at boot.
1043 static int __init pcxe_init(void)
1045 ulong memory_seg=0, memory_size=0;
1046 int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
1048 unchar *fepos, *memaddr, *bios, v;
1049 volatile struct global_data *gd;
1050 volatile struct board_chan *bc;
1051 struct board_info *bd;
1054 printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
1057 for (i = 0; i < MAX_DIGI_BOARDS; i++) {
1063 if (numcards == 0) {
1064 int first_minor = 0;
1066 for (i = 0; i < MAX_DIGI_BOARDS; i++) {
1069 boards[i].status = DISABLED;
1072 boards[i].port = (ushort)io[i];
1073 boards[i].status = ENABLED;
1074 boards[i].first_minor = first_minor;
1078 boards[i].membase = (ulong)membase[i];
1080 boards[i].membase = 0xD0000;
1083 boards[i].memsize = (ulong)(memsize[i] * 1024);
1085 boards[i].memsize = 0;
1088 boards[i].altpin = ON;
1090 boards[i].altpin = OFF;
1093 boards[i].numports = (ushort)numports[i];
1095 boards[i].numports = 16;
1097 boards[i].region = NULL;
1098 first_minor += boards[i].numports;
1105 printk("PC/Xx: No cards configured, driver not active.\n");
1110 for (i = 0; i < numcards; i++) {
1111 printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
1119 boards[i].first_minor);
1123 for (i=0;i<numcards;i++)
1124 nbdevs += boards[i].numports;
1128 printk("PC/Xx: No devices activated, driver not active.\n");
1132 pcxe_driver = alloc_tty_driver(nbdevs);
1137 * this turns out to be more memory efficient, as there are no
1140 digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
1141 if (!digi_channels) {
1142 printk(KERN_ERR "Unable to allocate digi_channel struct\n");
1143 put_tty_driver(pcxe_driver);
1146 memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
1148 init_timer(&pcxx_timer);
1149 pcxx_timer.function = pcxxpoll;
1151 pcxe_driver->owner = THIS_MODULE;
1152 pcxe_driver->name = "ttyD";
1153 pcxe_driver->devfs_name = "pcxe/";
1154 pcxe_driver->major = DIGI_MAJOR;
1155 pcxe_driver->minor_start = 0;
1156 pcxe_driver->type = TTY_DRIVER_TYPE_SERIAL;
1157 pcxe_driver->subtype = SERIAL_TYPE_NORMAL;
1158 pcxe_driver->init_termios = tty_std_termios;
1159 pcxe_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1160 pcxe_driver->flags = TTY_DRIVER_REAL_RAW;
1161 tty_set_operations(pcxe_driver, &pcxe_ops);
1163 for(crd=0; crd < numcards; crd++) {
1165 outb(FEPRST, bd->port);
1168 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
1170 printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
1172 bd->status = DISABLED;
1180 if(bd->status == DISABLED)
1185 if((v & 0x1) == 0x1) {
1186 if((v & 0x30) == 0) { /* PC/Xi 64K card */
1187 memory_seg = 0xf000;
1188 memory_size = 0x10000;
1191 if((v & 0x30) == 0x10) { /* PC/Xi 128K card */
1192 memory_seg = 0xe000;
1193 memory_size = 0x20000;
1196 if((v & 0x30) == 0x20) { /* PC/Xi 256K card */
1197 memory_seg = 0xc000;
1198 memory_size = 0x40000;
1201 if((v & 0x30) == 0x30) { /* PC/Xi 512K card */
1202 memory_seg = 0x8000;
1203 memory_size = 0x80000;
1207 if((v & 0x1) == 0x1) {
1208 bd->status = DISABLED; /* PC/Xm unsupported card */
1209 printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
1214 outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
1215 outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
1216 bd->type = PCXEVE; /* PC/Xe 8K card */
1218 bd->type = PCXE; /* PC/Xe 64K card */
1221 memory_seg = 0xf000;
1222 memory_size = 0x10000;
1226 printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
1227 crd+1, board_desc[bd->type], memory_size/1024,
1228 bd->port,bd->membase,bd->membase+memory_size-1);
1230 if (boards[crd].memsize == 0)
1231 boards[crd].memsize = memory_size;
1233 if (boards[crd].memsize != memory_size) {
1234 printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
1235 boards[crd].memsize, boards[crd].memsize / 1024,
1236 memory_size, memory_size / 1024);
1240 memaddr = (unchar *)phys_to_virt(bd->membase);
1243 printk("Resetting board and testing memory access:");
1245 outb(FEPRST|FEPMEM, bd->port);
1247 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
1249 printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
1250 board_desc[bd->type], bd->port);
1251 bd->status = DISABLED;
1259 if(bd->status == DISABLED)
1263 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
1264 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
1266 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
1267 *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
1268 printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
1269 bd->membase, board_desc[bd->type], bd->port);
1270 bd->status = DISABLED;
1276 for(i=0; i < 16; i++) {
1277 memaddr[MISCGLOBAL+i] = 0;
1280 if(bd->type == PCXI || bd->type == PCXE) {
1281 bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
1284 printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
1286 memcpy(bios, pcxx_bios, pcxx_nbios);
1291 outb(FEPMEM, bd->port);
1294 printk("Waiting for BIOS to become ready");
1296 for(i=1; i <= 30; i++) {
1297 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1311 printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
1312 bd->port, bd->membase, bd->membase+bd->memsize);
1313 bd->status = DISABLED;
1317 if(bd->type == PCXEVE) {
1318 bios = memaddr + (BIOSCODE & 0x1fff);
1321 memcpy(bios, pcxx_bios, pcxx_nbios);
1323 outb(FEPCLR, bd->port);
1326 for(i=0; i <= 1000; i++) {
1327 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1341 printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
1342 board_desc[bd->type], bd->port);
1343 bd->status = DISABLED;
1348 fepos = memaddr + FEPCODE;
1349 if(bd->type == PCXEVE)
1350 fepos = memaddr + (FEPCODE & 0x1fff);
1353 printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
1355 memwinon(bd, (FEPCODE >> 13));
1356 memcpy(fepos, pcxx_cook, pcxx_ncook);
1362 *(ushort *)((ulong)memaddr + MBOX + 0) = 2;
1363 *(ushort *)((ulong)memaddr + MBOX + 2) = memory_seg + FEPCODESEG;
1364 *(ushort *)((ulong)memaddr + MBOX + 4) = 0;
1365 *(ushort *)((ulong)memaddr + MBOX + 6) = FEPCODESEG;
1366 *(ushort *)((ulong)memaddr + MBOX + 8) = 0;
1367 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
1369 outb(FEPMEM|FEPINT, bd->port);
1370 outb(FEPMEM, bd->port);
1372 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
1374 printk("PC/Xx: Command failed for the %s at 0x%x!\n",
1375 board_desc[bd->type], bd->port);
1376 bd->status = DISABLED;
1385 if(bd->status == DISABLED)
1389 printk("Waiting for FEP/OS to become ready");
1391 *(ushort *)(memaddr + FEPSTAT) = 0;
1392 *(ushort *)(memaddr + MBOX + 0) = 1;
1393 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
1394 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
1396 outb(FEPINT, bd->port);
1397 outb(FEPCLR, bd->port);
1400 for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
1402 printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
1403 board_desc[bd->type], bd->port);
1404 bd->status = DISABLED;
1410 printk("\n%5d",i/50);
1417 if(bd->status == DISABLED)
1423 ch = digi_channels+bd->first_minor;
1424 pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
1426 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1427 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1429 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1432 bd->region = request_region(bd->port, 4, "PC/Xx");
1435 printk(KERN_ERR "I/O port 0x%x is already used\n", bd->port);
1437 goto cleanup_boards;
1440 for(i=0; i < bd->numports; i++, ch++, bc++) {
1441 if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1447 INIT_WORK(&ch->tqueue, do_softint, ch);
1448 ch->board = &boards[crd];
1449 #ifdef DEFAULT_HW_FLOW
1450 ch->digiext.digi_flags = RTSPACE|CTSPACE;
1452 if(boards[crd].altpin) {
1455 ch->digiext.digi_flags |= DIGI_ALTPIN;
1461 ch->magic = PCXX_MAGIC;
1465 ch->dev = bd->first_minor + i;
1469 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1473 if(bd->type != PCXEVE) {
1474 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1475 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1476 ch->txwin = ch->rxwin = 0;
1478 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1479 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1480 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1481 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1484 ch->txbufsize = bc->tmax + 1;
1485 ch->rxbufsize = bc->rmax + 1;
1486 ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1487 init_MUTEX(&ch->tmp_buf_sem);
1490 printk(KERN_ERR "Unable to allocate memory for temp buffers\n");
1491 goto cleanup_boards;
1494 lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1495 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1496 fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1497 fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1502 ch->startc = bc->startc;
1503 ch->stopc = bc->stopc;
1504 ch->startca = bc->startca;
1505 ch->stopca = bc->stopca;
1515 ch->close_delay = 50;
1517 ch->blocked_open = 0;
1518 init_waitqueue_head(&ch->open_wait);
1519 init_waitqueue_head(&ch->close_wait);
1524 printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
1525 crd+1, board_desc[bd->type], board_mem[bd->type], bd->port,
1526 bd->membase, bd->numports);
1528 printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
1529 board_desc[bd->type], board_mem[bd->type], bd->port,
1530 bd->membase, bd->numports);
1536 if (enabled_cards <= 0) {
1537 printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
1539 goto cleanup_boards;
1542 ret = tty_register_driver(pcxe_driver);
1544 printk(KERN_ERR "Couldn't register PC/Xe driver\n");
1545 goto cleanup_boards;
1549 * Start up the poller to check for events on all enabled boards
1551 mod_timer(&pcxx_timer, HZ/25);
1554 printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
1558 cleanup_board_resources();
1559 kfree(digi_channels);
1560 put_tty_driver(pcxe_driver);
1565 static void pcxxpoll(unsigned long dummy)
1567 unsigned long flags;
1569 volatile unsigned int head, tail;
1571 struct board_info *bd;
1576 for(crd=0; crd < numcards; crd++) {
1579 ch = digi_channels+bd->first_minor;
1581 if(bd->status == DISABLED)
1587 head = ch->mailbox->ein;
1588 tail = ch->mailbox->eout;
1596 mod_timer(&pcxx_timer, jiffies + HZ/25);
1597 restore_flags(flags);
1600 static void doevent(int crd)
1602 volatile struct board_info *bd;
1603 static struct tty_struct *tty;
1604 volatile struct board_chan *bc;
1605 volatile unchar *eventbuf;
1606 volatile unsigned int head;
1607 volatile unsigned int tail;
1609 struct channel *chan0;
1610 int channel, event, mstat, lstat;
1614 chan0 = digi_channels+bd->first_minor;
1615 pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
1618 assertgwinon(chan0);
1620 while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1621 assertgwinon(chan0);
1622 eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
1623 channel = eventbuf[0];
1624 event = eventbuf[1];
1625 mstat = eventbuf[2];
1626 lstat = eventbuf[3];
1630 if ((unsigned)channel >= bd->numports || !ch) {
1631 printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1632 printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1633 crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1634 if(channel >= bd->numports)
1639 if ((bc = ch->brdchan) == NULL)
1642 if (event & DATA_IND) {
1647 if (event & MODEMCHG_IND) {
1649 if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) {
1650 if (ch->asyncflags & ASYNC_CHECK_CD) {
1651 if (mstat & ch->dcd) {
1652 wake_up_interruptible(&ch->open_wait);
1654 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1664 if (event & BREAK_IND) {
1666 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1667 *tty->flip.char_buf_ptr++ = 0;
1669 if (ch->asyncflags & ASYNC_SAK)
1672 tty_schedule_flip(tty);
1675 if (event & LOWTX_IND) {
1676 if (ch->statusflags & LOWWAIT) {
1677 ch->statusflags &= ~LOWWAIT;
1678 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1679 tty->ldisc.write_wakeup)
1680 (tty->ldisc.write_wakeup)(tty);
1681 wake_up_interruptible(&tty->write_wait);
1685 if (event & EMPTYTX_IND) {
1686 ch->statusflags &= ~TXBUSY;
1687 if (ch->statusflags & EMPTYWAIT) {
1688 ch->statusflags &= ~EMPTYWAIT;
1689 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1690 tty->ldisc.write_wakeup)
1691 (tty->ldisc.write_wakeup)(tty);
1692 wake_up_interruptible(&tty->write_wait);
1699 if(!bc) printk("bc == NULL in doevent!\n");
1702 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1710 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
1714 unsigned int head, tail;
1718 if(ch->board->status == DISABLED)
1723 memaddr = (unchar *)phys_to_virt(ch->board->membase);
1724 head = ch->mailbox->cin;
1726 if(head >= (CMAX-CSTART) || (head & 03)) {
1727 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1732 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1734 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1736 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1737 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1739 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1741 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1742 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1745 head = (head+4) & (CMAX-CSTART-4);
1746 ch->mailbox->cin = head;
1753 printk("Fep not responding in fepcmd()\n");
1757 head = ch->mailbox->cin;
1758 tail = ch->mailbox->cout;
1760 n = (head-tail) & (CMAX-CSTART-4);
1762 if(n <= ncmds * (sizeof(short)*4))
1764 /* Seems not to be good here: schedule(); */
1769 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
1772 if (cflag & CBAUDEX)
1774 ch->digiext.digi_flags |= DIGI_FAST;
1776 /* This gets strange but if we don't do this we will get 78600
1777 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
1778 * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
1781 if (cflag & B115200) res|=1;
1783 else ch->digiext.digi_flags &= ~DIGI_FAST;
1784 res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
1788 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
1790 unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1792 if(ch->digiext.digi_flags & DIGI_AIXON)
1797 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
1801 if(cflag & CRTSCTS) {
1802 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1805 if(ch->digiext.digi_flags & RTSPACE)
1807 if(ch->digiext.digi_flags & DTRPACE)
1809 if(ch->digiext.digi_flags & CTSPACE)
1811 if(ch->digiext.digi_flags & DSRPACE)
1813 if(ch->digiext.digi_flags & DCDPACE)
1817 ch->digiext.digi_flags |= RTSPACE;
1819 ch->digiext.digi_flags |= CTSPACE;
1824 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
1826 volatile struct board_chan *bc;
1828 unsigned mval, hflow, cflag, iflag;
1835 if((ts->c_cflag & CBAUD) == 0) {
1839 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1843 cflag = termios2digi_c(ch, ts->c_cflag);
1845 if(cflag != ch->fepcflag) {
1846 ch->fepcflag = cflag;
1847 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1851 ch->asyncflags &= ~ASYNC_CHECK_CD;
1853 ch->asyncflags |= ASYNC_CHECK_CD;
1859 iflag = termios2digi_i(ch, ts->c_iflag);
1861 if(iflag != ch->fepiflag) {
1862 ch->fepiflag = iflag;
1863 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1867 if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1868 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1871 ch->imodem = bc->mstat;
1873 hflow = termios2digi_h(ch, ts->c_cflag);
1875 if(hflow != ch->hflow) {
1877 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1880 /* mval ^= ch->modemfake & (mval ^ ch->modem); */
1882 if(ch->omodem != mval) {
1884 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1887 if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1888 ch->fepstartc = ch->startc;
1889 ch->fepstopc = ch->stopc;
1890 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1893 if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1894 ch->fepstartca = ch->startca;
1895 ch->fepstopca = ch->stopca;
1896 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1901 static void receive_data(struct channel *ch)
1903 volatile struct board_chan *bc;
1904 struct tty_struct *tty;
1905 unsigned int tail, head, wrapmask;
1908 struct termios *ts=0;
1915 if (ch->statusflags & RXSTOPPED)
1925 printk("bc is NULL in receive_data!\n");
1929 wrapmask = ch->rxbufsize - 1;
1933 tail = bc->rout & wrapmask;
1935 n = (head-tail) & wrapmask;
1941 * If CREAD bit is off or device not open, set TX tail to head
1943 if(!tty || !ts || !(ts->c_cflag & CREAD)) {
1948 if(tty->flip.count == TTY_FLIPBUF_SIZE) {
1949 /* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
1955 printk("overrun! DigiBoard device %s\n", tty->name);
1959 rptr = tty->flip.char_buf_ptr;
1960 rc = tty->flip.count;
1962 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
1963 piece = (wrapgap < n) ? wrapgap : n;
1966 * Make sure we don't overflow the buffer
1969 if ((rc + piece) > TTY_FLIPBUF_SIZE)
1970 piece = TTY_FLIPBUF_SIZE - rc;
1975 memcpy(rptr, ch->rxptr + tail, piece);
1978 tail = (tail + piece) & wrapmask;
1981 tty->flip.count = rc;
1982 tty->flip.char_buf_ptr = rptr;
1986 /* Must be called with global data */
1987 tty_schedule_flip(ch->tty);
1992 static int pcxe_tiocmget(struct tty_struct *tty, struct file *file)
1994 struct channel *ch = (struct channel *) tty->driver_data;
1995 volatile struct board_chan *bc;
1996 unsigned long flags;
2002 printk("ch is NULL in %s!\n", __FUNCTION__);
2011 restore_flags(flags);
2030 static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
2031 unsigned int set, unsigned int clear)
2033 struct channel *ch = (struct channel *) tty->driver_data;
2034 volatile struct board_chan *bc;
2035 unsigned long flags;
2040 printk("ch is NULL in %s!\n", __FUNCTION__);
2047 * I think this modemfake stuff is broken. It doesn't
2048 * correctly reflect the behaviour desired by the TIOCM*
2049 * ioctls. Therefore this is probably broken.
2051 if (set & TIOCM_DTR) {
2052 ch->modemfake |= DTR;
2055 if (set & TIOCM_RTS) {
2056 ch->modemfake |= RTS;
2060 if (clear & TIOCM_DTR) {
2061 ch->modemfake |= DTR;
2064 if (clear & TIOCM_RTS) {
2065 ch->modemfake |= RTS;
2071 restore_flags(flags);
2075 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
2076 unsigned int cmd, unsigned long arg)
2078 struct channel *ch = (struct channel *) tty->driver_data;
2079 volatile struct board_chan *bc;
2081 unsigned int mflag, mstat;
2082 unsigned char startc, stopc;
2083 unsigned long flags;
2089 printk("ch is NULL in pcxe_ioctl!\n");
2096 case TCSBRK: /* SVID version: non-zero arg --> no break */
2097 retval = tty_check_change(tty);
2100 setup_empty_event(tty,ch);
2101 tty_wait_until_sent(tty, 0);
2103 digi_send_break(ch, HZ/4); /* 1/4 second */
2106 case TCSBRKP: /* support for POSIX tcsendbreak() */
2107 retval = tty_check_change(tty);
2110 setup_empty_event(tty,ch);
2111 tty_wait_until_sent(tty, 0);
2112 digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
2116 return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *)arg);
2121 if (get_user(value, (unsigned int *) arg))
2123 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
2128 mflag = pcxe_tiocmget(tty, file);
2129 if (put_user(mflag, (unsigned int *) arg))
2134 if (get_user(mstat, (unsigned int *) arg))
2136 return pcxe_tiocmset(tty, file, mstat, ~mstat);
2142 fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
2144 restore_flags(flags);
2151 fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
2153 restore_flags(flags);
2157 if (copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)))
2163 if(cmd == DIGI_SETAW) {
2164 setup_empty_event(tty,ch);
2165 tty_wait_until_sent(tty, 0);
2168 if(tty->ldisc.flush_buffer)
2169 tty->ldisc.flush_buffer(tty);
2175 if (copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)))
2178 printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
2181 if(ch->digiext.digi_flags & DIGI_ALTPIN) {
2193 restore_flags(flags);
2200 if(cmd == DIGI_GETFLOW) {
2201 dflow.startc = bc->startc;
2202 dflow.stopc = bc->stopc;
2204 dflow.startc = bc->startca;
2205 dflow.stopc = bc->stopca;
2208 restore_flags(flags);
2210 if (copy_to_user((char*)arg, &dflow, sizeof(dflow)))
2216 if(cmd == DIGI_SETFLOW) {
2217 startc = ch->startc;
2220 startc = ch->startca;
2224 if (copy_from_user(&dflow, (char*)arg, sizeof(dflow)))
2227 if(dflow.startc != startc || dflow.stopc != stopc) {
2231 if(cmd == DIGI_SETFLOW) {
2232 ch->fepstartc = ch->startc = dflow.startc;
2233 ch->fepstopc = ch->stopc = dflow.stopc;
2234 fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
2236 ch->fepstartca = ch->startca = dflow.startc;
2237 ch->fepstopca = ch->stopca = dflow.stopc;
2238 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
2241 if(ch->statusflags & TXSTOPPED)
2245 restore_flags(flags);
2250 return -ENOIOCTLCMD;
2256 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
2258 struct channel *info;
2260 if ((info=chan(tty))!=NULL) {
2261 unsigned long flags;
2265 pcxxparam(tty,info);
2268 if ((old_termios->c_cflag & CRTSCTS) &&
2269 ((tty->termios->c_cflag & CRTSCTS) == 0))
2270 tty->hw_stopped = 0;
2271 if(!(old_termios->c_cflag & CLOCAL) &&
2272 (tty->termios->c_cflag & CLOCAL))
2273 wake_up_interruptible(&info->open_wait);
2274 restore_flags(flags);
2280 static void do_softint(void *private_)
2282 struct channel *info = (struct channel *) private_;
2284 if(info && info->magic == PCXX_MAGIC) {
2285 struct tty_struct *tty = info->tty;
2286 if (tty && tty->driver_data) {
2287 if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
2289 wake_up_interruptible(&info->open_wait);
2290 info->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
2297 static void pcxe_stop(struct tty_struct *tty)
2299 struct channel *info;
2301 if ((info=chan(tty))!=NULL) {
2302 unsigned long flags;
2305 if ((info->statusflags & TXSTOPPED) == 0) {
2307 fepcmd(info, PAUSETX, 0, 0, 0, 0);
2308 info->statusflags |= TXSTOPPED;
2311 restore_flags(flags);
2315 static void pcxe_throttle(struct tty_struct * tty)
2317 struct channel *info;
2319 if ((info=chan(tty))!=NULL) {
2320 unsigned long flags;
2323 if ((info->statusflags & RXSTOPPED) == 0) {
2325 fepcmd(info, PAUSERX, 0, 0, 0, 0);
2326 info->statusflags |= RXSTOPPED;
2329 restore_flags(flags);
2333 static void pcxe_unthrottle(struct tty_struct *tty)
2335 struct channel *info;
2337 if ((info=chan(tty)) != NULL) {
2338 unsigned long flags;
2340 /* Just in case output was resumed because of a change in Digi-flow */
2343 if(info->statusflags & RXSTOPPED) {
2344 volatile struct board_chan *bc;
2347 fepcmd(info, RESUMERX, 0, 0, 0, 0);
2348 info->statusflags &= ~RXSTOPPED;
2351 restore_flags(flags);
2356 static void pcxe_start(struct tty_struct *tty)
2358 struct channel *info;
2360 if ((info=chan(tty))!=NULL) {
2361 unsigned long flags;
2365 /* Just in case output was resumed because of a change in Digi-flow */
2366 if(info->statusflags & TXSTOPPED) {
2367 volatile struct board_chan *bc;
2370 if(info->statusflags & LOWWAIT)
2372 fepcmd(info, RESUMETX, 0, 0, 0, 0);
2373 info->statusflags &= ~TXSTOPPED;
2376 restore_flags(flags);
2381 void digi_send_break(struct channel *ch, int msec)
2383 unsigned long flags;
2390 * Maybe I should send an infinite break here, schedule() for
2391 * msec amount of time, and then stop the break. This way,
2392 * the user can't screw up the FEP by causing digi_send_break()
2393 * to be called (i.e. via an ioctl()) more than once in msec amount
2394 * of time. Try this for now...
2397 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2400 restore_flags(flags);
2403 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
2405 volatile struct board_chan *bc;
2406 unsigned long flags;
2411 ch->statusflags |= EMPTYWAIT;
2415 restore_flags(flags);