static void __exit unregister_card(eicon_card * card) { isdn_ctrl cmd; cmd.command = ISDN_STAT_UNLOAD; cmd.driver = card->myid; card->interface.statcallb(&cmd); switch (card->bus) { #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_BUS_ISA: #ifdef CONFIG_MCA case EICON_BUS_MCA: #endif /* CONFIG_MCA */ eicon_isa_release(&card->hwif.isa); break; #endif case EICON_BUS_PCI: break; default: eicon_log(card, 1, "eicon: Invalid BUS type %d\n", card->bus); break; } }
int eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { eicon_isa_boot *boot; int tmp; int timeout; int j; eicon_isa_codebuf cbuf; unsigned char *code; unsigned char *p; if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf))) return -EFAULT; if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) { printk(KERN_WARNING "eicon_isa_load: Couldn't allocate code buffer\n"); return -ENOMEM; } if (copy_from_user(code, &cb->code, cbuf.firmware_len)) { kfree(code); return -EFAULT; } boot = &card->shmem->boot; if ((!card->ivalid) && card->master) { card->irqprobe = 1; /* Check for valid IRQ */ if ((card->irq < 0) || (card->irq > 15) || (!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) { printk(KERN_WARNING "eicon_isa_load: illegal irq: %d\n", card->irq); eicon_isa_release_shmem(card); kfree(code); return -EINVAL; } /* Register irq */ if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card)) card->ivalid = 1; else { printk(KERN_WARNING "eicon_isa_load: irq %d already in use.\n", card->irq); eicon_isa_release_shmem(card); kfree(code); return -EBUSY; } } tmp = readb(&boot->msize); if (tmp != 8 && tmp != 16 && tmp != 24 && tmp != 32 && tmp != 48 && tmp != 60) { printk(KERN_WARNING "eicon_isa_load: invalid memsize\n"); eicon_isa_release_shmem(card); return -EIO; } eicon_isa_printpar(card); /* Download firmware */ printk(KERN_INFO "%s %dkB, loading firmware ...\n", eicon_ctype_name[card->type], tmp * 16); tmp = cbuf.firmware_len >> 8; p = code; while (tmp--) { memcpy_toio(&boot->b, p, 256); writeb(1, &boot->ctrl); timeout = jiffies + 10; while (timeout > jiffies) { if (readb(&boot->ctrl) == 0) break; SLEEP(2); } if (readb(&boot->ctrl)) { printk(KERN_WARNING "eicon_isa_load: download timeout at 0x%x\n", p-code); eicon_isa_release(card); kfree(code); return -EIO; } p += 256; } kfree(code); /* Initialize firmware parameters */ memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14); memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96); memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96); /* Start firmware, wait for signature */ writeb(2, &boot->ctrl); timeout = jiffies + (5*HZ); while (timeout > jiffies) { if (readw(&boot->signature) == 0x4447) break; SLEEP(2); } if (readw(&boot->signature) != 0x4447) { printk(KERN_WARNING "eicon_isa_load: firmware selftest failed %04x\n", readw(&boot->signature)); eicon_isa_release(card); return -EIO; } card->channels = readb(&card->shmem->c[0x3f6]); /* clear irq-requests, reset irq-count */ readb(card->intack); writeb(0, card->intack); if (card->master) { card->irqprobe = 1; /* Trigger an interrupt and check if it is delivered */ tmp = readb(&card->shmem->com.ReadyInt); tmp ++; writeb(tmp, &card->shmem->com.ReadyInt); timeout = jiffies + 20; while (timeout > jiffies) { if (card->irqprobe > 1) break; SLEEP(2); } if (card->irqprobe == 1) { printk(KERN_WARNING "eicon_isa_load: IRQ # %d test failed\n", card->irq); eicon_isa_release(card); return -EIO; } } #ifdef EICON_MCA_DEBUG printk(KERN_INFO "eicon_isa_load: IRQ # %d test succeeded.\n", card->irq); #endif writeb(card->irq, &card->shmem->com.Int); /* initializing some variables */ ((eicon_card *)card->card)->ReadyInt = 0; ((eicon_card *)card->card)->ref_in = 1; ((eicon_card *)card->card)->ref_out = 1; for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; for(j=0; j< (card->channels + 1); j++) { ((eicon_card *)card->card)->bch[j].e.busy = 0; ((eicon_card *)card->card)->bch[j].e.D3Id = 0; ((eicon_card *)card->card)->bch[j].e.B2Id = 0; ((eicon_card *)card->card)->bch[j].e.ref = 0; ((eicon_card *)card->card)->bch[j].e.Req = 0; ((eicon_card *)card->card)->bch[j].e.complete = 1; ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; } printk(KERN_INFO "Eicon: Supported channels: %d\n", card->channels); printk(KERN_INFO "%s successfully started\n", eicon_ctype_name[card->type]); /* Enable normal IRQ processing */ card->irqprobe = 0; return 0; }