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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acorn/] [scsi/] [eesox.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/acorn/scsi/eesox.c
3
 *
4
 *  Copyright (C) 1997-2003 Russell King
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation.
9
 *
10
 *  This driver is based on experimentation.  Hence, it may have made
11
 *  assumptions about the particular card that I have available, and
12
 *  may not be reliable!
13
 *
14
 *  Changelog:
15
 *   01-10-1997 RMK             Created, READONLY version
16
 *   15-02-1998 RMK             READ/WRITE version
17
 *                              added DMA support and hardware definitions
18
 *   14-03-1998 RMK             Updated DMA support
19
 *                              Added terminator control
20
 *   15-04-1998 RMK             Only do PIO if FAS216 will allow it.
21
 *   27-06-1998 RMK             Changed asm/delay.h to linux/delay.h
22
 *   02-04-2000 RMK     0.0.3   Fixed NO_IRQ/NO_DMA problem, updated for new
23
 *                              error handling code.
24
 */
25
#include <linux/module.h>
26
#include <linux/blk.h>
27
#include <linux/kernel.h>
28
#include <linux/string.h>
29
#include <linux/ioport.h>
30
#include <linux/sched.h>
31
#include <linux/proc_fs.h>
32
#include <linux/delay.h>
33
#include <linux/pci.h>
34
#include <linux/init.h>
35
 
36
#include <asm/io.h>
37
#include <asm/irq.h>
38
#include <asm/dma.h>
39
#include <asm/ecard.h>
40
#include <asm/pgtable.h>
41
 
42
#include "../../scsi/sd.h"
43
#include "../../scsi/hosts.h"
44
#include "fas216.h"
45
#include "scsi.h"
46
 
47
#include <scsi/scsicam.h>
48
 
49
/*
50
 * List of devices that the driver will recognise
51
 */
52
#define EESOXSCSI_LIST  { MANU_EESOX, PROD_EESOX_SCSI2 }
53
 
54
#define EESOX_FAS216_OFFSET     0xc00
55
#define EESOX_FAS216_SHIFT      3
56
 
57
#define EESOX_DMASTAT           0xa00
58
#define EESOX_STAT_INTR         0x01
59
#define EESOX_STAT_DMA          0x02
60
 
61
#define EESOX_CONTROL           0xa00
62
#define EESOX_INTR_ENABLE       0x04
63
#define EESOX_TERM_ENABLE       0x02
64
#define EESOX_RESET             0x01
65
 
66
#define EESOX_DMADATA           0xe00
67
 
68
/*
69
 * Version
70
 */
71
#define VERSION "1.10 (22/01/2003 2.4.19-rmk5)"
72
 
73
/*
74
 * Use term=0,1,0,0,0 to turn terminators on/off
75
 */
76
static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
77
 
78
#define NR_SG   256
79
 
80
struct eesoxscsi_info {
81
        FAS216_Info             info;
82
        struct expansion_card   *ec;
83
 
84
        unsigned int            ctl_port;
85
        unsigned int            control;
86
        struct scatterlist      sg[NR_SG];      /* Scatter DMA list     */
87
};
88
 
89
/* Prototype: void eesoxscsi_irqenable(ec, irqnr)
90
 * Purpose  : Enable interrupts on EESOX SCSI card
91
 * Params   : ec    - expansion card structure
92
 *          : irqnr - interrupt number
93
 */
94
static void
95
eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
96
{
97
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
98
 
99
        info->control |= EESOX_INTR_ENABLE;
100
 
101
        outb(info->control, info->ctl_port);
102
}
103
 
104
/* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
105
 * Purpose  : Disable interrupts on EESOX SCSI card
106
 * Params   : ec    - expansion card structure
107
 *          : irqnr - interrupt number
108
 */
109
static void
110
eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
111
{
112
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
113
 
114
        info->control &= ~EESOX_INTR_ENABLE;
115
 
116
        outb(info->control, info->ctl_port);
117
}
118
 
119
static const expansioncard_ops_t eesoxscsi_ops = {
120
        .irqenable      = eesoxscsi_irqenable,
121
        .irqdisable     = eesoxscsi_irqdisable,
122
};
123
 
124
/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
125
 * Purpose  : Turn the EESOX SCSI terminators on or off
126
 * Params   : host   - card to turn on/off
127
 *          : on_off - !0 to turn on, 0 to turn off
128
 */
129
static void
130
eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
131
{
132
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
133
        unsigned long flags;
134
 
135
        save_flags_cli(flags);
136
        if (on_off)
137
                info->control |= EESOX_TERM_ENABLE;
138
        else
139
                info->control &= ~EESOX_TERM_ENABLE;
140
 
141
        outb(info->control, info->ctl_port);
142
        restore_flags(flags);
143
}
144
 
145
/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
146
 * Purpose  : handle interrupts from EESOX SCSI card
147
 * Params   : irq    - interrupt number
148
 *            dev_id - user-defined (Scsi_Host structure)
149
 *            regs   - processor registers at interrupt
150
 */
151
static void
152
eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
153
{
154
        fas216_intr(dev_id);
155
}
156
 
157
/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
158
 * Purpose  : initialises DMA/PIO
159
 * Params   : host      - host
160
 *            SCpnt     - command
161
 *            direction - DMA on to/off of card
162
 *            min_type  - minimum DMA support that we must have for this transfer
163
 * Returns  : type of transfer to be performed
164
 */
165
static fasdmatype_t
166
eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
167
                       fasdmadir_t direction, fasdmatype_t min_type)
