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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [isicom.c] - Blame information for rev 1772

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

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 *      This program is free software; you can redistribute it and/or
3
 *      modify it under the terms of the GNU General Public License
4
 *      as published by the Free Software Foundation; either version
5
 *      2 of the License, or (at your option) any later version.
6
 *
7
 *      Original driver code supplied by Multi-Tech
8
 *
9
 *      Changes
10
 *      1/9/98  alan@redhat.com         Merge to 2.0.x kernel tree
11
 *                                      Obtain and use official major/minors
12
 *                                      Loader switched to a misc device
13
 *                                      (fixed range check bug as a side effect)
14
 *                                      Printk clean up
15
 */
16
 
17
/*
18
 *              Currently ISICOM_BH is hard coded to 16 in isicom.h, cannot
19
 *              ask the kernel for a free slot as of 2.0.x - sameer
20
 */
21
 
22
 
23
#include <linux/config.h> 
24
#include <linux/module.h>
25
#include <linux/version.h>
26
#include <linux/kernel.h>
27
#include <linux/tty.h>
28
#include <linux/termios.h>
29
#include <linux/fs.h>
30
#include <linux/sched.h>
31
#include <linux/serial.h>
32
#include <linux/mm.h>
33
#include <linux/miscdevice.h>
34
#include <linux/interrupt.h>
35
#include <linux/timer.h>
36
#include <linux/ioport.h>
37
#include <asm/segment.h>
38
#include <asm/system.h>
39
#include <asm/io.h>
40
#include <linux/isicom.h>
41
 
42
static int isicom_refcount = 0;
43
static int prev_card = 3;       /*      start servicing isi_card[0]     */
44
static struct isi_board * irq_to_board[16] = { NULL, };
45
static struct tty_driver isicom_normal, isicom_callout;
46
static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, };
47
static struct termios * isicom_termios[PORT_COUNT] = { NULL, };
48
static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, };
49
 
50
static struct isi_board isi_card[BOARD_COUNT];
51
static struct isi_port  isi_ports[PORT_COUNT];
52
 
53
DECLARE_TASK_QUEUE(tq_isicom);
54
 
55
static struct timer_list tx;
56
static char re_schedule = 1;
57
#ifdef ISICOM_DEBUG
58
unsigned long tx_count = 0;
59
#endif
60
 
61
static int ISILoad_open(struct inode *inode, struct file *filp);
62
static void ISILoad_release(struct inode *inode, struct file *filp);
63
static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned  int cmd, unsigned long arg);
64
 
65
static void isicom_tx(unsigned long _data);
66
static void isicom_start(struct tty_struct * tty);
67
 
68
static unsigned char * tmp_buf = 0;
69
static struct semaphore tmp_buf_sem = MUTEX;
70
 
71
/*   baud index mappings from linux defns to isi */
72
 
73
static char linuxb_to_isib[] = {
74
        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17,
75
        18, 19
76
};
77
 
78
/*
79
 *  Firmware loader driver specific routines
80
 *
81
 */
82
 
83
static struct file_operations ISILoad_fops = {
84
        NULL,   /*      lseek   */
85
        NULL,   /*      read    */
86
        NULL,   /*      write   */
87
        NULL,   /*      readdir */
88
        NULL,   /*      select  */
89
        ISILoad_ioctl,
90
        NULL,   /*      mmap    */
91
        ISILoad_open,
92
        ISILoad_release,
93
        NULL,   /*      fsync   */
94
        NULL,   /*      fasync  */
95
        NULL,   /*      check_media_change      */
96
        NULL,   /*      revalidate      */
97
};
98
 
99
struct miscdevice isiloader_device = {
100
        ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
101
};
102
 
103
 
104
extern inline int WaitTillCardIsFree(unsigned short base)
105
{
106
        unsigned long count=0;
107
        while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
108
        if (inw(base+0xe)&0x1)
109
                return 0;
110
        else
111
                return 1;
112
}
113
 
114
static int ISILoad_open(struct inode *inode, struct file *filp)
115
{
116
#ifdef ISICOM_DEBUG     
117
        printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n");
118
#endif  
119
        MOD_INC_USE_COUNT;
120
        return 0;
121
}
122
 
123
static void ISILoad_release(struct inode *inode, struct file *filp)
124
{
125
#ifdef ISICOM_DEBUG
126
        printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",);
127
#endif  
128
        MOD_DEC_USE_COUNT;
129
}
130
 
131
static int ISILoad_ioctl(struct inode *inode, struct file *filp,
132
                         unsigned int cmd, unsigned long arg)
133
{
134
        unsigned int card, i, j, signature, status;
135
        unsigned short error, word_count, base;
136
        bin_frame frame;
137
        /* exec_record exec_rec; */
138
 
139
        /*      Added this check to avoid oopses on an ioctl with no
140
         *      args - sameer
141
         */
142
        error=verify_area(VERIFY_READ, (void *) arg, sizeof(int));
143
        if (error)
144
                return error;
145
        card=get_user((int *)arg);
146
        if(card < 0 || card >= BOARD_COUNT)
147
                return -ENXIO;
148
 
149
        base=isi_card[card].base;
150
 
151
        if(base==0)
152
                return -ENXIO;  /* disabled or not used */
153
 
154
        switch(cmd) {
155
                case MIOCTL_RESET_CARD:
156
                        if (!suser())
157
                                return -EPERM;
158
                        error=verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
159
                        if (error)
160
                                return error;
161
 
162
                        printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base);
163
 
164
                        inw(base+0x8);
165
 
166
                        for(i=jiffies+HZ/100;i>jiffies;);
167
 
168
                        outw(0,base+0x8); /* Reset */
169
 
170
                        for(j=1;j<=3;j++) {
171
                                for(i=jiffies+HZ;i>jiffies;);
172
                                printk(".");
173
                        }
174
                        signature=(inw(base+0x4)) & 0xff;
175
 
176
                        if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
177
#ifdef ISICOM_DEBUG                             
178
                                printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
179
#endif                          
180
                                printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
181
                                return -EIO;
182
                        }
183
 
184
                        switch(signature) {
185
                        case    0xa5:
186
                        case    0xbb:
187
                        case    0xdd:   isi_card[card].port_count = 8;
188
                                        isi_card[card].shift_count = 12;
189
                                        break;
190
 
191
                        case    0xcc:   isi_card[card].port_count = 16;
192
                                        isi_card[card].shift_count = 11;
193
                                        break;
194
 
195
                        default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
196
#ifdef ISICOM_DEBUG                     
197
                                 printk("Sig=0x%x\n",signature);
198
#endif                           
199
                                 return -EIO;
200
                        }
201
                        printk("-Done\n");
202
                        put_user(signature,(unsigned int*)arg);
203
                        return 0;
204
 
205
        case    MIOCTL_LOAD_FIRMWARE:
206
                        if (!suser())
207
                                return -EPERM;
208
                        error=verify_area(VERIFY_READ, (void *) arg, sizeof(bin_frame));
209
                        if (error)
210
                                return error;
211
 
212
                        memcpy_fromfs(&frame, (void *) arg, sizeof(bin_frame));
213
 
214
                        if (WaitTillCardIsFree(base))
215
                                return -EIO;
216
 
217
                        outw(0xf0,base);        /* start upload sequence */
218
                        outw(0x00,base);
219
                        outw((frame.addr), base);/*      lsb of adderess    */
220
 
221
                        word_count=(frame.count >> 1) + frame.count % 2;
222
                        outw(word_count, base);
223
                        InterruptTheCard(base);
224
 
225
                        for(i=0;i<=0x2f;i++);    /* a wee bit of delay */
226
 
227
                        if (WaitTillCardIsFree(base))
228
                                return -EIO;
229
 
230
                        if ((status=inw(base+0x4))!=0) {
231
                                printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
232
                                card+1, frame.addr, frame.count, status);
233
                                return -EIO;
234
                        }
235
                        outsw(base, (void *) frame.bin_data, word_count);
236
 
237
                        InterruptTheCard(base);
238
 
239
                        for(i=0;i<=0x0f;i++);    /* another wee bit of delay */
240
 
241
                        if (WaitTillCardIsFree(base))
242
                                return -EIO;
243
 
244
                        if ((status=inw(base+0x4))!=0) {
245
                                printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);
246
                                return -EIO;
247
                        }
248
                        return 0;
249
 
250
        case    MIOCTL_READ_FIRMWARE:
251
                        if (!suser())
252
                                return -EPERM;
