OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [pcxx.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.