168
{
169
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
170
        int dmach = host->dma_channel;
171
 
172
        if (dmach != NO_DMA &&
173
            (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
174
                int bufs, map_dir, dma_dir;
175
 
176
                bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
177
 
178
                if (direction == DMA_OUT)
179
                        map_dir = PCI_DMA_TODEVICE,
180
                        dma_dir = DMA_MODE_WRITE;
181
                else
182
                        map_dir = PCI_DMA_FROMDEVICE,
183
                        dma_dir = DMA_MODE_READ;
184
 
185
                pci_map_sg(NULL, info->sg, bufs, map_dir);
186
 
187
                disable_dma(dmach);
188
                set_dma_sg(dmach, info->sg, bufs);
189
                set_dma_mode(dmach, dma_dir);
190
                enable_dma(dmach);
191
                return fasdma_real_all;
192
        }
193
        /*
194
         * We don't do DMA, we only do slow PIO
195
         *
196
         * Some day, we will do Pseudo DMA
197
         */
198
        return fasdma_pseudo;
199
}
200
 
201
static void eesoxscsi_buffer_in(void *buf, int length, unsigned long base)
202
{
203
        const unsigned long reg_fas = base + EESOX_FAS216_OFFSET;
204
        const unsigned long reg_dmastat = base + EESOX_DMASTAT;
205
        const unsigned long reg_dmadata = base + EESOX_DMADATA;
206
 
207
        do {
208
                unsigned int status;
209
 
210
                /*
211
                 * Interrupt request?
212
                 */
213
                status = inb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
214
                if (status & STAT_INT)
215
                        break;
216
 
217
                /*
218
                 * DMA request active?
219
                 */
220
                status = inb(reg_dmastat);
221
                if (!(status & EESOX_STAT_DMA))
222
                        continue;
223
 
224
                /*
225
                 * Get number of bytes in FIFO
226
                 */
227
                status = inb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
228
                if (status > 16)
229
                        status = 16;
230
                if (status > length)
231
                        status = length;
232
 
233
                /*
234
                 * Align buffer.
235
                 */
236
                if (((u32)buf) & 2 && status >= 2) {
237
                        *((u16 *)buf)++ = inw(reg_dmadata);
238
                        status -= 2;
239
                        length -= 2;
240
                }
241
 
242
                if (status >= 8) {
243
                        unsigned long l1, l2;
244
 
245
                        l1 = inw(reg_dmadata);
246
                        l1 |= inw(reg_dmadata) << 16;
247
                        l2 = inw(reg_dmadata);
248
                        l2 |= inw(reg_dmadata) << 16;
249
                        *((u32 *)buf)++ = l1;
250
                        *((u32 *)buf)++ = l2;
251
                        length -= 8;
252
                        continue;
253
                }
254
 
255
                if (status >= 4) {
256
                        unsigned long l1;
257
 
258
                        l1 = inw(reg_dmadata);
259
                        l1 |= inw(reg_dmadata) << 16;
260
                        *((u32 *)buf)++ = l1;
261
                        length -= 4;
262
                        continue;
263
                }
264
 
265
                if (status >= 2) {
266
                        *((u16 *)buf)++ = inw(reg_dmadata);
267
                        length -= 2;
268
                }
269
        } while (length);
270
}
271
 
272
static void eesoxscsi_buffer_out(void *buf, int length, unsigned long base)
273
{
274
        const unsigned long reg_fas = base + EESOX_FAS216_OFFSET;
275
        const unsigned long reg_dmastat = base + EESOX_DMASTAT;
276
        const unsigned long reg_dmadata = base + EESOX_DMADATA;
277
 
278
        do {
279
                unsigned int status;
280
 
281
                /*
282
                 * Interrupt request?
283
                 */
284
                status = inb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
285
                if (status & STAT_INT)
286
                        break;
287
 
288
                /*
289
                 * DMA request active?
290
                 */
291
                status = inb(reg_dmastat);
292
                if (!(status & EESOX_STAT_DMA))
293
                        continue;
294
 
295
                /*
296
                 * Get number of bytes in FIFO
297
                 */
298
                status = inb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
299
                if (status > 16)
300
                        status = 16;
301
                status = 16 - status;
302
                if (status > length)
303
                        status = length;
304
 
305
                /*
306
                 * Align buffer.
307
                 */
308
                if (((u32)buf) & 2 && status >= 2) {
309
                        outw(*((u16 *)buf)++, reg_dmadata);
310
                        status -= 2;
311
                        length -= 2;
312
                }
313
 
314
                if (status >= 8) {
315
                        unsigned long l1, l2;
316
 
317
                        l1 = *((u32 *)buf)++;
318
                        l2 = *((u32 *)buf)++;
319
 
320
                        outw(l1, reg_dmadata);
321
                        outw(l1 >> 16, reg_dmadata);
322
                        outw(l2, reg_dmadata);
323
                        outw(l2 >> 16, reg_dmadata);
324
                        status -= 8;
325
                        length -= 8;
326
                        continue;
327
                }
328
 
329
                if (status >= 4) {
330
                        unsigned long l1;
331
 
332
                        l1 = *((u32 *)buf)++;
333
                        outw(l1, reg_dmadata);
334
                        outw(l1 >> 16, reg_dmadata);
335
                        status -= 4;
336
                        length -= 4;
337
                        continue;
338
                }
339
 
340
                if (status >= 2) {
341
                        outw(*((u16 *)buf)++, reg_dmadata);
342
                        length -= 2;
343
                }
344
        } while (length);
345
}
346
 
347
static void
348
eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
349
                     fasdmadir_t dir, int transfer_size)