253
                        error=verify_area(VERIFY_READ, (void *) arg, sizeof(bin_header));
254
                        if (error)
255
                                return error;
256
 
257
                        memcpy_fromfs(&frame, (void *) arg, sizeof(bin_header));
258
 
259
                        if (WaitTillCardIsFree(base))
260
                                return -EIO;
261
 
262
                        outw(0xf1,base);        /* start download sequence */
263
                        outw(0x00,base);
264
                        outw((frame.addr), base);/*      lsb of adderess    */
265
 
266
                        word_count=(frame.count >> 1) + frame.count % 2;
267
                        outw(word_count+1, base);
268
                        InterruptTheCard(base);
269
 
270
                        for(i=0;i<=0xf;i++);     /* a wee bit of delay */
271
 
272
                        if (WaitTillCardIsFree(base))
273
                                return -EIO;
274
 
275
                        if ((status=inw(base+0x4))!=0) {
276
                                printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
277
                                card+1, frame.addr, frame.count, status);
278
                                return -EIO;
279
                        }
280
 
281
                        inw(base);
282
                        insw(base, frame.bin_data, word_count);
283
                        InterruptTheCard(base);
284
 
285
                        for(i=0;i<=0x0f;i++);    /* another wee bit of delay */
286
 
287
                        if (WaitTillCardIsFree(base))
288
                                return -EIO;
289
 
290
                        if ((status=inw(base+0x4))!=0) {
291
                                printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);
292
                                return -EIO;
293
                        }
294
                        error=verify_area(VERIFY_WRITE, (void *) arg, sizeof(bin_frame));
295
                        if (error)
296
                                return error;
297
                        memcpy_tofs((void *) arg, &frame, sizeof(bin_frame));
298
 
299
                        return 0;
300
 
301
        case    MIOCTL_XFER_CTRL:
302
                        if (!suser())
303
                                return -EPERM;
304
                        if (WaitTillCardIsFree(base))
305
                                return -EIO;
306
 
307
                        outw(0xf2, base);
308
                        outw(0x800, base);
309
                        outw(0x0, base);
310
                        outw(0x0, base);
311
                        InterruptTheCard(base);
312
 
313
                        isi_card[card].status |= FIRMWARE_LOADED;
314
                        return 0;
315
 
316
        default:
317
#ifdef ISICOM_DEBUG     
318
                printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd);
319
#endif
320
                return -ENOIOCTLCMD;
321
 
322
        }
323
 
324
}
325
 
326
 
327
/*
328
 *      ISICOM Driver specific routines ...
329
 *
330
 */
331
 
332
static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev,
333
                                        const char * routine)
334
{
335
#ifdef ISICOM_DEBUG 
336
        static const char * badmagic =
337
                        KERN_WARNING "ISICOM: Warning: bad isicom magic for dev %s in %s.\n";
338
        static const char * badport =
339
                        KERN_WARNING "ISICOM: Warning: NULL isicom port for dev %s in %s.\n";
340
        if (!port) {
341
                printk(badport, kdevname(dev), routine);
342
                return 1;
343
        }
344
        if (port->magic != ISICOM_MAGIC) {
345
                printk(badmagic, kdevname(dev), routine);
346
                return 1;
347
        }
348
#endif  
349
        return 0;
350
}
351
 
352
extern inline void schedule_bh(struct isi_port * port)
353
{
354
        queue_task_irq_off(&port->bh_tqueue, &tq_isicom);
355
        mark_bh(ISICOM_BH);
356
}
357
 
358
/*      Transmitter     */
359
 
360
static void isicom_tx(unsigned long _data)
361
{
362
        short count = (BOARD_COUNT-1), card, base;
363
        short txcount, wait, wrd, residue, word_count, cnt;
364
        struct isi_port * port;
365
        struct tty_struct * tty;
366
        unsigned long flags;
367
 
368
#ifdef ISICOM_DEBUG
369
        ++tx_count;
370
#endif  
371
 
372
        /*      find next active board  */
373
        card = (prev_card + 1) & 0x0003;
374
        while(count-- > 0) {
375
                if (isi_card[card].status & BOARD_ACTIVE)
376
                        break;
377
                card = (card + 1) & 0x0003;
378
        }
379
        if (!(isi_card[card].status & BOARD_ACTIVE))
380
                goto sched_again;
381
 
382
        prev_card = card;
383
 
384
        count = isi_card[card].port_count;
385
        port = isi_card[card].ports;
386
        base = isi_card[card].base;
387
        for (;count > 0;count--, port++) {
388
                /* port not active or tx disabled to force flow control */
389
                if (!(port->status & ISI_TXOK))
390
                        continue;
391
 
392
                tty = port->tty;
393
                save_flags(flags); cli();
394
                txcount = MIN(TX_SIZE, port->xmit_cnt);
395
                if ((txcount <= 0) || tty->stopped || tty->hw_stopped) {
396
                        restore_flags(flags);
397
                        continue;
398
                }
399
                wait = 200;
400
                while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
401
                if (wait <= 0) {
402
                        restore_flags(flags);
403
#ifdef ISICOM_DEBUG
404
                        printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n",
405
                                card);
406
#endif
407
                        continue;
408
                }
409
                if (!(inw(base + 0x02) & (1 << port->channel))) {
410
                        restore_flags(flags);
411
#ifdef ISICOM_DEBUG                                     
412
                        printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n",
413
                                        base, port->channel + 1);
414
#endif                                  
415
                        continue;
416
                }
417
#ifdef ISICOM_DEBUG
418
                printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n",
419
                                txcount, port->channel+1);
420
#endif  
421
                outw((port->channel << isi_card[card].shift_count) | txcount
422
                                        , base);
423
                residue = NO;
424
                wrd = 0;
425
                while (1) {
426
                        cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail));
427
                        if (residue == YES) {
428
                                residue = NO;
429
                                if (cnt > 0) {
430
                                        wrd |= (port->xmit_buf[port->xmit_tail] << 8);
431
                                        port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
432
                                        port->xmit_cnt--;
433
                                        txcount--;
434
                                        cnt--;
435
                                        outw(wrd, base);
436
                                }
437
                                else {
438
                                        outw(wrd, base);
439
                                        break;
440
                                }
441
                        }
442
                        if (cnt <= 0) break;
443
                        word_count = cnt >> 1;
444
                        outsw(base, port->xmit_buf+port->xmit_tail, word_count);
445
                        port->xmit_tail = (port->xmit_tail + (word_count << 1)) &
446
                                                (SERIAL_XMIT_SIZE - 1);
447
                        txcount -= (word_count << 1);
448
                        port->xmit_cnt -= (word_count << 1);
449
                        if (cnt & 0x0001) {
450
                                residue = YES;
451
                                wrd = port->xmit_buf[port->xmit_tail];
452
                                port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
453
                                port->xmit_cnt--;
454
                                txcount--;
455
                        }
456
                }
457
/*
458
 *      Replaced the code below with hopefully a faster loop - sameer
459
 */
460
 
461
/*
462
                while (1) {
463
                        wrd = port->xmit_buf[port->xmit_tail++];
464
                        port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
465
                        port->xmit_cnt--;
466
                        if (--txcount > 0) {
467
                                wrd |= (port->xmit_buf[port->xmit_tail++] << 8);
468
                                port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
469
                                port->xmit_cnt--;
470
                                outw(wrd, base);
471
                                if (--txcount <= 0) break;
472
                        }
473
                        else {
474
                                outw(wrd, base);
475
                                break;
476
                        }
477
                }
478
*/
479
                InterruptTheCard(base);
480
                if (port->xmit_cnt <= 0)
481
                        port->status &= ~ISI_TXOK;
482
                if (port->xmit_cnt <= WAKEUP_CHARS)
483
                        schedule_bh(port);
484
                restore_flags(flags);
485
        }
486
 
487
                /*      schedule another tx for hopefully in about 10ms */
488
sched_again:
489
        if (!re_schedule)
490
                return;
491
        init_timer(&tx);
492
        tx.expires = jiffies + HZ/100;
493
        tx.data = 0;
494
        tx.function = isicom_tx;
495
        add_timer(&tx);
496
 
497
        return;
498
}
499
 
500
                /*      Interrupt handlers      */
501
static void do_isicom_bh(void)
502
{
503
        run_task_queue(&tq_isicom);
504
}
505
 
506
 
507
 
