This source file includes following definitions.
- ecb_dma_to_cpu
- ecb_cpu_to_dma
- aha1740_show_info
- aha1740_makecode
- aha1740_test_port
- aha1740_intr_handle
- aha1740_queuecommand_lck
- DEF_SCSI_QCMD
- aha1740_biosparam
- aha1740_eh_abort_handler
- aha1740_probe
- aha1740_remove
- aha1740_init
- aha1740_exit
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 #include <linux/blkdev.h>
  41 #include <linux/interrupt.h>
  42 #include <linux/module.h>
  43 #include <linux/kernel.h>
  44 #include <linux/types.h>
  45 #include <linux/string.h>
  46 #include <linux/ioport.h>
  47 #include <linux/proc_fs.h>
  48 #include <linux/stat.h>
  49 #include <linux/init.h>
  50 #include <linux/device.h>
  51 #include <linux/eisa.h>
  52 #include <linux/dma-mapping.h>
  53 #include <linux/gfp.h>
  54 
  55 #include <asm/dma.h>
  56 #include <asm/io.h>
  57 
  58 #include "scsi.h"
  59 #include <scsi/scsi_host.h>
  60 #include "aha1740.h"
  61 
  62 
  63 
  64 
  65 
  66 #ifdef DEBUG
  67 #define DEB(x) x
  68 #else
  69 #define DEB(x)
  70 #endif
  71 
  72 struct aha1740_hostdata {
  73         struct eisa_device *edev;
  74         unsigned int translation;
  75         unsigned int last_ecb_used;
  76         dma_addr_t ecb_dma_addr;
  77         struct ecb ecb[AHA1740_ECBS];
  78 };
  79 
  80 struct aha1740_sg {
  81         struct aha1740_chain sg_chain[AHA1740_SCATTER];
  82         dma_addr_t sg_dma_addr;
  83         dma_addr_t buf_dma_addr;
  84 };
  85 
  86 #define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
  87 
  88 static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host,
  89                                           dma_addr_t dma)
  90 {
  91         struct aha1740_hostdata *hdata = HOSTDATA (host);
  92         dma_addr_t offset;
  93 
  94         offset = dma - hdata->ecb_dma_addr;
  95 
  96         return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset);
  97 }
  98 
  99 static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
 100 {
 101         struct aha1740_hostdata *hdata = HOSTDATA (host);
 102         dma_addr_t offset;
 103     
 104         offset = (char *) cpu - (char *) hdata->ecb;
 105 
 106         return hdata->ecb_dma_addr + offset;
 107 }
 108 
 109 static int aha1740_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
 110 {
 111         struct aha1740_hostdata *host = HOSTDATA(shpnt);
 112         seq_printf(m, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
 113                       "Extended translation %sabled.\n",
 114                       shpnt->io_port, shpnt->irq, host->edev->slot,
 115                       host->translation ? "en" : "dis");
 116         return 0;
 117 }
 118 
 119 static int aha1740_makecode(unchar *sense, unchar *status)
 120 {
 121         struct statusword
 122         {
 123                 ushort  don:1,  
 124                         du:1,   
 125                     :1, qf:1,   
 126                         sc:1,   
 127                         dor:1,  
 128                         ch:1,   
 129                         intr:1, 
 130                         asa:1,  
 131                         sns:1,  
 132                     :1, ini:1,  
 133                         me:1,   
 134                     :1, eca:1,  
 135                     :1;
 136         } status_word;
 137         int retval = DID_OK;
 138 
 139         status_word = * (struct statusword *) status;
 140 #ifdef DEBUG
 141         printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
 142                status[0], status[1], status[2], status[3],
 143                sense[0], sense[1], sense[2], sense[3]);
 144 #endif
 145         if (!status_word.don) { 
 146                 if ( (status[1]&0x18) || status_word.sc ) {
 147                         
 148                         
 149                         switch ( status[2] ) {
 150                         case 0x12:
 151                                 if ( status_word.dor )
 152                                         retval=DID_ERROR; 
 153                                 
 154 
 155                         case 0x00: 
 156 
 157                                 break;
 158                         case 0x11:
 159                         case 0x21:
 160                                 retval=DID_TIME_OUT;
 161                                 break;
 162                         case 0x0a:
 163                                 retval=DID_BAD_TARGET;
 164                                 break;
 165                         case 0x04:
 166                         case 0x05:
 167                                 retval=DID_ABORT;
 168                                 
 169 
 170                                 break;
 171                         default:
 172                                 retval=DID_ERROR; 
 173 
 174 
 175                         }
 176                 } else {
 177                         
 178                         if ( status_word.qf ) {
 179                                 retval = DID_TIME_OUT; 
 180                                 
 181 
 182                                 printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
 183                         } else
 184                                 if ( status[0]&0x60 ) {
 185                                          
 186                                         retval = DID_ERROR;
 187                                 }
 188                         
 189 
 190 
 191                 }
 192         }
 193         
 194         return status[3] | retval << 16;
 195 }
 196 
 197 static int aha1740_test_port(unsigned int base)
 198 {
 199         if ( inb(PORTADR(base)) & PORTADDR_ENH )
 200                 return 1;   
 201         
 202         printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
 203         return 0;
 204 }
 205 
 206 
 207 static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
 208 {
 209         struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
 210         void (*my_done)(struct scsi_cmnd *);
 211         int errstatus, adapstat;
 212         int number_serviced;
 213         struct ecb *ecbptr;
 214         struct scsi_cmnd *SCtmp;
 215         unsigned int base;
 216         unsigned long flags;
 217         int handled = 0;
 218         struct aha1740_sg *sgptr;
 219         struct eisa_device *edev;
 220         
 221         if (!host)
 222                 panic("aha1740.c: Irq from unknown host!\n");
 223         spin_lock_irqsave(host->host_lock, flags);
 224         base = host->io_port;
 225         number_serviced = 0;
 226         edev = HOSTDATA(host)->edev;
 227 
 228         while(inb(G2STAT(base)) & G2STAT_INTPEND) {
 229                 handled = 1;
 230                 DEB(printk("aha1740_intr top of loop.\n"));
 231                 adapstat = inb(G2INTST(base));
 232                 ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base)));
 233                 outb(G2CNTRL_IRST,G2CNTRL(base)); 
 234       
 235                 switch ( adapstat & G2INTST_MASK ) {
 236                 case    G2INTST_CCBRETRY:
 237                 case    G2INTST_CCBERROR:
 238                 case    G2INTST_CCBGOOD:
 239                         
 240                         outb(G2CNTRL_HRDY,G2CNTRL(base));
 241                         if (!ecbptr) {
 242                                 printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
 243                                        inb(G2STAT(base)),adapstat,
 244                                        inb(G2INTST(base)), number_serviced++);
 245                                 continue;
 246                         }
 247                         SCtmp = ecbptr->SCpnt;
 248                         if (!SCtmp) {
 249                                 printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
 250                                        inb(G2STAT(base)),adapstat,
 251                                        inb(G2INTST(base)), number_serviced++);
 252                                 continue;
 253                         }
 254                         sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
 255                         scsi_dma_unmap(SCtmp);
 256 
 257                         
 258                         dma_free_coherent (&edev->dev,
 259                                            sizeof (struct aha1740_sg),
 260                                            SCtmp->host_scribble,
 261                                            sgptr->sg_dma_addr);
 262             
 263                         
 264 
 265 
 266 
 267 
 268                         if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
 269                                 memcpy(SCtmp->sense_buffer, ecbptr->sense, 
 270                                        SCSI_SENSE_BUFFERSIZE);
 271                                 errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
 272                         } else
 273                                 errstatus = 0;
 274                         DEB(if (errstatus)
 275                             printk("aha1740_intr_handle: returning %6x\n",
 276                                    errstatus));
 277                         SCtmp->result = errstatus;
 278                         my_done = ecbptr->done;
 279                         memset(ecbptr,0,sizeof(struct ecb)); 
 280                         if ( my_done )
 281                                 my_done(SCtmp);
 282                         break;
 283                         
 284                 case    G2INTST_HARDFAIL:
 285                         printk(KERN_ALERT "aha1740 hardware failure!\n");
 286                         panic("aha1740.c");     
 287                         
 288                 case    G2INTST_ASNEVENT:
 289                         printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
 290                                adapstat,
 291                                inb(MBOXIN0(base)),
 292                                inb(MBOXIN1(base)),
 293                                inb(MBOXIN2(base)),
 294                                inb(MBOXIN3(base))); 
 295                         
 296                         outb(G2CNTRL_HRDY,G2CNTRL(base));
 297                         break;
 298                         
 299                 case    G2INTST_CMDGOOD:
 300                         
 301                         break;
 302                         
 303                 case    G2INTST_CMDERROR:
 304                         
 305                         break;
 306                 }
 307                 number_serviced++;
 308         }
 309 
 310         spin_unlock_irqrestore(host->host_lock, flags);
 311         return IRQ_RETVAL(handled);
 312 }
 313 
 314 static int aha1740_queuecommand_lck(struct scsi_cmnd * SCpnt,
 315                                     void (*done)(struct scsi_cmnd *))
 316 {
 317         unchar direction;
 318         unchar *cmd = (unchar *) SCpnt->cmnd;
 319         unchar target = scmd_id(SCpnt);
 320         struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
 321         unsigned long flags;
 322         dma_addr_t sg_dma;
 323         struct aha1740_sg *sgptr;
 324         int ecbno, nseg;
 325         DEB(int i);
 326 
 327         if(*cmd == REQUEST_SENSE) {
 328                 SCpnt->result = 0;
 329                 done(SCpnt); 
 330                 return 0;
 331         }
 332 
 333 #ifdef DEBUG
 334         if (*cmd == READ_10 || *cmd == WRITE_10)
 335                 i = xscsi2int(cmd+2);
 336         else if (*cmd == READ_6 || *cmd == WRITE_6)
 337                 i = scsi2int(cmd+2);
 338         else
 339                 i = -1;
 340         printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
 341                target, *cmd, i, bufflen);
 342         printk("scsi cmd:");
 343         for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
 344         printk("\n");
 345 #endif
 346 
 347         
 348         spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
 349         ecbno = host->last_ecb_used + 1; 
 350         if (ecbno >= AHA1740_ECBS)
 351                 ecbno = 0;
 352         do {
 353                 if (!host->ecb[ecbno].cmdw)
 354                         break;
 355                 ecbno++;
 356                 if (ecbno >= AHA1740_ECBS)
 357                         ecbno = 0;
 358         } while (ecbno != host->last_ecb_used);
 359 
 360         if (host->ecb[ecbno].cmdw)
 361                 panic("Unable to find empty ecb for aha1740.\n");
 362 
 363         host->ecb[ecbno].cmdw = AHA1740CMD_INIT; 
 364 
 365 
 366         host->last_ecb_used = ecbno;    
 367         spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
 368 
 369 #ifdef DEBUG
 370         printk("Sending command (%d %x)...", ecbno, done);
 371 #endif
 372 
 373         host->ecb[ecbno].cdblen = SCpnt->cmd_len; 
 374 
 375 
 376 
 377         direction = 0;
 378         if (*cmd == READ_10 || *cmd == READ_6)
 379                 direction = 1;
 380         else if (*cmd == WRITE_10 || *cmd == WRITE_6)
 381                 direction = 0;
 382 
 383         memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
 384 
 385         SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev,
 386                                                    sizeof (struct aha1740_sg),
 387                                                    &sg_dma, GFP_ATOMIC);
 388         if(SCpnt->host_scribble == NULL) {
 389                 printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n");
 390                 return 1;
 391         }
 392         sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
 393         sgptr->sg_dma_addr = sg_dma;
 394 
 395         nseg = scsi_dma_map(SCpnt);
 396         BUG_ON(nseg < 0);
 397         if (nseg) {
 398                 struct scatterlist *sg;
 399                 struct aha1740_chain * cptr;
 400                 int i;
 401                 DEB(unsigned char * ptr);
 402 
 403                 host->ecb[ecbno].sg = 1;  
 404 
 405                 cptr = sgptr->sg_chain;
 406                 scsi_for_each_sg(SCpnt, sg, nseg, i) {
 407                         cptr[i].datalen = sg_dma_len (sg);
 408                         cptr[i].dataptr = sg_dma_address (sg);
 409                 }
 410                 host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
 411                 host->ecb[ecbno].dataptr = sg_dma;
 412 #ifdef DEBUG
 413                 printk("cptr %x: ",cptr);
 414                 ptr = (unsigned char *) cptr;
 415                 for(i=0;i<24;i++) printk("%02x ", ptr[i]);
 416 #endif
 417         } else {
 418                 host->ecb[ecbno].datalen = 0;
 419                 host->ecb[ecbno].dataptr = 0;
 420         }
 421         host->ecb[ecbno].lun = SCpnt->device->lun;
 422         host->ecb[ecbno].ses = 1; 
 423         host->ecb[ecbno].dir = direction;
 424         host->ecb[ecbno].ars = 1; 
 425         host->ecb[ecbno].senselen = 12;
 426         host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host,
 427                                                     host->ecb[ecbno].sense);
 428         host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host,
 429                                                      host->ecb[ecbno].status);
 430         host->ecb[ecbno].done = done;
 431         host->ecb[ecbno].SCpnt = SCpnt;
 432 #ifdef DEBUG
 433         {
 434                 int i;
 435                 printk("aha1740_command: sending.. ");
 436                 for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
 437                         printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
 438         }
 439         printk("\n");
 440 #endif
 441         if (done) {
 442         
 443 
 444 
 445 
 446 
 447 
 448 
 449 
 450 
 451 
 452 
 453 
 454 #define LOOPCNT_WARN 10         
 455 #define LOOPCNT_MAX 1000000     
 456                 int loopcnt;
 457                 unsigned int base = SCpnt->device->host->io_port;
 458                 DEB(printk("aha1740[%d] critical section\n",ecbno));
 459 
 460                 spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
 461                 for (loopcnt = 0; ; loopcnt++) {
 462                         if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
 463                         if (loopcnt == LOOPCNT_WARN) {
 464                                 printk("aha1740[%d]_mbxout wait!\n",ecbno);
 465                         }
 466                         if (loopcnt == LOOPCNT_MAX)
 467                                 panic("aha1740.c: mbxout busy!\n");
 468                 }
 469                 outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno),
 470                       MBOXOUT0(base));
 471                 for (loopcnt = 0; ; loopcnt++) {
 472                         if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
 473                         if (loopcnt == LOOPCNT_WARN) {
 474                                 printk("aha1740[%d]_attn wait!\n",ecbno);
 475                         }
 476                         if (loopcnt == LOOPCNT_MAX)
 477                                 panic("aha1740.c: attn wait failed!\n");
 478                 }
 479                 outb(ATTN_START | (target & 7), ATTN(base)); 
 480                 spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
 481                 DEB(printk("aha1740[%d] request queued.\n",ecbno));
 482         } else
 483                 printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
 484         return 0;
 485 }
 486 
 487 static DEF_SCSI_QCMD(aha1740_queuecommand)
 488 
 489 
 490 
 491 
 492 static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
 493                               unsigned int *irq_type,
 494                               unsigned int *translation)
 495 {
 496         static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
 497 
 498         *irq_level = intab[inb(INTDEF(base)) & 0x7];
 499         *irq_type  = (inb(INTDEF(base)) & 0x8) >> 3;
 500         *translation = inb(RESV1(base)) & 0x1;
 501         outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
 502 }
 503 
 504 static int aha1740_biosparam(struct scsi_device *sdev,
 505                              struct block_device *dev,
 506                              sector_t capacity, int* ip)
 507 {
 508         int size = capacity;
 509         int extended = HOSTDATA(sdev->host)->translation;
 510 
 511         DEB(printk("aha1740_biosparam\n"));
 512         if (extended && (ip[2] > 1024)) {
 513                 ip[0] = 255;
 514                 ip[1] = 63;
 515                 ip[2] = size / (255 * 63);
 516         } else {
 517                 ip[0] = 64;
 518                 ip[1] = 32;
 519                 ip[2] = size >> 11;
 520         }
 521         return 0;
 522 }
 523 
 524 static int aha1740_eh_abort_handler (struct scsi_cmnd *dummy)
 525 {
 526 
 527 
 528 
 529 
 530 
 531 
 532 
 533 
 534 
 535         return SUCCESS;
 536 }
 537 
 538 static struct scsi_host_template aha1740_template = {
 539         .module           = THIS_MODULE,
 540         .proc_name        = "aha1740",
 541         .show_info        = aha1740_show_info,
 542         .name             = "Adaptec 174x (EISA)",
 543         .queuecommand     = aha1740_queuecommand,
 544         .bios_param       = aha1740_biosparam,
 545         .can_queue        = AHA1740_ECBS,
 546         .this_id          = 7,
 547         .sg_tablesize     = AHA1740_SCATTER,
 548         .eh_abort_handler = aha1740_eh_abort_handler,
 549 };
 550 
 551 static int aha1740_probe (struct device *dev)
 552 {
 553         int slotbase, rc;
 554         unsigned int irq_level, irq_type, translation;
 555         struct Scsi_Host *shpnt;
 556         struct aha1740_hostdata *host;
 557         struct eisa_device *edev = to_eisa_device (dev);
 558 
 559         DEB(printk("aha1740_probe: \n"));
 560         
 561         slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET;
 562         if (!request_region(slotbase, SLOTSIZE, "aha1740")) 
 563                 return -EBUSY;
 564         if (!aha1740_test_port(slotbase))
 565                 goto err_release_region;
 566         aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation);
 567         if ((inb(G2STAT(slotbase)) &
 568              (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
 569                 
 570                 outb(G2CNTRL_HRST, G2CNTRL(slotbase));
 571                 outb(0, G2CNTRL(slotbase));
 572         }
 573         printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n",
 574                edev->slot, slotbase, irq_level, irq_type ? "edge" : "level");
 575         printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
 576                translation ? "en" : "dis");
 577         shpnt = scsi_host_alloc(&aha1740_template,
 578                               sizeof(struct aha1740_hostdata));
 579         if(shpnt == NULL)
 580                 goto err_release_region;
 581 
 582         shpnt->base = 0;
 583         shpnt->io_port = slotbase;
 584         shpnt->n_io_port = SLOTSIZE;
 585         shpnt->irq = irq_level;
 586         shpnt->dma_channel = 0xff;
 587         host = HOSTDATA(shpnt);
 588         host->edev = edev;
 589         host->translation = translation;
 590         host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb,
 591                                              sizeof (host->ecb),
 592                                              DMA_BIDIRECTIONAL);
 593         if (!host->ecb_dma_addr) {
 594                 printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
 595                 scsi_host_put (shpnt);
 596                 goto err_host_put;
 597         }
 598         
 599         DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
 600         if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED,
 601                         "aha1740",shpnt)) {
 602                 printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
 603                        irq_level);
 604                 goto err_unmap;
 605         }
 606 
 607         eisa_set_drvdata (edev, shpnt);
 608 
 609         rc = scsi_add_host (shpnt, dev);
 610         if (rc)
 611                 goto err_irq;
 612 
 613         scsi_scan_host (shpnt);
 614         return 0;
 615 
 616  err_irq:
 617         free_irq(irq_level, shpnt);
 618  err_unmap:
 619         dma_unmap_single (&edev->dev, host->ecb_dma_addr,
 620                           sizeof (host->ecb), DMA_BIDIRECTIONAL);
 621  err_host_put:
 622         scsi_host_put (shpnt);
 623  err_release_region:
 624         release_region(slotbase, SLOTSIZE);
 625 
 626         return -ENODEV;
 627 }
 628 
 629 static int aha1740_remove (struct device *dev)
 630 {
 631         struct Scsi_Host *shpnt = dev_get_drvdata(dev);
 632         struct aha1740_hostdata *host = HOSTDATA (shpnt);
 633 
 634         scsi_remove_host(shpnt);
 635         
 636         free_irq (shpnt->irq, shpnt);
 637         dma_unmap_single (dev, host->ecb_dma_addr,
 638                           sizeof (host->ecb), DMA_BIDIRECTIONAL);
 639         release_region (shpnt->io_port, SLOTSIZE);
 640 
 641         scsi_host_put (shpnt);
 642         
 643         return 0;
 644 }
 645 
 646 static struct eisa_device_id aha1740_ids[] = {
 647         { "ADP0000" },          
 648         { "ADP0001" },          
 649         { "ADP0002" },          
 650         { "ADP0400" },          
 651         { "" }
 652 };
 653 MODULE_DEVICE_TABLE(eisa, aha1740_ids);
 654 
 655 static struct eisa_driver aha1740_driver = {
 656         .id_table = aha1740_ids,
 657         .driver   = {
 658                 .name    = "aha1740",
 659                 .probe   = aha1740_probe,
 660                 .remove  = aha1740_remove,
 661         },
 662 };
 663 
 664 static __init int aha1740_init (void)
 665 {
 666         return eisa_driver_register (&aha1740_driver);
 667 }
 668 
 669 static __exit void aha1740_exit (void)
 670 {
 671         eisa_driver_unregister (&aha1740_driver);
 672 }
 673 
 674 module_init (aha1740_init);
 675 module_exit (aha1740_exit);
 676 
 677 MODULE_LICENSE("GPL");