350
{
351
        unsigned int base = host->io_port;
352
        if (dir == DMA_IN) {
353
                eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, base);
354
        } else {
355
                eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, base);
356
        }
357
}
358
 
359
/* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
360
 * Purpose  : stops DMA/PIO
361
 * Params   : host  - host
362
 *            SCpnt - command
363
 */
364
static void
365
eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
366
{
367
        if (host->dma_channel != NO_DMA)
368
                disable_dma(host->dma_channel);
369
}
370
 
371
/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
372
 * Purpose  : returns a descriptive string about this interface,
373
 * Params   : host - driver host structure to return info for.
374
 * Returns  : pointer to a static buffer containing null terminated string.
375
 */
376
const char *eesoxscsi_info(struct Scsi_Host *host)
377
{
378
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
379
        static char string[150];
380
 
381
        sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
382
                host->hostt->name, info->info.scsi.type, info->ec->slot_no,
383
                VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
384
 
385
        return string;
386
}
387
 
388
/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
389
 * Purpose  : Set a driver specific function
390
 * Params   : host   - host to setup
391
 *          : buffer - buffer containing string describing operation
392
 *          : length - length of string
393
 * Returns  : -EINVAL, or 0
394
 */
395
static int
396
eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
397
{
398
        int ret = length;
399
 
400
        if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
401
                buffer += 9;
402
                length -= 9;
403
 
404
                if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
405
                        if (buffer[5] == '1')
406
                                eesoxscsi_terminator_ctl(host, 1);
407
                        else if (buffer[5] == '0')
408
                                eesoxscsi_terminator_ctl(host, 0);
409
                        else
410
                                ret = -EINVAL;
411
                } else
