int eicon_pci_find_card(char *ID) { int pci_cards = 0; int card_id = 0; int had_q = 0; int ctype = 0; char did[20]; card_t *pCard; word wCardIndex; pCard = DivasCards; for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) { if ((pCard->hw) && (pCard->hw->in_use)) { switch(pCard->hw->card_type) { case DIA_CARD_TYPE_DIVA_SERVER: ctype = EICON_CTYPE_MAESTRAP; card_id++; had_q = 0; break; case DIA_CARD_TYPE_DIVA_SERVER_B: ctype = EICON_CTYPE_MAESTRA; card_id++; had_q = 0; break; case DIA_CARD_TYPE_DIVA_SERVER_Q: ctype = EICON_CTYPE_MAESTRAQ; if (!had_q) card_id++; if (++had_q >=4) had_q = 0; break; default: printk(KERN_ERR "eicon_pci: unknown card type %d !\n", pCard->hw->card_type); goto err; } sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) { printk(KERN_ERR "eicon_pci: Card could not be added !\n"); } else { pci_cards++; printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", eicon_ctype_name[ctype], did, card_id); } err:; } pCard++; } return pci_cards; }
int eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { int tmp; int timeout; eicon_isa_codebuf cbuf; unsigned char *code; eicon_isa_boot *boot; if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf))) return -EFAULT; /* Allocate code-buffer and copy code from userspace */ if (cbuf.bootstrap_len > 1024) { printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ld\n", cbuf.bootstrap_len); return -EINVAL; } if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) { printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n"); return -ENOMEM; } if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) { kfree(code); return -EFAULT; } if (card->type == EICON_CTYPE_ISAPRI) card->ramsize = RAMSIZE_P; else card->ramsize = RAMSIZE; /* Register shmem */ if (check_shmem((unsigned long)card->shmem, card->ramsize)) { printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n", (unsigned long)card->shmem); kfree(code); return -EBUSY; } request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN"); #ifdef EICON_MCA_DEBUG printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize); #endif card->mvalid = 1; switch(card->type) { case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: case EICON_CTYPE_QUADRO: case EICON_CTYPE_ISABRI: card->intack = (__u8 *)card->shmem + INTACK; card->startcpu = (__u8 *)card->shmem + STARTCPU; card->stopcpu = (__u8 *)card->shmem + STOPCPU; break; case EICON_CTYPE_S2M: case EICON_CTYPE_ISAPRI: card->intack = (__u8 *)card->shmem + INTACK_P; card->startcpu = (__u8 *)card->shmem + STARTCPU_P; card->stopcpu = (__u8 *)card->shmem + STOPCPU_P; break; default: printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type); eicon_isa_release_shmem(card); kfree(code); return -EINVAL; } /* clear any pending irq's */ readb(card->intack); #ifdef CONFIG_MCA if (MCA_bus) { if (card->type == EICON_CTYPE_SCOM) { outb_p(0,card->io+1); } else { printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n"); eicon_isa_release_shmem(card); return -EINVAL; }; #ifdef EICON_MCA_DEBUG printk(KERN_INFO "eicon_isa_boot: card->io = %x.\n", card->io); printk(KERN_INFO "eicon_isa_boot: card->irq = %d.\n", (int)card->irq); #endif } #else /* set reset-line active */ writeb(0, card->stopcpu); #endif /* CONFIG_MCA */ /* clear irq-requests */ writeb(0, card->intack); readb(card->intack); /* Copy code into card */ memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len); /* Check for properly loaded code */ if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) { printk(KERN_WARNING "eicon_isa_boot: Could not load startup-code\n"); eicon_isa_release_shmem(card); kfree(code); return -EIO; } /* if 16k-ramsize, duplicate the reset-jump-code */ if (card->ramsize == RAMSIZE_P) memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12); kfree(code); boot = &card->shmem->boot; /* Delay 0.2 sec. */ SLEEP(20); /* Start CPU */ writeb(cbuf.boot_opt, &boot->ctrl); #ifdef CONFIG_MCA if (MCA_bus) { outb_p(0, card->io); } #else writeb(0, card->startcpu); #endif /* CONFIG_MCA */ /* Delay 0.2 sec. */ SLEEP(20); timeout = jiffies + (HZ * 22); while (timeout > jiffies) { if (readb(&boot->ctrl) == 0) break; SLEEP(10); } if (readb(&boot->ctrl) != 0) { printk(KERN_WARNING "eicon_isa_boot: CPU test failed.\n"); #ifdef EICON_MCA_DEBUG printk(KERN_INFO "eicon_isa_boot: &boot->ctrl = %d.\n", readb(&boot->ctrl)); #endif eicon_isa_release_shmem(card); return -EIO; } /* Check for memory-test errors */ if (readw(&boot->ebit)) { printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)\n", readw(&boot->ebit), readl(&boot->eloc)); eicon_isa_release_shmem(card); return -EIO; } /* Check card type and memory size */ tmp = readb(&boot->card); if ((tmp < 0) || (tmp > 4)) { printk(KERN_WARNING "eicon_isa_boot: Type detect failed\n"); eicon_isa_release_shmem(card); return -EIO; } card->type = tmp; ((eicon_card *)card->card)->type = tmp; tmp = readb(&boot->msize); if (tmp != 8 && tmp != 16 && tmp != 24 && tmp != 32 && tmp != 48 && tmp != 60) { printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n"); eicon_isa_release_shmem(card); return -EIO; } printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { tmp = eicon_addcard(card->type, card->physmem, card->irq, ((eicon_card *)card->card)->regname); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } return 0; }
static int eicon_command(eicon_card * card, isdn_ctrl * c) { ulong a; eicon_chan *chan; eicon_cdef cdef; #ifdef CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI dia_start_t dstart; int idi_length = 0; #endif #endif isdn_ctrl cmd; int ret = 0; unsigned long flags; eicon_log(card, 16, "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n", c->command, c->arg, (ulong) *c->parm.num); switch (c->command) { case ISDN_CMD_IOCTL: memcpy(&a, c->parm.num, sizeof(ulong)); switch (c->arg) { case EICON_IOCTL_GETVER: return(EICON_CTRL_VERSION); case EICON_IOCTL_GETTYPE: if (card->bus == EICON_BUS_PCI) { copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int)); } return(card->type); case EICON_IOCTL_GETMMIO: switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: return (int)card->hwif.isa.shmem; default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", card->bus); ret = -ENODEV; } #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_IOCTL_SETMMIO: if (card->flags & EICON_FLAGS_LOADED) return -EBUSY; switch (card->bus) { case EICON_BUS_ISA: if (eicon_isa_find_card(a, card->hwif.isa.irq, card->regname) < 0) return -EFAULT; card->hwif.isa.shmem = (eicon_isa_shmem *)a; return 0; case EICON_BUS_MCA: #if CONFIG_MCA if (eicon_mca_find_card( 0, a, card->hwif.isa.irq, card->regname) < 0) return -EFAULT; card->hwif.isa.shmem = (eicon_isa_shmem *)a; return 0; #endif /* CONFIG_MCA */ default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", card->bus); ret = -ENODEV; } #endif case EICON_IOCTL_GETIRQ: switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: return card->hwif.isa.irq; default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", card->bus); ret = -ENODEV; } case EICON_IOCTL_SETIRQ: if (card->flags & EICON_FLAGS_LOADED) return -EBUSY; if ((a < 2) || (a > 15)) return -EFAULT; switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: card->hwif.isa.irq = a; return 0; default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", card->bus); ret = -ENODEV; } #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_IOCTL_LOADBOOT: if (card->flags & EICON_FLAGS_RUNNING) return -EBUSY; switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: ret = eicon_isa_bootload( &(card->hwif.isa), &(((eicon_codebuf *)a)->isa)); break; default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", card->bus); ret = -ENODEV; } return ret; #endif #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_IOCTL_LOADISA: if (card->flags & EICON_FLAGS_RUNNING) return -EBUSY; switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: ret = eicon_isa_load( &(card->hwif.isa), &(((eicon_codebuf *)a)->isa)); if (!ret) { card->flags |= EICON_FLAGS_LOADED; card->flags |= EICON_FLAGS_RUNNING; if (card->hwif.isa.channels > 1) { cmd.command = ISDN_STAT_ADDCH; cmd.driver = card->myid; cmd.arg = card->hwif.isa.channels - 1; card->interface.statcallb(&cmd); } cmd.command = ISDN_STAT_RUN; cmd.driver = card->myid; cmd.arg = 0; card->interface.statcallb(&cmd); } break; default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", card->bus); ret = -ENODEV; } return ret; #endif case EICON_IOCTL_MANIF: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!card->d) return -ENODEV; if (!card->d->features & DI_MANAGE) return -ENODEV; ret = eicon_idi_manage( card, (eicon_manifbuf *)a); return ret; case EICON_IOCTL_GETXLOG: return -ENODEV; case EICON_IOCTL_ADDCARD: if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) return -EFAULT; if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0))) return -EIO; return 0; case EICON_IOCTL_DEBUGVAR: DebugVar = a; eicon_log(card, 1, "Eicon: Debug Value set to %ld\n", DebugVar); return 0; #ifdef MODULE case EICON_IOCTL_FREEIT: while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT; MOD_INC_USE_COUNT; return 0; #endif case EICON_IOCTL_LOADPCI: eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n"); eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n"); eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n"); return -EINVAL; default: #ifdef CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI if (c->arg < EICON_IOCTL_DIA_OFFSET) return -EINVAL; if (copy_from_user(&dstart, (char *)a, sizeof(dstart))) return -1; if (!(card = eicon_findnpcicard(dstart.card_id))) return -EINVAL; ret = do_ioctl(NULL, NULL, c->arg - EICON_IOCTL_DIA_OFFSET, (unsigned long) a); if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { if (card->type != EICON_CTYPE_MAESTRAQ) { DIVA_DIDD_Read(idi_d, sizeof(idi_d)); for(idi_length = 0; idi_length < 32; idi_length++) { if (idi_d[idi_length].type == 0) break; } if ((idi_length < 1) || (idi_length >= 32)) { eicon_log(card, 1, "eicon: invalid idi table length.\n"); break; } card->d = &idi_d[idi_length - 1]; card->flags |= EICON_FLAGS_LOADED; card->flags |= EICON_FLAGS_RUNNING; eicon_pci_init_conf(card); if (card->d->channels > 1) { cmd.command = ISDN_STAT_ADDCH; cmd.driver = card->myid; cmd.arg = card->d->channels - 1; card->interface.statcallb(&cmd); } cmd.command = ISDN_STAT_RUN; cmd.driver = card->myid; cmd.arg = 0; card->interface.statcallb(&cmd); eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x)\n", (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", card->d->channels, card->d->features); } else { int i; DIVA_DIDD_Read(idi_d, sizeof(idi_d)); for(idi_length = 0; idi_length < 32; idi_length++) if (idi_d[idi_length].type == 0) break; if ((idi_length < 1) || (idi_length >= 32)) { eicon_log(card, 1, "eicon: invalid idi table length.\n"); break; } for(i = 3; i >= 0; i--) { if (!(card = eicon_findnpcicard(dstart.card_id - i))) return -EINVAL; card->flags |= EICON_FLAGS_LOADED; card->flags |= EICON_FLAGS_RUNNING; card->d = &idi_d[idi_length - (i+1)]; eicon_pci_init_conf(card); if (card->d->channels > 1) { cmd.command = ISDN_STAT_ADDCH; cmd.driver = card->myid; cmd.arg = card->d->channels - 1; card->interface.statcallb(&cmd); } cmd.command = ISDN_STAT_RUN; cmd.driver = card->myid; cmd.arg = 0; card->interface.statcallb(&cmd); eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x)\n", 4-i, card->d->channels, card->d->features); } } } return ret; #else return -EINVAL; #endif #endif /* CONFIG_PCI */ } break; case ISDN_CMD_DIAL: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; spin_lock_irqsave(&eicon_lock, flags); if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "Dial on channel %d with state %d\n", chan->No, chan->fsm_state); return -EBUSY; } chan->fsm_state = EICON_STATE_OCALL; spin_unlock_irqrestore(&eicon_lock, flags); ret = idi_connect_req(card, chan, c->parm.setup.phone, c->parm.setup.eazmsn, c->parm.setup.si1, c->parm.setup.si2); if (ret) { cmd.driver = card->myid; cmd.command = ISDN_STAT_DHUP; cmd.arg &= 0x1f; card->interface.statcallb(&cmd); } return ret; case ISDN_CMD_ACCEPTD: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; if (chan->fsm_state == EICON_STATE_ICALL) { idi_connect_res(card, chan); } return 0; case ISDN_CMD_ACCEPTB: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; return 0; case ISDN_CMD_HANGUP: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; idi_hangup(card, chan); return 0; case ISDN_CMD_SETEAZ: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; chan->eazmask = 0x3ff; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_CLREAZ: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; chan->eazmask = 0; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_SETL2: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; chan->l2prot = (c->arg >> 8); return 0; case ISDN_CMD_GETL2: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; return chan->l2prot; case ISDN_CMD_SETL3: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; chan->l3prot = (c->arg >> 8); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { chan->fax = c->parm.fax; eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); } #endif return 0; case ISDN_CMD_GETL3: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; return chan->l3prot; case ISDN_CMD_GETEAZ: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; eicon_log(card, 1, "eicon CMD_GETEAZ not implemented\n"); return 0; case ISDN_CMD_SETSIL: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; eicon_log(card, 1, "eicon CMD_SETSIL not implemented\n"); return 0; case ISDN_CMD_GETSIL: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n"); return 0; case ISDN_CMD_LOCK: MOD_INC_USE_COUNT; return 0; case ISDN_CMD_UNLOCK: MOD_DEC_USE_COUNT; return 0; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_CMD_FAXCMD: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; if (!chan->fax) break; idi_fax_cmd(card, chan); return 0; #endif case ISDN_CMD_AUDIO: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); return 0; case CAPI_PUT_MESSAGE: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; if (c->parm.cmsg.Length < 8) break; switch(c->parm.cmsg.Command) { case CAPI_FACILITY: if (c->parm.cmsg.Subcommand == CAPI_REQ) return(capipmsg(card, chan, &c->parm.cmsg)); break; case CAPI_MANUFACTURER: default: break; } return 0; } return -EINVAL; }
static int __init eicon_init(void) { int card_count = 0; char tmprev[50]; DebugVar = 1; eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; printk(KERN_INFO "%s Rev: ", DRIVERNAME); strcpy(tmprev, eicon_revision); printk("%s/", eicon_getrev(tmprev)); strcpy(tmprev, eicon_pci_revision); #ifdef CONFIG_ISDN_DRV_EICON_PCI printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif strcpy(tmprev, eicon_isa_revision); #ifdef CONFIG_ISDN_DRV_EICON_ISA printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif strcpy(tmprev, eicon_idi_revision); printk("%s\n", eicon_getrev(tmprev)); printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME, DRIVERRELEASE, DRIVERPATCH); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA /* Check if we have MCA-bus */ if (!MCA_bus) { printk(KERN_INFO "eicon: No MCA bus, ISDN-interfaces not probed.\n"); } else { eicon_log(NULL, 8, "eicon_mca_find_card, irq=%d.\n", irq); if (!eicon_mca_find_card(0, membase, irq, id)) card_count++; }; #else card_count = eicon_addcard(0, membase, irq, id, 0); #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ #ifdef CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI DivasCardsDiscover(); card_count += eicon_pci_find_card(id); #endif #endif if (!cards) { #ifdef MODULE #ifndef CONFIG_ISDN_DRV_EICON_PCI #ifndef CONFIG_ISDN_DRV_EICON_ISA printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n"); printk(KERN_INFO "Eicon: Driver not loaded !\n"); #else printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); #endif #else printk(KERN_INFO "Eicon: No PCI-cards found, driver not loaded !\n"); #endif #endif /* MODULE */ return -ENODEV; } else printk(KERN_INFO "Eicon: %d card%s added\n", card_count, (card_count>1)?"s":""); return 0; }