508
static void isicom_bottomhalf(void * data)
509
{
510
        struct isi_port * port = (struct isi_port *) data;
511
        struct tty_struct * tty = port->tty;
512
 
513
        if (!tty)
514
                return;
515
 
516
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
517
            tty->ldisc.write_wakeup)
518
                (tty->ldisc.write_wakeup)(tty);
519
        wake_up_interruptible(&tty->write_wait);
520
}
521
 
522
/* main interrupt handler routine */
523
static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs)
524
{
525
        struct isi_board * card;
526
        struct isi_port * port;
527
        struct tty_struct * tty;
528
        unsigned short base, header, word_count, count;
529
        unsigned char channel;
530
        short byte_count;
531
 
532
        card = irq_to_board[irq];
533
        if (!card || !(card->status & FIRMWARE_LOADED)) {
534
                printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);
535
                return;
536
        }
537
        base = card->base;
538
 
539
        inw(base);              /* get the dummy word out */
540
        header = inw(base);
541
        channel = (header & 0x7800) >> card->shift_count;
542
        byte_count = header & 0xff;
543
#ifdef ISICOM_DEBUG     
544
        printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1);
545
#endif  
546
        if ((channel+1) > card->port_count) {
547
                printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n",
548
                                base, channel+1);
549
                ClearInterrupt(base);
550
                return;
551
        }
552
        port = card->ports + channel;
553
        if (!(port->flags & ASYNC_INITIALIZED)) {
554
                ClearInterrupt(base);
555
                return;
556
        }
557
 
558
        tty = port->tty;
559
 
560
        if (header & 0x8000) {          /* Status Packet */
561
                header = inw(base);
562
                switch(header & 0xff) {
563
                        case 0:  /* Change in EIA signals */
564
 
565
                                if (port->flags & ASYNC_CHECK_CD) {
566
                                        if (port->status & ISI_DCD) {
567
                                                if (!(header & ISI_DCD)) {
568
                                                /* Carrier has been lost  */
569
#ifdef ISICOM_DEBUG                                             
570
                                                        printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n");
571
#endif                                                  
572
                                                        port->status &= ~ISI_DCD;
573
                                                        if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
574
                                                                (port->flags & ASYNC_CALLOUT_NOHUP)))
575
                                                                queue_task_irq_off(&port->hangup_tq,
576
                                                                        &tq_scheduler);
577
                                                }
578
                                        }
579
                                        else {
580
                                                if (header & ISI_DCD) {
581
                                                /* Carrier has been detected */
582
#ifdef ISICOM_DEBUG
583
                                                        printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n");
584
#endif                                                  
585
                                                        port->status |= ISI_DCD;
586
                                                        wake_up_interruptible(&port->open_wait);
587
                                                }
588
                                        }
589
                                }
590
                                else {
591
                                        if (header & ISI_DCD)
592
                                                port->status |= ISI_DCD;
593
                                        else
594
                                                port->status &= ~ISI_DCD;
595
                                }
596
 
597
                                if (port->flags & ASYNC_CTS_FLOW) {
598
                                        if (port->tty->hw_stopped) {
599
                                                if (header & ISI_CTS) {
600
                                                        port->tty->hw_stopped = 0;
601
                                                        /* start tx ing */
602
                                                        port->status |= (ISI_TXOK | ISI_CTS);
603
                                                        schedule_bh(port);
604
                                                }
605
                                        }
606
                                        else {
607
                                                if (!(header & ISI_CTS)) {
608
                                                        port->tty->hw_stopped = 1;
609
                                                        /* stop tx ing */
610
                                                        port->status &= ~(ISI_TXOK | ISI_CTS);
611
                                                }
612
                                        }
613
                                }
614
                                else {
615
                                        if (header & ISI_CTS)
616
                                                port->status |= ISI_CTS;
617
                                        else
618
                                                port->status &= ~ISI_CTS;
619
                                }
620
 
621
                                if (header & ISI_DSR)
622
                                        port->status |= ISI_DSR;
623
                                else
624
                                        port->status &= ~ISI_DSR;
625
 
626
                                if (header & ISI_RI)
627
                                        port->status |= ISI_RI;
628
                                else
629
                                        port->status &= ~ISI_RI;
630
 
631
                                break;
632
 
633
                        case 1: /* Received Break !!!    */
634
                                if (tty->flip.count >= TTY_FLIPBUF_SIZE)
635
                                        break;
636
                                *tty->flip.flag_buf_ptr++ = TTY_BREAK;
637
                                /* dunno if this is right */
638
                                *tty->flip.char_buf_ptr++ = 0;
639
                                tty->flip.count++;
640
                                if (port->flags & ASYNC_SAK)
641
                                        do_SAK(tty);
642
                                queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
643
                                break;
644
 
645
                        case 2: /* Statistics            */
646
                                printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n");
647
                                break;
648
 
649
                        default:
650
                                printk(KERN_WARNING "ISICOM: Intr: Unknown code in status packet.\n");
651
                                break;
652
                }
653
        }
654
        else {                          /* Data   Packet */
655
                count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count));
656
#ifdef ISICOM_DEBUG
657
                printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n",
658
                                        count, byte_count);
659
#endif                  
660
                word_count = count >> 1;
661
                insw(base, tty->flip.char_buf_ptr, word_count);
662
                tty->flip.char_buf_ptr += (word_count << 1);
663
                byte_count -= (word_count << 1);
664
                if (count & 0x0001) {
665
                        *tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff);
666
                        byte_count -= 2;
667
                }
668
                memset(tty->flip.flag_buf_ptr, 0, count);
669
                tty->flip.flag_buf_ptr += count;
670
                tty->flip.count += count;
671
 
672
                if (byte_count > 0) {
673
                        printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n",
674
                                        base, channel+1);
675
                        while(byte_count > 0) { /* drain out unread xtra data */
676
                                inw(base);
677
                                byte_count -= 2;
678
                        }
679
                }
680
                queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
681
        }
682
        ClearInterrupt(base);
683
        return;
684
}
685
 
686
 /* called with interrupts disabled */
687
static void isicom_config_port(struct isi_port * port)
688
{
689
        struct isi_board * card = port->card;
690
        struct tty_struct * tty;
691
        unsigned long baud;
692
        unsigned short channel_setup, wait, base = card->base;
693
        unsigned short channel = port->channel, shift_count = card->shift_count;
694
        unsigned char flow_ctrl;
695
 
696
        if (!(tty = port->tty) || !tty->termios)
697
                return;
698
        baud = C_BAUD(tty);
699
        if (baud & CBAUDEX) {
700
                baud &= ~CBAUDEX;
701
 
702
                /*  if CBAUDEX bit is on and the baud is set to either 50 or 75
703
                 *  then the card is programmed for 57.6Kbps or 115Kbps
704
                 *  respectively.
705
                 */
706
 
707
                if (baud < 1 || baud > 2)
708
                        port->tty->termios->c_cflag &= ~CBAUDEX;
709
                else
710
                        baud += 15;
711
        }
712
        if (baud == 15) {
713
 
714
                /*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
715
                 *  by the set_serial_info ioctl ... this is done by
716
                 *  the 'setserial' utility.
717
                 */
718
 
719
                if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
720
                        baud++;     /*  57.6 Kbps */
721
                if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
722
                        baud +=2;   /*  115  Kbps */
723
        }
724
        if (linuxb_to_isib[baud] == -1) {
725
                /* hang up */
726
                drop_dtr(port);
727
                return;
728
        }
729
        else
730
                raise_dtr(port);
731
 
732
        wait = 100;
733
        while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));
734
        if (!wait) {
735
                printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n");
736
                return;
737
        }
738
        outw(0x8000 | (channel << shift_count) |0x03, base);
739
        outw(linuxb_to_isib[baud] << 8 | 0x03, base);
740
        channel_setup = 0;
741
        switch(C_CSIZE(tty)) {
742
                case CS5:
743
                        channel_setup |= ISICOM_CS5;
744
                        break;
745
                case CS6:
746
                        channel_setup |= ISICOM_CS6;
747
                        break;
748
                case CS7:
749
                        channel_setup |= ISICOM_CS7;
750
                        break;
751
                case CS8:
752
                        channel_setup |= ISICOM_CS8;
753
                        break;
754
        }
755
 
756
        if (C_CSTOPB(tty))
757
                channel_setup |= ISICOM_2SB;
758
 
759
        if (C_PARENB(tty))
760
                channel_setup |= ISICOM_EVPAR;
761
        if (C_PARODD(tty))
762
                channel_setup |= ISICOM_ODPAR;
