📄 eicon_mod.c
字号:
/* $Id: eicon_mod.c,v 1.37 2000/09/02 11:16:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * * Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. * (dor@deutschemailbox.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#define DRIVERNAME "Eicon active ISDN driver"#define DRIVERRELEASE "2.0"#define DRIVERPATCH ".15"#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#ifdef CONFIG_MCA#include <linux/mca.h>#endif /* CONFIG_MCA */#include "eicon.h"#include "../avmb1/capicmd.h" /* this should be moved in a common place */#undef N_DATA#include "adapter.h"#include "uxio.h"#define INCLUDE_INLINE_FUNCSstatic eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */static char *eicon_revision = "$Revision: 1.37 $";extern char *eicon_pci_revision;extern char *eicon_isa_revision;extern char *eicon_idi_revision;extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, unsigned int command, unsigned long arg);extern void eicon_pci_init_conf(eicon_card *card);void mod_inc_use_count(void);void mod_dec_use_count(void);extern char *file_check(void);#ifdef MODULE#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))#endif#define EICON_CTRL_VERSION 2 ulong DebugVar;spinlock_t eicon_lock;DESCRIPTOR idi_d[32];/* Parameters to be set by insmod */#ifdef CONFIG_ISDN_DRV_EICON_ISAstatic int membase = -1;static int irq = -1;#endifstatic char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";MODULE_DESCRIPTION( "Driver for Eicon active ISDN cards");MODULE_AUTHOR( "Armin Schindler");MODULE_SUPPORTED_DEVICE( "ISDN subsystem");MODULE_PARM_DESC(id, "ID-String of first card");MODULE_PARM(id, "s");#ifdef CONFIG_ISDN_DRV_EICON_ISAMODULE_PARM_DESC(membase, "Base address of first ISA card");MODULE_PARM_DESC(irq, "IRQ of first card");MODULE_PARM(membase, "i");MODULE_PARM(irq, "i");#endifchar *eicon_ctype_name[] = { "ISDN-S", "ISDN-SX", "ISDN-SCOM", "ISDN-QUADRO", "ISDN-S2M", "DIVA Server BRI/PCI", "DIVA Server 4BRI/PCI", "DIVA Server 4BRI/PCI", "DIVA Server PRI/PCI"};static char *eicon_getrev(const char *revision){ char *rev; char *p; if ((p = strchr(revision, ':'))) { rev = p + 2; p = strchr(rev, '$'); *--p = 0; } else rev = "?.??"; return rev;}static eicon_chan *find_channel(eicon_card *card, int channel){ if ((channel >= 0) && (channel < card->nchannels)) return &(card->bch[channel]); eicon_log(card, 1, "eicon: Invalid channel %d\n", channel); return NULL;}#ifdef CONFIG_PCI#ifdef CONFIG_ISDN_DRV_EICON_PCI/* * Find pcicard with given card number */static inline eicon_card *eicon_findnpcicard(int driverid){ eicon_card *p = cards; while (p) { if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) && (p->bus == EICON_BUS_PCI)) return p; p = p->next; } return (eicon_card *) 0;}#endif#endif /* CONFIG_PCI */static voideicon_rcv_dispatch(struct eicon_card *card){ switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: case EICON_BUS_PCI: eicon_io_rcv_dispatch(card); break; default: eicon_log(card, 1, "eicon_ack_dispatch: Illegal bustype %d\n", card->bus); }}static voideicon_ack_dispatch(struct eicon_card *card){ switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: case EICON_BUS_PCI: eicon_io_ack_dispatch(card); break; default: eicon_log(card, 1, "eicon_ack_dispatch: Illegal bustype %d\n", card->bus); }}static voideicon_transmit(struct eicon_card *card){ switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: case EICON_BUS_PCI: eicon_io_transmit(card); break; default: eicon_log(card, 1, "eicon_transmit: Illegal bustype %d\n", card->bus); }}static inteicon_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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -