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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [pcxx.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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