763
        outw(channel_setup, base);
764
        InterruptTheCard(base);
765
 
766
        if (C_CLOCAL(tty))
767
                port->flags &= ~ASYNC_CHECK_CD;
768
        else
769
                port->flags |= ASYNC_CHECK_CD;
770
 
771
        /* flow control settings ...*/
772
        flow_ctrl = 0;
773
        port->flags &= ~ASYNC_CTS_FLOW;
774
        if (C_CRTSCTS(tty)) {
775
                port->flags |= ASYNC_CTS_FLOW;
776
                flow_ctrl |= ISICOM_CTSRTS;
777
        }
778
        if (I_IXON(tty))
779
                flow_ctrl |= ISICOM_RESPOND_XONXOFF;
780
        if (I_IXOFF(tty))
781
                flow_ctrl |= ISICOM_INITIATE_XONXOFF;
782
 
783
        wait = 100;
784
        while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));
785
        if (!wait) {
786
                printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n");
787
                return;
788
        }
789
        outw(0x8000 | (channel << shift_count) |0x04, base);
790
        outw(flow_ctrl << 8 | 0x05, base);
791
        outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
792
        InterruptTheCard(base);
793
 
794
        /*      rx enabled -> enable port for rx on the card    */
795
        if (C_CREAD(tty)) {
796
                card->port_status |= (1 << channel);
797
                outw(card->port_status, base + 0x02);
798
        }
799
 
800
}
801
 
802
/* open et all */
803
 
804
extern inline void isicom_setup_board(struct isi_board * bp)
805
{
806
        int channel;
807
        struct isi_port * port;
808
        unsigned long flags;
809
 
810
        if (bp->status & BOARD_ACTIVE)
811
                return;
812
        port = bp->ports;
813
#ifdef ISICOM_DEBUG     
814
        printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count);
815
#endif
816
        for(channel = 0; channel < bp->port_count; channel++, port++) {
817
                save_flags(flags); cli();
818
                drop_dtr_rts(port);
819
                restore_flags(flags);
820
        }
821
#ifdef ISICOM_DEBUG             
822
        printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n");
823
#endif  
824
 
825
        bp->status |= BOARD_ACTIVE;
826
        MOD_INC_USE_COUNT;
827
        return;
828
}
829
 
830
static int isicom_setup_port(struct isi_port * port)
831
{
832
        struct isi_board * card = port->card;
833
        unsigned long flags;
834
 
835
        if (port->flags & ASYNC_INITIALIZED)
836
                return 0;
837
        if (!port->xmit_buf) {
838
                unsigned long page;
839
 
840
                if (!(page = get_free_page(GFP_KERNEL)))
841
                        return -ENOMEM;
842
 
843
                if (port->xmit_buf) {
844
                        free_page(page);
845
                        return -ERESTARTSYS;
846
                }
847
                port->xmit_buf = (unsigned char *) page;
848
        }
849
        save_flags(flags); cli();
850
        if (port->tty)
851
                clear_bit(TTY_IO_ERROR, &port->tty->flags);
852
        if (port->count == 1)
853
                card->count++;
854
 
855
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
856
 
857
        /*      discard any residual data       */
858
        kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX);
859
 
860
        isicom_config_port(port);
861
        port->flags |= ASYNC_INITIALIZED;
862
 
863
        restore_flags(flags);
864
 
865
        return 0;
866
}
867
 
868
static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port)
869
{
870
        int do_clocal = 0, retval;
871
        struct wait_queue wait = { current, NULL };
872
 
873
        /* block if port is in the process of being closed */
874
 
875
        if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
876
#ifdef ISICOM_DEBUG     
877
                printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n");
878
#endif          
879
                interruptible_sleep_on(&port->close_wait);
880
                if (port->flags & ASYNC_HUP_NOTIFY)
881
                        return -EAGAIN;
882
                else
883
                        return -ERESTARTSYS;
884
        }
885
 
886
        /* trying to open a callout device... check for constraints */
887
 
888
        if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
889
#ifdef ISICOM_DEBUG
890
                printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n");
891
#endif          
892
                if (port->flags & ASYNC_NORMAL_ACTIVE)
893
                        return -EBUSY;
894
                if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
895
                    (port->flags & ASYNC_SESSION_LOCKOUT) &&
896
                    (port->session != current->session))
897
                        return -EBUSY;
898
 
899
                if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
900
                    (port->flags & ASYNC_PGRP_LOCKOUT) &&
901
                    (port->pgrp != current->pgrp))
902
                        return -EBUSY;
903
                port->flags |= ASYNC_CALLOUT_ACTIVE;
904
                cli();
905
                raise_dtr_rts(port);
906
                sti();
907
                return 0;
908
        }
909
 
910
        /* if non-blocking mode is set ... */
911
 
912
        if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
913
#ifdef ISICOM_DEBUG     
914
                printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n");
915
#endif          
916
                if (port->flags & ASYNC_CALLOUT_ACTIVE)
917
                        return -EBUSY;
918
                port->flags |= ASYNC_NORMAL_ACTIVE;
919
                return 0;
920
        }
921
 
922
        if (port->flags & ASYNC_CALLOUT_ACTIVE) {
923
                if (port->normal_termios.c_cflag & CLOCAL)
924
                        do_clocal = 1;
925
        } else {
926
                if (C_CLOCAL(tty))
927
                        do_clocal = 1;
928
        }
929
#ifdef ISICOM_DEBUG     
930
        if (do_clocal)
931
                printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n");
932
#endif          
933
 
934
        /* block waiting for DCD to be asserted, and while
935
                                                callout dev is busy */
936
        retval = 0;
937
        add_wait_queue(&port->open_wait, &wait);
938
        cli();
939
                if (!tty_hung_up_p(filp))
940
                        port->count--;
941
        sti();
942
        port->blocked_open++;
943
#ifdef ISICOM_DEBUG     
944
        printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n");
945
#endif  
946
        while (1) {
947
                cli();
948
                if (!(port->flags & ASYNC_CALLOUT_ACTIVE))
949
                        raise_dtr_rts(port);
950
 
951
                sti();
952
                current->state = TASK_INTERRUPTIBLE;
953
                if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
954
                        if (port->flags & ASYNC_HUP_NOTIFY)
955
                                retval = -EAGAIN;
956
                        else
957
                                retval = -ERESTARTSYS;
958
#ifdef ISICOM_DEBUG                             
959
                        printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n");
960
#endif                  
961
                        break;
962
                }
963
                if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
964
                    !(port->flags & ASYNC_CLOSING) &&
965
                    (do_clocal || (port->status & ISI_DCD))) {
966
#ifdef ISICOM_DEBUG                 
967
                        printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n");
968
#endif                  
969
                        break;
970
                }
971
                if (current->signal & ~current->blocked) {
972
#ifdef ISICOM_DEBUG             
973
                        printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n");
974
#endif                  
975
                        retval = -ERESTARTSYS;
976
                        break;
977
                }
978
                schedule();
979
        }
980
        current->state = TASK_RUNNING;
981
        remove_wait_queue(&port->open_wait, &wait);
982
        if (!tty_hung_up_p(filp))
983
                port->count++;
984
        port->blocked_open--;
985
        if (retval)
986
                return retval;
987
        port->flags |= ASYNC_NORMAL_ACTIVE;
988
        return 0;
989
}
990
 
991
static int isicom_open(struct tty_struct * tty, struct file * filp)
992
{
993
        struct isi_port * port;
994
        struct isi_board * card;
995
        unsigned int line, board;
996
        unsigned long flags;
997
        int error;
998
 
999
#ifdef ISICOM_DEBUG     
1000
        printk(KERN_DEBUG "ISICOM: open start!!!.\n");
1001
#endif  
1002
        line = MINOR(tty->device) - tty->driver.minor_start;
1003
 
1004
#ifdef ISICOM_DEBUG     
1005
        printk(KERN_DEBUG "line = %d.\n", line);
1006
#endif  
1007
 
1008
        if ((line < 0) || (line > (PORT_COUNT-1)))
1009
                return -ENODEV;
1010
        board = BOARD(line);
1011
 
1012
#ifdef ISICOM_DEBUG     
1013
        printk(KERN_DEBUG "board = %d.\n", board);
1014
#endif  
1015
 
1016
        card = &isi_card[board];
1017
        if (!(card->status & FIRMWARE_LOADED)) {
1018
#ifdef ISICOM_DEBUG     
1019
                printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board);
1020
#endif          
1021
                return -ENODEV;
1022
        }
1023
 
1024
        /*  open on higher 8 dev files on a 8 port card !!! */
1025
        if (card->port_count == 8)
1026
                if (line > ((board * 16)+7)) {
1027
                        printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n");
1028
                        return -ENODEV;
1029
                }
1030
        port = &isi_ports[line];
1031
        if (isicom_paranoia_check(port, tty->device, "isicom_open"))
1032
                return -ENODEV;
1033
 
1034
#ifdef ISICOM_DEBUG             
1035
        printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n");
1036
#endif  
1037
        isicom_setup_board(card);
1038
 
1039
        port->count++;
1040
        tty->driver_data = port;
1041
        port->tty = tty;
1042
#ifdef ISICOM_DEBUG     
1043
        printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n");
1044
#endif  
1045
        if ((error = isicom_setup_port(port))!=0)
1046
                return error;
1047
#ifdef ISICOM_DEBUG             
1048
        printk(KERN_DEBUG "ISICOM: block_til_ready ...\n");
1049
#endif  
1050
        if ((error = block_til_ready(tty, filp, port))!=0)
1051
                return error;
1052
 
1053
        if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
1054
                if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
1055
                        *tty->termios = port->normal_termios;
1056
                else
1057
                        *tty->termios = port->callout_termios;
1058
                save_flags(flags); cli();
1059
                isicom_config_port(port);
1060
                restore_flags(flags);
1061
        }
1062
 
1063
        port->session = current->session;
1064
        port->pgrp = current->pgrp;
1065
#ifdef ISICOM_DEBUG     
1066
        printk(KERN_DEBUG "ISICOM: open end!!!.\n");
1067
#endif  
1068
        return 0;
1069
}
1070
 
1071
/* close et all */
1072
 
1073
extern inline void isicom_shutdown_board(struct isi_board * bp)
1074
{
1075
        int channel;
1076
        struct isi_port * port;
1077
 
1078
        if (!(bp->status & BOARD_ACTIVE))
1079
                return;
1080
        bp->status &= ~BOARD_ACTIVE;
1081
        port = bp->ports;
1082
        for(channel = 0; channel < bp->port_count; channel++, port++) {
1083
                drop_dtr_rts(port);
1084
        }
1085
        MOD_DEC_USE_COUNT;
1086
}
1087
 
1088
static void isicom_shutdown_port(struct isi_port * port)
1089
{
1090
        struct isi_board * card = port->card;
1091
        struct tty_struct * tty;
1092
 
1093
        if (!(port->flags & ASYNC_INITIALIZED))
1094
                return;
1095
        if (port->xmit_buf) {
1096
                free_page((unsigned long) port->xmit_buf);
1097
                port->xmit_buf = NULL;
1098
        }
1099
        if (!(tty = port->tty) || C_HUPCL(tty))
1100
                /* drop dtr on this port */
1101
                drop_dtr(port);
1102
 
1103
        /* any other port uninits  */
1104
 
1105
        if (tty)
1106
                set_bit(TTY_IO_ERROR, &tty->flags);
1107
        port->flags &= ~ASYNC_INITIALIZED;
1108
 
1109
        if (--card->count < 0) {
1110
                printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n",
1111
                        card->base, card->count);
1112
                card->count = 0;
1113
        }
1114
 
1115
        /* last port was closed , shutdown that boad too */
1116
        if (!card->count)
1117
                isicom_shutdown_board(card);
1118
}
1119
 
1120
static void isicom_close(struct tty_struct * tty, struct file * filp)
1121
{
1122
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1123
        struct isi_board * card = port->card;
1124
        unsigned long flags;
1125
 
1126
        if (!port)
1127
                return;
1128
        if (isicom_paranoia_check(port, tty->device, "isicom_close"))
1129
                return;
1130
 
1131
#ifdef ISICOM_DEBUG             
1132
        printk(KERN_DEBUG "ISICOM: Close start!!!.\n");
1133
#endif  
1134
 
1135
        save_flags(flags); cli();
1136
        if (tty_hung_up_p(filp)) {
1137
                restore_flags(flags);
1138
                return;
1139
        }
1140
 
1141
        if ((tty->count == 1) && (port->count != 1)) {
1142
                printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count"
1143
                        "tty->count = 1 port count = %d.\n",
1144
                        card->base, port->count);
1145
                port->count = 1;
1146
        }
1147
        if (--port->count < 0) {
1148
                printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for"
1149
                        "channel%d = %d", card->base, port->channel,
1150
                        port->count);
1151
                port->count = 0;
1152
        }
1153
 
1154
        if (port->count) {
1155
                restore_flags(flags);
1156
                return;
1157
        }
1158
        port->flags |= ASYNC_CLOSING;
1159
        /*
1160
         * save termios struct since callout and dialin termios may be
1161
         * different.
1162
         */
1163
        if (port->flags & ASYNC_NORMAL_ACTIVE)
1164
                port->normal_termios = *tty->termios;
1165
        if (port->flags & ASYNC_CALLOUT_ACTIVE)
1166
                port->callout_termios = *tty->termios;
1167
 
1168
        tty->closing = 1;
1169
        if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
1170
                tty_wait_until_sent(tty, port->closing_wait);
1171
        /* indicate to the card that no more data can be received
1172
           on this port */
1173
        if (port->flags & ASYNC_INITIALIZED) {
1174
                card->port_status &= ~(1 << port->channel);
1175
                outw(card->port_status, card->base + 0x02);
1176
        }
1177
        isicom_shutdown_port(port);
1178
        if (tty->driver.flush_buffer)
1179
                tty->driver.flush_buffer(tty);
1180
        if (tty->ldisc.flush_buffer)
1181
                tty->ldisc.flush_buffer(tty);
1182
        tty->closing = 0;
1183
        port->tty = 0;
1184
        if (port->blocked_open) {
1185
                if (port->close_delay) {
1186
                        current->state = TASK_INTERRUPTIBLE;
1187
                        current->timeout = jiffies + port->close_delay;
1188
#ifdef ISICOM_DEBUG                     
1189
                        printk(KERN_DEBUG "ISICOM: scheduling until time out.\n");
1190
#endif                  
1191
                        schedule();
1192
                }
1193
                wake_up_interruptible(&port->open_wait);
1194
        }
1195
        port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
1196
                        ASYNC_CLOSING);
1197
        wake_up_interruptible(&port->close_wait);
1198
        restore_flags(flags);
1199
#ifdef ISICOM_DEBUG     
1200
        printk(KERN_DEBUG "ISICOM: Close end!!!.\n");
1201
#endif  
1202
}
1203
 
1204
/* write et all */
1205
static int isicom_write(struct tty_struct * tty, int from_user,
1206
                        const unsigned char * buf, int count)
1207
{
1208
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1209
        unsigned long flags;
1210
        int cnt, total = 0;
1211
#ifdef ISICOM_DEBUG
1212
        printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n",
1213
                        port->channel+1, count);
1214
#endif          
1215
        if (isicom_paranoia_check(port, tty->device, "isicom_write"))
1216
                return 0;
1217
 
1218
        if (!tty || !port->xmit_buf || !tmp_buf)
1219
                return 0;
1220
        if (from_user)
1221
                down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */
1222
 
1223
        save_flags(flags);
1224
        while(1) {
1225
                cli();
1226
                cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
1227
                        SERIAL_XMIT_SIZE - port->xmit_head));
1228
                if (cnt <= 0)
1229
                        break;
1230
 
1231
                if (from_user) {
1232
                        /* the following may block for paging... hence
1233
                           enabling interrupts but tx routine may have
1234
                           created more space in xmit_buf when the ctrl
1235
                           gets back here
1236
                        sti(); */
1237
                        memcpy_fromfs(tmp_buf, buf, cnt);
1238
/*                      cli();*/
1239
                        cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
1240
                        SERIAL_XMIT_SIZE - port->xmit_head));
1241
                        memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt);
1242
                }
1243
                else
1244
                        memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
1245
                port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1);
1246
                port->xmit_cnt += cnt;
1247
                restore_flags(flags);
1248
                buf += cnt;
1249
                count -= cnt;
1250
                total += cnt;
1251
        }
1252
        if (from_user)
1253
                up(&tmp_buf_sem);
1254
        if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1255
                port->status |= ISI_TXOK;
1256
        restore_flags(flags);
1257
#ifdef ISICOM_DEBUG
1258
        printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total);
1259
#endif          
1260
        return total;
