linux/drivers/scsi/arm/eesox.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/acorn/scsi/eesox.c
   3 *
   4 *  Copyright (C) 1997-2005 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/blkdev.h>
  27#include <linux/kernel.h>
  28#include <linux/string.h>
  29#include <linux/ioport.h>
  30#include <linux/proc_fs.h>
  31#include <linux/delay.h>
  32#include <linux/interrupt.h>
  33#include <linux/init.h>
  34#include <linux/dma-mapping.h>
  35
  36#include <asm/io.h>
  37#include <asm/dma.h>
  38#include <asm/ecard.h>
  39#include <asm/pgtable.h>
  40
  41#include "../scsi.h"
  42#include <scsi/scsi_host.h>
  43#include "fas216.h"
  44#include "scsi.h"
  45
  46#include <scsi/scsicam.h>
  47
  48#define EESOX_FAS216_OFFSET     0x3000
  49#define EESOX_FAS216_SHIFT      5
  50
  51#define EESOX_DMASTAT           0x2800
  52#define EESOX_STAT_INTR         0x01
  53#define EESOX_STAT_DMA          0x02
  54
  55#define EESOX_CONTROL           0x2800
  56#define EESOX_INTR_ENABLE       0x04
  57#define EESOX_TERM_ENABLE       0x02
  58#define EESOX_RESET             0x01
  59
  60#define EESOX_DMADATA           0x3800
  61
  62#define VERSION "1.10 (17/01/2003 2.5.59)"
  63
  64/*
  65 * Use term=0,1,0,0,0 to turn terminators on/off
  66 */
  67static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
  68
  69#define NR_SG   256
  70
  71struct eesoxscsi_info {
  72        FAS216_Info             info;
  73        struct expansion_card   *ec;
  74        void __iomem            *base;
  75        void __iomem            *ctl_port;
  76        unsigned int            control;
  77        struct scatterlist      sg[NR_SG];      /* Scatter DMA list     */
  78};
  79
  80/* Prototype: void eesoxscsi_irqenable(ec, irqnr)
  81 * Purpose  : Enable interrupts on EESOX SCSI card
  82 * Params   : ec    - expansion card structure
  83 *          : irqnr - interrupt number
  84 */
  85static void
  86eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
  87{
  88        struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
  89
  90        info->control |= EESOX_INTR_ENABLE;
  91
  92        writeb(info->control, info->ctl_port);
  93}
  94
  95/* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
  96 * Purpose  : Disable interrupts on EESOX SCSI card
  97 * Params   : ec    - expansion card structure
  98 *          : irqnr - interrupt number
  99 */
 100static void
 101eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
 102{
 103        struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
 104
 105        info->control &= ~EESOX_INTR_ENABLE;
 106
 107        writeb(info->control, info->ctl_port);
 108}
 109
 110static const expansioncard_ops_t eesoxscsi_ops = {
 111        .irqenable      = eesoxscsi_irqenable,
 112        .irqdisable     = eesoxscsi_irqdisable,
 113};
 114
 115/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
 116 * Purpose  : Turn the EESOX SCSI terminators on or off
 117 * Params   : host   - card to turn on/off
 118 *          : on_off - !0 to turn on, 0 to turn off
 119 */
 120static void
 121eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
 122{
 123        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 124        unsigned long flags;
 125
 126        spin_lock_irqsave(host->host_lock, flags);
 127        if (on_off)
 128                info->control |= EESOX_TERM_ENABLE;
 129        else
 130                info->control &= ~EESOX_TERM_ENABLE;
 131
 132        writeb(info->control, info->ctl_port);
 133        spin_unlock_irqrestore(host->host_lock, flags);
 134}
 135
 136/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
 137 * Purpose  : handle interrupts from EESOX SCSI card
 138 * Params   : irq    - interrupt number
 139 *            dev_id - user-defined (Scsi_Host structure)
 140 */
 141static irqreturn_t
 142eesoxscsi_intr(int irq, void *dev_id)
 143{
 144        struct eesoxscsi_info *info = dev_id;
 145
 146        return fas216_intr(&info->info);
 147}
 148
 149/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
 150 * Purpose  : initialises DMA/PIO
 151 * Params   : host      - host
 152 *            SCpnt     - command
 153 *            direction - DMA on to/off of card
 154 *            min_type  - minimum DMA support that we must have for this transfer
 155 * Returns  : type of transfer to be performed
 156 */
 157static fasdmatype_t
 158eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
 159                       fasdmadir_t direction, fasdmatype_t min_type)
 160{
 161        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 162        struct device *dev = scsi_get_device(host);
 163        int dmach = info->info.scsi.dma;
 164
 165        if (dmach != NO_DMA &&
 166            (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
 167                int bufs, map_dir, dma_dir;
 168
 169                bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
 170
 171                if (direction == DMA_OUT)
 172                        map_dir = DMA_TO_DEVICE,
 173                        dma_dir = DMA_MODE_WRITE;
 174                else
 175                        map_dir = DMA_FROM_DEVICE,
 176                        dma_dir = DMA_MODE_READ;
 177
 178                dma_map_sg(dev, info->sg, bufs, map_dir);
 179
 180                disable_dma(dmach);
 181                set_dma_sg(dmach, info->sg, bufs);
 182                set_dma_mode(dmach, dma_dir);
 183                enable_dma(dmach);
 184                return fasdma_real_all;
 185        }
 186        /*
 187         * We don't do DMA, we only do slow PIO
 188         *
 189         * Some day, we will do Pseudo DMA
 190         */
 191        return fasdma_pseudo;
 192}
 193
 194static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base)
 195{
 196        const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
 197        const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
 198        const void __iomem *reg_dmadata = base + EESOX_DMADATA;
 199        register const unsigned long mask = 0xffff;
 200
 201        do {
 202                unsigned int status;
 203
 204                /*
 205                 * Interrupt request?
 206                 */
 207                status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
 208                if (status & STAT_INT)
 209                        break;
 210
 211                /*
 212                 * DMA request active?
 213                 */
 214                status = readb(reg_dmastat);
 215                if (!(status & EESOX_STAT_DMA))
 216                        continue;
 217
 218                /*
 219                 * Get number of bytes in FIFO
 220                 */
 221                status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
 222                if (status > 16)
 223                        status = 16;
 224                if (status > length)
 225                        status = length;
 226
 227                /*
 228                 * Align buffer.
 229                 */
 230                if (((u32)buf) & 2 && status >= 2) {
 231                        *(u16 *)buf = readl(reg_dmadata);
 232                        buf += 2;
 233                        status -= 2;
 234                        length -= 2;
 235                }
 236
 237                if (status >= 8) {
 238                        unsigned long l1, l2;
 239
 240                        l1 = readl(reg_dmadata) & mask;
 241                        l1 |= readl(reg_dmadata) << 16;
 242                        l2 = readl(reg_dmadata) & mask;
 243                        l2 |= readl(reg_dmadata) << 16;
 244                        *(u32 *)buf = l1;
 245                        buf += 4;
 246                        *(u32 *)buf = l2;
 247                        buf += 4;
 248                        length -= 8;
 249                        continue;
 250                }
 251
 252                if (status >= 4) {
 253                        unsigned long l1;
 254
 255                        l1 = readl(reg_dmadata) & mask;
 256                        l1 |= readl(reg_dmadata) << 16;
 257
 258                        *(u32 *)buf = l1;
 259                        buf += 4;
 260                        length -= 4;
 261                        continue;
 262                }
 263
 264                if (status >= 2) {
 265                        *(u16 *)buf = readl(reg_dmadata);
 266                        buf += 2;
 267                        length -= 2;
 268                }
 269        } while (length);
 270}
 271
 272static void eesoxscsi_buffer_out(void *buf, int length, void __iomem *base)
 273{
 274        const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
 275        const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
 276        const void __iomem *reg_dmadata = base + EESOX_DMADATA;
 277
 278        do {
 279                unsigned int status;
 280
 281                /*
 282                 * Interrupt request?
 283                 */
 284                status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
 285                if (status & STAT_INT)
 286                        break;
 287
 288                /*
 289                 * DMA request active?
 290                 */
 291                status = readb(reg_dmastat);
 292                if (!(status & EESOX_STAT_DMA))
 293                        continue;
 294
 295                /*
 296                 * Get number of bytes in FIFO
 297                 */
 298                status = readb(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                status &= ~1;
 305
 306                /*
 307                 * Align buffer.
 308                 */
 309                if (((u32)buf) & 2 && status >= 2) {
 310                        writel(*(u16 *)buf << 16, reg_dmadata);
 311                        buf += 2;
 312                        status -= 2;
 313                        length -= 2;
 314                }
 315
 316                if (status >= 8) {
 317                        unsigned long l1, l2;
 318
 319                        l1 = *(u32 *)buf;
 320                        buf += 4;
 321                        l2 = *(u32 *)buf;
 322                        buf += 4;
 323
 324                        writel(l1 << 16, reg_dmadata);
 325                        writel(l1, reg_dmadata);
 326                        writel(l2 << 16, reg_dmadata);
 327                        writel(l2, reg_dmadata);
 328                        length -= 8;
 329                        continue;
 330                }
 331
 332                if (status >= 4) {
 333                        unsigned long l1;
 334
 335                        l1 = *(u32 *)buf;
 336                        buf += 4;
 337
 338                        writel(l1 << 16, reg_dmadata);
 339                        writel(l1, reg_dmadata);
 340                        length -= 4;
 341                        continue;
 342                }
 343
 344                if (status >= 2) {
 345                        writel(*(u16 *)buf << 16, reg_dmadata);
 346                        buf += 2;
 347                        length -= 2;
 348                }
 349        } while (length);
 350}
 351
 352static void
 353eesoxscsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
 354                     fasdmadir_t dir, int transfer_size)
 355{
 356        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 357        if (dir == DMA_IN) {
 358                eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, info->base);
 359        } else {
 360                eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, info->base);
 361        }
 362}
 363
 364/* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
 365 * Purpose  : stops DMA/PIO
 366 * Params   : host  - host
 367 *            SCpnt - command
 368 */
 369static void
 370eesoxscsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
 371{
 372        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 373        if (info->info.scsi.dma != NO_DMA)
 374                disable_dma(info->info.scsi.dma);
 375}
 376
 377/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
 378 * Purpose  : returns a descriptive string about this interface,
 379 * Params   : host - driver host structure to return info for.
 380 * Returns  : pointer to a static buffer containing null terminated string.
 381 */
 382const char *eesoxscsi_info(struct Scsi_Host *host)
 383{
 384        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 385        static char string[150];
 386
 387        sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
 388                host->hostt->name, info->info.scsi.type, info->ec->slot_no,
 389                VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
 390
 391        return string;
 392}
 393
 394/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
 395 * Purpose  : Set a driver specific function
 396 * Params   : host   - host to setup
 397 *          : buffer - buffer containing string describing operation
 398 *          : length - length of string
 399 * Returns  : -EINVAL, or 0
 400 */
 401static int
 402eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
 403{
 404        int ret = length;
 405
 406        if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
 407                buffer += 9;
 408                length -= 9;
 409
 410                if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
 411                        if (buffer[5] == '1')
 412                                eesoxscsi_terminator_ctl(host, 1);
 413                        else if (buffer[5] == '0')
 414                                eesoxscsi_terminator_ctl(host, 0);
 415                        else
 416                                ret = -EINVAL;
 417                } else
 418                        ret = -EINVAL;
 419        } else
 420                ret = -EINVAL;
 421
 422        return ret;
 423}
 424
 425/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
 426 *                                    int length, int host_no, int inout)
 427 * Purpose  : Return information about the driver to a user process accessing
 428 *            the /proc filesystem.
 429 * Params   : buffer - a buffer to write information to
 430 *            start  - a pointer into this buffer set by this routine to the start
 431 *                     of the required information.
 432 *            offset - offset into information that we have read up to.
 433 *            length - length of buffer
 434 *            host_no - host number to return information for
 435 *            inout  - 0 for reading, 1 for writing.
 436 * Returns  : length of data written to buffer.
 437 */
 438int eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
 439                            int length, int inout)
 440{
 441        struct eesoxscsi_info *info;
 442        char *p = buffer;
 443        int pos;
 444
 445        if (inout == 1)
 446                return eesoxscsi_set_proc_info(host, buffer, length);
 447
 448        info = (struct eesoxscsi_info *)host->hostdata;
 449
 450        p += sprintf(p, "EESOX SCSI driver v%s\n", VERSION);
 451        p += fas216_print_host(&info->info, p);
 452        p += sprintf(p, "Term    : o%s\n",
 453                        info->control & EESOX_TERM_ENABLE ? "n" : "ff");
 454
 455        p += fas216_print_stats(&info->info, p);
 456        p += fas216_print_devices(&info->info, p);
 457
 458        *start = buffer + offset;
 459        pos = p - buffer - offset;
 460        if (pos > length)
 461                pos = length;
 462
 463        return pos;
 464}
 465
 466static ssize_t eesoxscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf)
 467{
 468        struct expansion_card *ec = ECARD_DEV(dev);
 469        struct Scsi_Host *host = ecard_get_drvdata(ec);
 470        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 471
 472        return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0);
 473}
 474
 475static ssize_t eesoxscsi_store_term(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
 476{
 477        struct expansion_card *ec = ECARD_DEV(dev);
 478        struct Scsi_Host *host = ecard_get_drvdata(ec);
 479        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 480        unsigned long flags;
 481
 482        if (len > 1) {
 483                spin_lock_irqsave(host->host_lock, flags);
 484                if (buf[0] != '0') {
 485                        info->control |= EESOX_TERM_ENABLE;
 486                } else {
 487                        info->control &= ~EESOX_TERM_ENABLE;
 488                }
 489                writeb(info->control, info->ctl_port);
 490                spin_unlock_irqrestore(host->host_lock, flags);
 491        }
 492
 493        return len;
 494}
 495
 496static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
 497                   eesoxscsi_show_term, eesoxscsi_store_term);
 498
 499static struct scsi_host_template eesox_template = {
 500        .module                         = THIS_MODULE,
 501        .proc_info                      = eesoxscsi_proc_info,
 502        .name                           = "EESOX SCSI",
 503        .info                           = eesoxscsi_info,
 504        .queuecommand                   = fas216_queue_command,
 505        .eh_host_reset_handler          = fas216_eh_host_reset,
 506        .eh_bus_reset_handler           = fas216_eh_bus_reset,
 507        .eh_device_reset_handler        = fas216_eh_device_reset,
 508        .eh_abort_handler               = fas216_eh_abort,
 509        .can_queue                      = 1,
 510        .this_id                        = 7,
 511        .sg_tablesize                   = SCSI_MAX_SG_CHAIN_SEGMENTS,
 512        .dma_boundary                   = IOMD_DMA_BOUNDARY,
 513        .cmd_per_lun                    = 1,
 514        .use_clustering                 = DISABLE_CLUSTERING,
 515        .proc_name                      = "eesox",
 516};
 517
 518static int __devinit
 519eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 520{
 521        struct Scsi_Host *host;
 522        struct eesoxscsi_info *info;
 523        void __iomem *base;
 524        int ret;
 525
 526        ret = ecard_request_resources(ec);
 527        if (ret)
 528                goto out;
 529
 530        base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
 531        if (!base) {
 532                ret = -ENOMEM;
 533                goto out_region;
 534        }
 535
 536        host = scsi_host_alloc(&eesox_template,
 537                               sizeof(struct eesoxscsi_info));
 538        if (!host) {
 539                ret = -ENOMEM;
 540                goto out_region;
 541        }
 542
 543        ecard_set_drvdata(ec, host);
 544
 545        info = (struct eesoxscsi_info *)host->hostdata;
 546        info->ec        = ec;
 547        info->base      = base;
 548        info->ctl_port  = base + EESOX_CONTROL;
 549        info->control   = term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
 550        writeb(info->control, info->ctl_port);
 551
 552        info->info.scsi.io_base         = base + EESOX_FAS216_OFFSET;
 553        info->info.scsi.io_shift        = EESOX_FAS216_SHIFT;
 554        info->info.scsi.irq             = ec->irq;
 555        info->info.scsi.dma             = ec->dma;
 556        info->info.ifcfg.clockrate      = 40; /* MHz */
 557        info->info.ifcfg.select_timeout = 255;
 558        info->info.ifcfg.asyncperiod    = 200; /* ns */
 559        info->info.ifcfg.sync_max_depth = 7;
 560        info->info.ifcfg.cntl3          = CNTL3_FASTSCSI | CNTL3_FASTCLK;
 561        info->info.ifcfg.disconnect_ok  = 1;
 562        info->info.ifcfg.wide_max_size  = 0;
 563        info->info.ifcfg.capabilities   = FASCAP_PSEUDODMA;
 564        info->info.dma.setup            = eesoxscsi_dma_setup;
 565        info->info.dma.pseudo           = eesoxscsi_dma_pseudo;
 566        info->info.dma.stop             = eesoxscsi_dma_stop;
 567
 568        ec->irqaddr     = base + EESOX_DMASTAT;
 569        ec->irqmask     = EESOX_STAT_INTR;
 570
 571        ecard_setirq(ec, &eesoxscsi_ops, info);
 572
 573        device_create_file(&ec->dev, &dev_attr_bus_term);
 574
 575        ret = fas216_init(host);
 576        if (ret)
 577                goto out_free;
 578
 579        ret = request_irq(ec->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
 580        if (ret) {
 581                printk("scsi%d: IRQ%d not free: %d\n",
 582                       host->host_no, ec->irq, ret);
 583                goto out_remove;
 584        }
 585
 586        if (info->info.scsi.dma != NO_DMA) {
 587                if (request_dma(info->info.scsi.dma, "eesox")) {
 588                        printk("scsi%d: DMA%d not free, DMA disabled\n",
 589                               host->host_no, info->info.scsi.dma);
 590                        info->info.scsi.dma = NO_DMA;
 591                } else {
 592                        set_dma_speed(info->info.scsi.dma, 180);
 593                        info->info.ifcfg.capabilities |= FASCAP_DMA;
 594                        info->info.ifcfg.cntl3 |= CNTL3_BS8;
 595                }
 596        }
 597
 598        ret = fas216_add(host, &ec->dev);
 599        if (ret == 0)
 600                goto out;
 601
 602        if (info->info.scsi.dma != NO_DMA)
 603                free_dma(info->info.scsi.dma);
 604        free_irq(ec->irq, host);
 605
 606 out_remove:
 607        fas216_remove(host);
 608
 609 out_free:
 610        device_remove_file(&ec->dev, &dev_attr_bus_term);
 611        scsi_host_put(host);
 612
 613 out_region:
 614        ecard_release_resources(ec);
 615
 616 out:
 617        return ret;
 618}
 619
 620static void __devexit eesoxscsi_remove(struct expansion_card *ec)
 621{
 622        struct Scsi_Host *host = ecard_get_drvdata(ec);
 623        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 624
 625        ecard_set_drvdata(ec, NULL);
 626        fas216_remove(host);
 627
 628        if (info->info.scsi.dma != NO_DMA)
 629                free_dma(info->info.scsi.dma);
 630        free_irq(ec->irq, info);
 631
 632        device_remove_file(&ec->dev, &dev_attr_bus_term);
 633
 634        fas216_release(host);
 635        scsi_host_put(host);
 636        ecard_release_resources(ec);
 637}
 638
 639static const struct ecard_id eesoxscsi_cids[] = {
 640        { MANU_EESOX, PROD_EESOX_SCSI2 },
 641        { 0xffff, 0xffff },
 642};
 643
 644static struct ecard_driver eesoxscsi_driver = {
 645        .probe          = eesoxscsi_probe,
 646        .remove         = __devexit_p(eesoxscsi_remove),
 647        .id_table       = eesoxscsi_cids,
 648        .drv = {
 649                .name           = "eesoxscsi",
 650        },
 651};
 652
 653static int __init eesox_init(void)
 654{
 655        return ecard_register_driver(&eesoxscsi_driver);
 656}
 657
 658static void __exit eesox_exit(void)
 659{
 660        ecard_remove_driver(&eesoxscsi_driver);
 661}
 662
 663module_init(eesox_init);
 664module_exit(eesox_exit);
 665
 666MODULE_AUTHOR("Russell King");
 667MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
 668module_param_array(term, int, NULL, 0);
 669MODULE_PARM_DESC(term, "SCSI bus termination");
 670MODULE_LICENSE("GPL");
 671