412
                        ret = -EINVAL;
413
        } else
414
                ret = -EINVAL;
415
 
416
        return ret;
417
}
418
 
419
/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
420
 *                                    int length, int host_no, int inout)
421
 * Purpose  : Return information about the driver to a user process accessing
422
 *            the /proc filesystem.
423
 * Params   : buffer - a buffer to write information to
424
 *            start  - a pointer into this buffer set by this routine to the start
425
 *                     of the required information.
426
 *            offset - offset into information that we have read upto.
427
 *            length - length of buffer
428
 *            host_no - host number to return information for
429
 *            inout  - 0 for reading, 1 for writing.
430
 * Returns  : length of data written to buffer.
431
 */
432
int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
433
                            int length, int host_no, int inout)
434
{
435
        int pos, begin;
436
        struct Scsi_Host *host;
437
        struct eesoxscsi_info *info;
438
        Scsi_Device *scd;
439
 
440
        host = scsi_host_hn_get(host_no);
441
        if (!host)
442
                return 0;
443
 
444
        if (inout == 1)
445
                return eesoxscsi_set_proc_info(host, buffer, length);
446
 
447
        info = (struct eesoxscsi_info *)host->hostdata;
448
 
449
        begin = 0;
450
        pos = sprintf(buffer, "EESOX SCSI driver v%s\n", VERSION);
451
        pos += fas216_print_host(&info->info, buffer + pos);
452
        pos += sprintf(buffer + pos, "Term    : o%s\n",
453
                        info->control & EESOX_TERM_ENABLE ? "n" : "ff");
454
 
455
        pos += fas216_print_stats(&info->info, buffer + pos);
456
 
457
        pos += sprintf(buffer+pos, "\nAttached devices:\n");
458
 
459
        for (scd = host->host_queue; scd; scd = scd->next) {
460
                int len;
461
 
462
                proc_print_scsidevice(scd, buffer, &len, pos);
463
                pos += len;
464
                pos += sprintf(buffer+pos, "Extensions: ");
465
                if (scd->tagged_supported)
466
                        pos += sprintf(buffer+pos, "TAG %sabled [%d] ",
467
                                        scd->tagged_queue ? "en" : "dis",
468
                                        scd->current_tag);
469
                pos += sprintf (buffer+pos, "\n");
470
 
471
                if (pos + begin < offset) {
472
                        begin += pos;
473
                        pos = 0;
474
                }
475
        }
476
        *start = buffer + (offset - begin);
477
        pos -= offset - begin;
478
        if (pos > length)
479
                pos = length;
480
 
481
        return pos;
482
}
483
 
484
static int eesoxscsi_probe(struct expansion_card *ec);
485
 