1261
}
1262
 
1263
/* put_char et all */
1264
static void isicom_put_char(struct tty_struct * tty, unsigned char ch)
1265
{
1266
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1267
        unsigned long flags;
1268
 
1269
        if (isicom_paranoia_check(port, tty->device, "isicom_put_char"))
1270
                return;
1271
 
1272
        if (!tty || !port->xmit_buf)
1273
                return;
1274
#ifdef ISICOM_DEBUG
1275
        printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch);
1276
#endif                  
1277
 
1278
        save_flags(flags); cli();
1279
 
1280
        if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) {
1281
                restore_flags(flags);
1282
                return;
1283
        }
1284
 
1285
        port->xmit_buf[port->xmit_head++] = ch;
1286
        port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
1287
        port->xmit_cnt++;
1288
        restore_flags(flags);
1289
}
1290
 
1291
/* flush_chars et all */
1292
static void isicom_flush_chars(struct tty_struct * tty)
1293
{
1294
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1295
 
1296
        if (isicom_paranoia_check(port, tty->device, "isicom_flush_chars"))
1297
                return;
1298
 
1299
        if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1300
            !port->xmit_buf)
1301
                return;
1302
 
1303
        /* this tells the transmitter to consider this port for
1304
           data output to the card ... that's the best we can do. */
1305
        port->status |= ISI_TXOK;
1306
}
1307
 
1308
/* write_room et all */
1309
static int isicom_write_room(struct tty_struct * tty)
1310
{
1311
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1312
        int free;
1313
        if (isicom_paranoia_check(port, tty->device, "isicom_write_room"))
1314
                return 0;
1315
 
1316
        free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1317
        if (free < 0)
1318
                free = 0;
1319
        return free;
1320
}
1321
 
1322
/* chars_in_buffer et all */
1323
static int isicom_chars_in_buffer(struct tty_struct * tty)
1324
{
1325
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1326
        if (isicom_paranoia_check(port, tty->device, "isicom_chars_in_buffer"))
1327
                return 0;
1328
        return port->xmit_cnt;
1329
}
1330
 
1331
/* ioctl et all */
1332
extern inline void isicom_send_break(struct isi_port * port, unsigned long length)
1333
{
1334
        struct isi_board * card = port->card;
1335
        short wait = 10;
1336
        unsigned short base = card->base;
1337
        unsigned long flags;
1338
 
1339
        save_flags(flags); cli();
1340
        while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));
1341
        if (!wait) {
1342
                printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n");
1343
                return;
1344
        }
1345
        outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
1346
        outw((length & 0xff) << 8 | 0x00, base);
1347
        outw((length & 0xff00), base);
1348
        InterruptTheCard(base);
1349
        restore_flags(flags);
1350
}
1351
 
1352
static int isicom_get_modem_info(struct isi_port * port, unsigned int * value)
1353
{
1354
        /* just send the port status */
1355
        unsigned int info;
1356
        unsigned short status = port->status;
1357
 
1358
        info =  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
1359
                ((status & ISI_DTR) ? TIOCM_DTR : 0) |
1360
                ((status & ISI_DCD) ? TIOCM_CAR : 0) |
1361
                ((status & ISI_DSR) ? TIOCM_DSR : 0) |
1362
                ((status & ISI_CTS) ? TIOCM_CTS : 0) |
1363
                ((status & ISI_RI ) ? TIOCM_RI  : 0);
1364
        put_user(info, (unsigned long *) value);
1365
        return 0;
1366
}
1367
 
1368
static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd,
1369
                                        unsigned int * value)
1370
{
1371
        unsigned int arg;
1372
        unsigned long flags;
1373
 
1374
        arg = get_user(value);
1375
        save_flags(flags); cli();
1376
        switch(cmd) {
1377
                case TIOCMBIS:
1378
                        if (arg & TIOCM_RTS)
1379
                                raise_rts(port);
1380
                        if (arg & TIOCM_DTR)
1381
                                raise_dtr(port);
1382
                        break;
1383
 
1384
                case TIOCMBIC:
1385
                        if (arg & TIOCM_RTS)
1386
                                drop_rts(port);
1387
                        if (arg & TIOCM_DTR)
1388
                                drop_dtr(port);
1389
                        break;
1390
 
1391
                case TIOCMSET:
1392
                        if (arg & TIOCM_RTS)
1393
                                raise_rts(port);
1394
                        else
1395
                                drop_rts(port);
1396
 
1397
                        if (arg & TIOCM_DTR)
1398
                                raise_dtr(port);
1399
                        else
1400
                                drop_dtr(port);
1401
                        break;
1402
 
1403
                default:
1404
                        restore_flags(flags);
1405
                        return -EINVAL;
1406
        }
1407
        restore_flags(flags);
1408
        return 0;
1409
}
1410
 
1411
static int isicom_set_serial_info(struct isi_port * port,
1412
                                        struct serial_struct * info)
1413
{
1414
        struct serial_struct newinfo;
1415
        unsigned long flags;
1416
        int reconfig_port;
1417
 
1418
        memcpy_fromfs(&newinfo, info, sizeof(newinfo));
1419
        reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
1420
                         (newinfo.flags & ASYNC_SPD_MASK));
1421
 
1422
        if (!suser()) {
1423
                if ((newinfo.close_delay != port->close_delay) ||
1424
                    (newinfo.closing_wait != port->closing_wait) ||
1425
                    ((newinfo.flags & ~ASYNC_USR_MASK) !=
1426
                     (port->flags & ~ASYNC_USR_MASK)))
1427
                        return -EPERM;
1428
                port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
1429
                                (newinfo.flags & ASYNC_USR_MASK));
1430
        }
1431
        else {
1432
                port->close_delay = newinfo.close_delay;
1433
                port->closing_wait = newinfo.closing_wait;
1434
                port->flags = ((port->flags & ~ASYNC_FLAGS) |
1435
                                (newinfo.flags & ASYNC_FLAGS));
1436
        }
1437
        if (reconfig_port) {
1438
                save_flags(flags); cli();
1439
                isicom_config_port(port);
1440
                restore_flags(flags);
1441
        }
1442
        return 0;
1443
}
1444
 
1445
static int isicom_get_serial_info(struct isi_port * port,
1446
                                        struct serial_struct * info)
1447
{
1448
        struct serial_struct out_info;
1449
 
1450
        memset(&out_info, 0, sizeof(out_info));
1451
/*      out_info.type = ? */
1452
        out_info.line = port - isi_ports;
1453
        out_info.port = port->card->base;
1454
        out_info.irq = port->card->irq;
1455
        out_info.flags = port->flags;
1456
/*      out_info.baud_base = ? */
1457
        out_info.close_delay = port->close_delay;
1458
        out_info.closing_wait = port->closing_wait;
1459
        memcpy_tofs(info, &out_info, sizeof(out_info));
1460
        return 0;
1461
}
1462
 
1463
static int isicom_ioctl(struct tty_struct * tty, struct file * filp,
1464
                        unsigned int cmd, unsigned long arg)
1465
{
1466
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1467
        int retval, error;
1468
 
1469
        if (isicom_paranoia_check(port, tty->device, "isicom_ioctl"))
1470
                return -ENODEV;
1471
 
1472
        switch(cmd) {
1473
                case TCSBRK:
1474
                        retval = tty_check_change(tty);
1475
                        if (retval)
1476
                                return retval;
1477
                        tty_wait_until_sent(tty, 0);
1478
                        if (!arg)
1479
                                isicom_send_break(port, HZ/4);
1480
                        return 0;
1481
 
1482
                case TCSBRKP:
1483
                        retval = tty_check_change(tty);
1484
                        if (retval)
1485
                                return retval;
1486
                        tty_wait_until_sent(tty, 0);
1487
                        isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
1488
                        return 0;
1489
 
1490
                case TIOCGSOFTCAR:
1491
                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
1492
                        if (error)
1493
                                return error;
1494
                        put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
1495
                        return 0;
1496
 
1497
                case TIOCSSOFTCAR:
1498
                        error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
1499
                        if (error)
1500
                                return error;
1501
                        arg = get_user((unsigned long *) arg);
1502
                        tty->termios->c_cflag =
1503
                                ((tty->termios->c_cflag & ~CLOCAL) |
1504
                                (arg ? CLOCAL : 0));
1505
                        return 0;
1506
 
1507
                case TIOCMGET:
1508
                        error = verify_area(VERIFY_WRITE, (void *) arg,
1509
                                        sizeof(unsigned int));
1510
                        if (error)
1511
                                return error;
1512
                        return isicom_get_modem_info(port, (unsigned int*) arg);
1513
 
1514
                case TIOCMBIS:
1515
                case TIOCMBIC:
1516
                case TIOCMSET:
1517
                        error = verify_area(VERIFY_READ, (void *) arg,
1518
                                        sizeof(unsigned int));
1519
                        if (error)
1520
                                return error;
1521
                        return isicom_set_modem_info(port, cmd,
1522
                                        (unsigned int *) arg);
1523
 
1524
                case TIOCGSERIAL:
1525
                        error = verify_area(VERIFY_WRITE, (void *) arg,
1526
                                        sizeof(struct serial_struct));
1527
                        if (error)
1528
                                return error;
1529
                        return isicom_get_serial_info(port,
1530
                                        (struct serial_struct *) arg);
1531
 
1532
                case TIOCSSERIAL:
1533
                        error = verify_area(VERIFY_READ, (void *) arg,
1534
                                        sizeof(struct serial_struct));
1535
                        if (error)
1536
                                return error;
1537
                        return isicom_set_serial_info(port,
1538
                                        (struct serial_struct *) arg);
1539
 
1540
                default:
1541
                        return -ENOIOCTLCMD;
1542
        }
1543
        return 0;
1544
}
1545
 
