extractedLnx/linux-2.5.49/drivers/isdn/eicon/eicon_mod.c_eicon_command.c
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) {
if (copy_to_user((char *)a,
&card->hwif.pci.master,
sizeof(int)))
return -EFAULT;
}
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 (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 -EFAULT;
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;
}
Generated by GNU enscript 1.6.4.