486
/* Prototype: int eesoxscsi_detect(Scsi_Host_Template * tpnt)
487
 * Purpose  : initialises EESOX SCSI driver
488
 * Params   : tpnt - template for this SCSI adapter
489
 * Returns  : >0 if host found, 0 otherwise.
490
 */
491
static int eesoxscsi_detect(Scsi_Host_Template *tpnt)
492
{
493
        static const card_ids eesoxscsi_cids[] =
494
                        { EESOXSCSI_LIST, { 0xffff, 0xffff} };
495
        struct expansion_card *ec;
496
        int count = 0, ret;
497
 
498
        ecard_startfind();
499
 
500
        while(1) {
501
                ec = ecard_find(0, eesoxscsi_cids);
502
                if (!ec)
503
                        break;
504
 
505
                ecard_claim(ec);
506
 
507
                ret = eesoxscsi_probe(ec);
508
                if (ret) {
509
                        ecard_release(ec);
510
                        break;
511
                }
512
                ++count;
513
        }
514
        return count;
515
}
516
 
517
static void eesoxscsi_remove(struct Scsi_Host *host);
518
 
519
/* Prototype: int eesoxscsi_release(struct Scsi_Host * host)
520
 * Purpose  : releases all resources used by this adapter
521
 * Params   : host - driver host structure to return info for.
522
 */
523
static int eesoxscsi_release(struct Scsi_Host *host)
524
{
525
        eesoxscsi_remove(host);
526
        return 0;
527
}
528
 
529
static Scsi_Host_Template eesox_template = {
530
        .module                         = THIS_MODULE,
531
        .proc_info                      = eesoxscsi_proc_info,
532
        .name                           = "EESOX SCSI",
533
        .detect                         = eesoxscsi_detect,
534
        .release                        = eesoxscsi_release,
535
        .info                           = eesoxscsi_info,
536
        .bios_param                     = scsicam_bios_param,
537
        .command                        = fas216_command,
538
        .queuecommand                   = fas216_queue_command,
539
        .eh_host_reset_handler          = fas216_eh_host_reset,
540
        .eh_bus_reset_handler           = fas216_eh_bus_reset,
541
        .eh_device_reset_handler        = fas216_eh_device_reset,
542
        .eh_abort_handler               = fas216_eh_abort,
543
        .use_new_eh_code                = 1,
544
 
545
        .can_queue                      = 1,
546
        .this_id                        = 7,
547
        .sg_tablesize                   = SG_ALL,
548
        .cmd_per_lun                    = 1,
549
        .use_clustering                 = DISABLE_CLUSTERING,
550
        .proc_name                      = "eesox",
551
};
552
 