1546
/* set_termios et all */
1547
static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios)
1548
{
1549
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1550
        unsigned long flags;
1551
 
1552
        if (isicom_paranoia_check(port, tty->device, "isicom_set_termios"))
1553
                return;
1554
 
1555
        if (tty->termios->c_cflag == old_termios->c_cflag &&
1556
            tty->termios->c_iflag == old_termios->c_iflag)
1557
                return;
1558
 
1559
        save_flags(flags); cli();
1560
        isicom_config_port(port);
1561
        restore_flags(flags);
1562
 
1563
        if ((old_termios->c_cflag & CRTSCTS) &&
1564
            !(tty->termios->c_cflag & CRTSCTS)) {
1565
                tty->hw_stopped = 0;
1566
                isicom_start(tty);
1567
        }
1568
}
1569
 
1570
/* throttle et all */
1571
static void isicom_throttle(struct tty_struct * tty)
1572
{
1573
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1574
        struct isi_board * card = port->card;
1575
        unsigned long flags;
1576
 
1577
        if (isicom_paranoia_check(port, tty->device, "isicom_throttle"))
1578
                return;
1579
 
1580
        /* tell the card that this port cannot handle any more data for now */
1581
        save_flags(flags); cli();
1582
        card->port_status &= ~(1 << port->channel);
1583
        outw(card->port_status, card->base + 0x02);
1584
        restore_flags(flags);
1585
}
1586
 
1587
/* unthrottle et all */
1588
static void isicom_unthrottle(struct tty_struct * tty)
1589
{
1590
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1591
        struct isi_board * card = port->card;
1592
        unsigned long flags;
1593
 
1594
        if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle"))
1595
                return;
1596
 
1597
        /* tell the card that this port is ready to accept more data */
1598
        save_flags(flags); cli();
1599
        card->port_status |= (1 << port->channel);
1600
        outw(card->port_status, card->base + 0x02);
1601
        restore_flags(flags);
1602
}
1603
 
1604
/* stop et all */
1605
static void isicom_stop(struct tty_struct * tty)
1606
{
1607
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1608
 
1609
        if (isicom_paranoia_check(port, tty->device, "isicom_stop"))
1610
                return;
1611
 
1612
        /* this tells the transmitter not to consider this port for
1613
           data output to the card. */
1614
        port->status &= ~ISI_TXOK;
1615
}
1616
 
1617
/* start et all */
1618
static void isicom_start(struct tty_struct * tty)
1619
{
1620
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1621
 
1622
        if (isicom_paranoia_check(port, tty->device, "isicom_start"))
1623
                return;
1624
 
1625
        /* this tells the transmitter to consider this port for
1626
           data output to the card. */
1627
        port->status |= ISI_TXOK;
1628
}
1629
 
1630
/* hangup et all */
1631
static void do_isicom_hangup(void * data)
1632
{
1633
        struct isi_port * port = (struct isi_port *) data;
1634
        struct tty_struct * tty;
1635
 
1636
        tty = port->tty;
1637
        if (!tty)
1638
                return;
1639
 
1640
        tty_hangup(tty);
1641
}
1642
 
1643
static void isicom_hangup(struct tty_struct * tty)
1644
{
1645
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1646
 
1647
        if (isicom_paranoia_check(port, tty->device, "isicom_hangup"))
1648
                return;
1649
 
1650
        isicom_shutdown_port(port);
1651
        port->count = 0;
1652
        port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
1653
        port->tty = 0;
1654
        wake_up_interruptible(&port->open_wait);
1655
}
1656
 
1657
/* flush_buffer et all */
1658
static void isicom_flush_buffer(struct tty_struct * tty)
1659
{
1660
        struct isi_port * port = (struct isi_port *) tty->driver_data;
1661
        unsigned long flags;
1662
 
1663
        if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer"))
1664
                return;
1665
 
1666
        save_flags(flags); cli();
1667
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1668
        restore_flags(flags);
1669
 
1670
        wake_up_interruptible(&tty->write_wait);
1671
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1672
            tty->ldisc.write_wakeup)
1673
                (tty->ldisc.write_wakeup)(tty);
1674
}
1675
 
1676
 
1677
static int register_ioregion(void)
1678
{
1679
        int count, done=0;
1680
        for (count=0; count < BOARD_COUNT; count++ ) {
1681
                if (isi_card[count].base) {
1682
                        if (check_region(isi_card[count].base,16)) {
1683
                                printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n",
1684
                                        isi_card[count].base,isi_card[count].base+15,count+1);
1685
                                isi_card[count].base=0;
1686
                        }
1687
                        else {
1688
                                request_region(isi_card[count].base,16,ISICOM_NAME);
1689
#ifdef ISICOM_DEBUG                             
1690
                                printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);
1691
#endif                          
1692
                                done++;
1693
                        }
1694
                }
1695
        }
1696
        return done;
1697
}
1698
 
1699
static void unregister_ioregion(void)
1700
{
1701
        int count;
1702
        for (count=0; count < BOARD_COUNT; count++ )
1703
                if (isi_card[count].base) {
1704
                        release_region(isi_card[count].base,16);
1705
#ifdef ISICOM_DEBUG                     
1706
                        printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);
1707
#endif                  
1708
                }
1709
}
1710
 
1711
static int register_drivers(void)
1712
{
1713
        int error;
1714
 
1715
        /* tty driver structure initialization */
1716
        memset(&isicom_normal, 0, sizeof(struct tty_driver));
1717
        isicom_normal.magic     = TTY_DRIVER_MAGIC;
1718
        isicom_normal.name      = "ttyM";
1719
        isicom_normal.major     = ISICOM_NMAJOR;
1720
        isicom_normal.minor_start       = 0;
1721
        isicom_normal.num       = PORT_COUNT;
1722
        isicom_normal.type      = TTY_DRIVER_TYPE_SERIAL;
1723
        isicom_normal.subtype   = SERIAL_TYPE_NORMAL;
1724
        isicom_normal.init_termios      = tty_std_termios;
1725
        isicom_normal.init_termios.c_cflag      =
1726
                                B9600 | CS8 | CREAD | HUPCL |CLOCAL;
1727
        isicom_normal.flags     = TTY_DRIVER_REAL_RAW;
1728
        isicom_normal.refcount  = &isicom_refcount;
1729
 
1730
        isicom_normal.table     = isicom_table;
1731
        isicom_normal.termios   = isicom_termios;
1732
        isicom_normal.termios_locked    = isicom_termios_locked;
1733
 
1734
        isicom_normal.open      = isicom_open;
1735
        isicom_normal.close     = isicom_close;
1736
        isicom_normal.write     = isicom_write;
1737
        isicom_normal.put_char  = isicom_put_char;
1738
        isicom_normal.flush_chars       = isicom_flush_chars;
1739
        isicom_normal.write_room        = isicom_write_room;
1740
        isicom_normal.chars_in_buffer   = isicom_chars_in_buffer;
1741
        isicom_normal.ioctl     = isicom_ioctl;
1742
        isicom_normal.set_termios       = isicom_set_termios;
1743
        isicom_normal.throttle  = isicom_throttle;
1744
        isicom_normal.unthrottle        = isicom_unthrottle;
1745
        isicom_normal.stop      = isicom_stop;
1746
        isicom_normal.start     = isicom_start;
1747
        isicom_normal.hangup    = isicom_hangup;
1748
        isicom_normal.flush_buffer      = isicom_flush_buffer;
1749
 
1750
        /*      callout device  */
1751
 
1752
        isicom_callout  = isicom_normal;
1753
        isicom_callout.name     = "cum";
1754
        isicom_callout.major    = ISICOM_CMAJOR;
1755
        isicom_callout.subtype  = SERIAL_TYPE_CALLOUT;
1756
 
1757
        if ((error=tty_register_driver(&isicom_normal))!=0) {
1758
                printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n",
1759
                        error);
1760
                return error;
1761
        }