553
static int
554
eesoxscsi_probe(struct expansion_card *ec)
555
{
556
        struct Scsi_Host *host;
557
        struct eesoxscsi_info *info;
558
        unsigned long base;
559
        int ret;
560
 
561
        base = ecard_address(ec, ECARD_IOC, ECARD_FAST);
562
 
563
        if (!request_region(base + EESOX_FAS216_OFFSET,
564
                            16 << EESOX_FAS216_SHIFT, "eesox2-fas")) {
565
                ret = -EBUSY;
566
                goto out;
567
        }
568
 
569
        host = scsi_register(&eesox_template,
570
                             sizeof(struct eesoxscsi_info));
571
        if (!host) {
572
                ret = -ENOMEM;
573
                goto out_region;
574
        }
575
 
576
        host->io_port     = base;
577
        host->irq         = ec->irq;
578
        host->dma_channel = ec->dma;
579
 
580
        info = (struct eesoxscsi_info *)host->hostdata;
581
        info->ec        = ec;
582
        info->ctl_port  = base + EESOX_CONTROL;
583
        info->control   = term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
584
        outb(info->control, info->ctl_port);
585
 
586
        ec->irqaddr     = (unsigned char *)ioaddr(base + EESOX_DMASTAT);
587
        ec->irqmask     = EESOX_STAT_INTR;
588
        ec->irq_data    = info;
589
        ec->ops         = (expansioncard_ops_t *)&eesoxscsi_ops;
590
 
591
        info->info.scsi.io_port         = base + EESOX_FAS216_OFFSET;
592
        info->info.scsi.io_shift        = EESOX_FAS216_SHIFT;
593
        info->info.scsi.irq             = host->irq;
594
        info->info.ifcfg.clockrate      = 40; /* MHz */
595
        info->info.ifcfg.select_timeout = 255;
596
        info->info.ifcfg.asyncperiod    = 200; /* ns */
597
        info->info.ifcfg.sync_max_depth = 7;
598
        info->info.ifcfg.cntl3          = CNTL3_FASTSCSI | CNTL3_FASTCLK;
599
        info->info.ifcfg.disconnect_ok  = 1;
600
        info->info.ifcfg.wide_max_size  = 0;
601
        info->info.ifcfg.capabilities   = FASCAP_PSEUDODMA;
602
        info->info.dma.setup            = eesoxscsi_dma_setup;
603
        info->info.dma.pseudo           = eesoxscsi_dma_pseudo;
604
        info->info.dma.stop             = eesoxscsi_dma_stop;
605
 
606
        ret = fas216_init(host);
607
        if (ret)
608
                goto out_free;
609
 
610
        ret = request_irq(host->irq, eesoxscsi_intr, 0, "eesox", &info->info);
611
        if (ret) {
612
                printk("scsi%d: IRQ%d not free: %d\n",
613
                       host->host_no, host->irq, ret);
614
                goto out_remove;
615
        }
616
 
617
        if (host->dma_channel != NO_DMA) {
618
                if (request_dma(host->dma_channel, "eesox")) {
619
                        printk("scsi%d: DMA%d not free, DMA disabled\n",
620
                               host->host_no, host->dma_channel);
621
                        host->dma_channel = NO_DMA;
622
                } else {
623
                        set_dma_speed(host->dma_channel, 180);
624
                        info->info.ifcfg.capabilities |= FASCAP_DMA;
625
                        info->info.ifcfg.cntl3 |= CNTL3_BS8;
626
                }
627
        }
628
 
629
        ret = fas216_add(host);
630
        if (ret == 0)
631
                goto out;
632
 
633
        if (host->dma_channel != NO_DMA)
634
                free_dma(host->dma_channel);
635
        free_irq(host->irq, host);
636
 
637
 out_remove:
638
        fas216_remove(host);
639
 
640
 out_free:
641
        scsi_unregister(host);
642
 
643
 out_region:
644
        release_region(base + EESOX_FAS216_OFFSET, 16 << EESOX_FAS216_SHIFT);
645
 
646
 out:
647
        return ret;
648
}
649
 
650
static void eesoxscsi_remove(struct Scsi_Host *host)
651
{
652
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
653
 
654
        fas216_remove(host);
655
 
656
        if (host->dma_channel != NO_DMA)
657
                free_dma(host->dma_channel);
658
        free_irq(host->irq, host);
659
 
660
        release_region(host->io_port + EESOX_FAS216_OFFSET, 16 << EESOX_FAS216_SHIFT);
661
 
662
        fas216_release(host);
663
        ecard_release(info->ec);
664
}
665
 
666
static int __init eesox_init(void)
667
{
668
        scsi_register_module(MODULE_SCSI_HA, &eesox_template);
669
        if (eesox_template.present)
670
                return 0;
671
 
672
        scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
673
        return -ENODEV;
674
}
675
 
676
static void __exit eesox_exit(void)
677
{
678
        scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
679
}
680
 
681
module_init(eesox_init);
682
module_exit(eesox_exit);
683
 
684
MODULE_AUTHOR("Russell King");
685
MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
686
MODULE_PARM(term, "1-8i");
687
MODULE_PARM_DESC(term, "SCSI bus termination");
688
MODULE_LICENSE("GPL");
689
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

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