1762
        if ((error=tty_register_driver(&isicom_callout))!=0) {
1763
                tty_unregister_driver(&isicom_normal);
1764
                printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n",
1765
                        error);
1766
                return error;
1767
        }
1768
        return 0;
1769
}
1770
 
1771
static void unregister_drivers(void)
1772
{
1773
        int error;
1774
        if ((error=tty_unregister_driver(&isicom_callout))!=0)
1775
                printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error);
1776
        if (tty_unregister_driver(&isicom_normal))
1777
                printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error);
1778
}
1779
 
1780
static int register_isr(void)
1781
{
1782
        int count, done=0;
1783
        for (count=0; count < BOARD_COUNT; count++ ) {
1784
                if (isi_card[count].base) {
1785
                        if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) {
1786
                                printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",
1787
                                        isi_card[count].irq, count+1);
1788
                                release_region(isi_card[count].base,16);
1789
                                isi_card[count].base=0;
1790
                        }
1791
                        else {
1792
                                printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n",
1793
                                count+1, isi_card[count].base, isi_card[count].irq);
1794
 
1795
                                irq_to_board[isi_card[count].irq]=&isi_card[count];
1796
                                done++;
1797
                        }
1798
                }
1799
        }
1800
        return done;
1801
}
1802
 
1803
static void unregister_isr(void)
1804
{
1805
        int count;
1806
        for (count=0; count < BOARD_COUNT; count++ )
1807
                if (isi_card[count].base) {
1808
                        free_irq(isi_card[count].irq, NULL);
1809
#ifdef ISICOM_DEBUG                     
1810
                        printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);
1811
#endif                  
1812
                }
1813
}
1814
 
1815
static int isicom_init(void)
1816
{
1817
        int card, channel, base;
1818
        struct isi_port * port;
1819
        unsigned long page;
1820
 
1821
        if (!tmp_buf) {
1822
                page = get_free_page(GFP_KERNEL);
1823
                if (!page) {
1824
#ifdef ISICOM_DEBUG             
1825
                        printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");
1826
#else
1827
                        printk(KERN_ERR "ISICOM: Not enough memory...\n");
1828
#endif        
1829
                        return 0;
1830
                }
1831
                tmp_buf = (unsigned char *) page;
1832
        }
1833
 
1834
        if (!register_ioregion())
1835
        {
1836
                printk(KERN_ERR "ISICOM: All required I/O space found busy.\n");
1837
                free_page((unsigned long)tmp_buf);
1838
                return 0;
1839
        }
1840
        if (register_drivers())
1841
        {
1842
                unregister_ioregion();
1843
                free_page((unsigned long)tmp_buf);
1844
                return 0;
1845
        }
1846
        if (!register_isr())
1847
        {
1848
                unregister_drivers();
1849
                /*  ioports already uregistered in register_isr */
1850
                free_page((unsigned long)tmp_buf);
1851
                return 0;
1852
        }
1853
 
1854
        /* initialize bottom half  */
1855
        init_bh(ISICOM_BH, do_isicom_bh);
1856
 
1857
 
1858
        memset(isi_ports, 0, sizeof(isi_ports));
1859
        for (card = 0; card < BOARD_COUNT; card++) {
1860
                port = &isi_ports[card * 16];
1861
                isi_card[card].ports = port;
1862
                base = isi_card[card].base;
1863
                for (channel = 0; channel < 16; channel++, port++) {
1864
                        port->magic = ISICOM_MAGIC;
1865
                        port->card = &isi_card[card];
1866
                        port->channel = channel;
1867
                        port->normal_termios = isicom_normal.init_termios;
1868
                        port->callout_termios = isicom_callout.init_termios;
1869
                        port->close_delay = 50 * HZ/100;
1870
                        port->closing_wait = 3000 * HZ/100;
1871
                        port->hangup_tq.routine = do_isicom_hangup;
1872
                        port->hangup_tq.data = port;
1873
                        port->bh_tqueue.routine = isicom_bottomhalf;
1874
                        port->bh_tqueue.data = port;
1875
                        port->status = 0;
1876
 
1877
                        /*  . . .  */
1878
                }
1879
        }
1880
 
1881
        return 1;
1882
}
1883
 
1884
/*
1885
 *      Insmod can set static symbols so keep these static
1886
 */
1887
 
1888
static int ISIBase1=0, ISIBase2=0, ISIBase3=0, ISIBase4=0;
1889
static int Irq1=0, Irq2=0, Irq3=0, Irq4=0;
1890
 
1891
int init_module(void)
1892
{
1893
        int retval, card;
1894
 
1895
        isi_card[0].base=ISIBase1;
1896
        isi_card[1].base=ISIBase2;
1897
        isi_card[2].base=ISIBase3;
1898
        isi_card[3].base=ISIBase4;
1899
 
1900
        isi_card[0].irq=Irq1;
1901
        isi_card[1].irq=Irq2;
1902
        isi_card[2].irq=Irq3;
1903
        isi_card[3].irq=Irq4;
1904
 
1905
        for (card=0 ;card < BOARD_COUNT; card++) {
1906
                if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)||
1907
                    (isi_card[card].irq==4)||(isi_card[card].irq==5)||
1908
                    (isi_card[card].irq==7)||(isi_card[card].irq==10)||
1909
                    (isi_card[card].irq==11)||(isi_card[card].irq==12)||
1910
                    (isi_card[card].irq==15))) {
1911
 
1912
                        if (isi_card[card].base) {
1913
                                printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",
1914
                                        isi_card[card].irq, card+1);
1915
                                isi_card[card].base=0;
1916
                        }
1917
                }
1918
        }
1919
 
1920
        if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {
1921
                printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n");
1922
                return -EIO;
1923
        }
1924
        retval=misc_register(&isiloader_device);
1925
        if (retval<0) {
1926
                printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
1927
                return -EIO;
1928
        }
1929
 
1930
        if (!isicom_init()) {
1931
                if (misc_deregister(&isiloader_device))
1932
                        printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
1933
                return -EIO;
1934
        }
1935
 
1936
        init_timer(&tx);
1937
        tx.expires = jiffies + 1;
1938
        tx.data = 0;
1939
        tx.function = isicom_tx;
1940
        re_schedule = 1;
1941
        add_timer(&tx);
1942
 
1943
        return 0;
1944
}
1945
 
1946
void cleanup_module(void)
1947
{
1948
        re_schedule = 0;
1949
        current->state = TASK_INTERRUPTIBLE;
1950
        current->timeout = jiffies + HZ;
1951
        schedule();
1952
        disable_bh(ISICOM_BH);
1953
 
1954
#ifdef ISICOM_DEBUG     
1955
        printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count);
1956
#endif  
1957
 
1958
#ifdef ISICOM_DEBUG
1959
        printk("ISICOM: uregistering isr ...\n");
1960
#endif  
1961
        unregister_isr();
1962
 
1963
#ifdef ISICOM_DEBUG     
1964
        printk("ISICOM: unregistering drivers ...\n");
1965
#endif
1966
        unregister_drivers();
1967
 
1968
#ifdef ISICOM_DEBUG     
1969
        printk("ISICOM: unregistering ioregion ...\n");
1970
#endif  
1971
        unregister_ioregion();
1972
 
1973
#ifdef ISICOM_DEBUG     
1974
        printk("ISICOM: freeing tmp_buf ...\n");
1975
#endif  
1976
        free_page((unsigned long)tmp_buf);
1977
 
1978
#ifdef ISICOM_DEBUG             
1979
        printk("ISICOM: unregistering firmware loader ...\n");
1980
#endif
1981
        if (misc_deregister(&isiloader_device))
1982
                printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
1983
}

powered by: WebSVN 2.1.0

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