From: Karsten Keil - new port of 2.4 I4L core to 2.6 - new port of 2.4 I4L HiSax to 2.6 - fixes for I4L CAPI subsystem to make it stable in 2.6 - fix parameter handling of AVM ISA cards (calle) - cleanup ISDN config variables --- /dev/null | 7895 ----------------------------------- drivers/Makefile | 2 drivers/isdn/Kconfig | 14 drivers/isdn/Makefile | 2 drivers/isdn/act2000/Kconfig | 2 drivers/isdn/capi/Kconfig | 2 drivers/isdn/capi/capi.c | 40 drivers/isdn/capi/capidrv.c | 18 drivers/isdn/capi/capifs.c | 209 drivers/isdn/capi/capifs.h | 6 drivers/isdn/capi/kcapi.c | 127 drivers/isdn/capi/kcapi.h | 7 drivers/isdn/capi/kcapi_proc.c | 71 drivers/isdn/hardware/Kconfig | 25 drivers/isdn/hardware/avm/Kconfig | 2 drivers/isdn/hardware/avm/b1.c | 51 drivers/isdn/hardware/avm/b1dma.c | 50 drivers/isdn/hardware/avm/b1isa.c | 56 drivers/isdn/hardware/avm/b1pci.c | 45 drivers/isdn/hardware/avm/b1pcmcia.c | 39 drivers/isdn/hardware/avm/c4.c | 84 drivers/isdn/hardware/avm/t1isa.c | 95 drivers/isdn/hardware/avm/t1pci.c | 29 drivers/isdn/hardware/eicon/Kconfig | 2 drivers/isdn/hisax/Kconfig | 47 drivers/isdn/hisax/Makefile | 28 drivers/isdn/hisax/amd7930_fn.c | 245 - drivers/isdn/hisax/amd7930_fn.h | 21 drivers/isdn/hisax/arcofi.c | 25 drivers/isdn/hisax/asuscom.c | 471 +- drivers/isdn/hisax/avm_a1.c | 303 - drivers/isdn/hisax/avm_a1p.c | 255 - drivers/isdn/hisax/avm_pci.c | 663 +- drivers/isdn/hisax/avma1_cs.c | 101 drivers/isdn/hisax/bkm_a4t.c | 365 - drivers/isdn/hisax/bkm_a8.c | 359 + drivers/isdn/hisax/callc.c | 233 - drivers/isdn/hisax/config.c | 902 +-- drivers/isdn/hisax/diva.c | 1328 +++-- drivers/isdn/hisax/elsa.c | 1210 ++--- drivers/isdn/hisax/elsa_cs.c | 32 drivers/isdn/hisax/elsa_ser.c | 142 drivers/isdn/hisax/enternow.h | 9 drivers/isdn/hisax/enternow_pci.c | 363 - drivers/isdn/hisax/gazel.c | 877 ++- drivers/isdn/hisax/hfc_2bds0.c | 369 + drivers/isdn/hisax/hfc_2bds0.h | 4 drivers/isdn/hisax/hfc_2bs0.c | 178 drivers/isdn/hisax/hfc_2bs0.h | 3 drivers/isdn/hisax/hfc_pci.c | 747 ++- drivers/isdn/hisax/hfc_pci.h | 48 drivers/isdn/hisax/hfc_sx.c | 623 +- drivers/isdn/hisax/hfc_usb.c | 1667 +++++++ drivers/isdn/hisax/hfcscard.c | 268 - drivers/isdn/hisax/hisax.h | 771 +-- drivers/isdn/hisax/hisax_cfg.h | 64 drivers/isdn/hisax/hisax_debug.h | 2 drivers/isdn/hisax/hisax_fcpcipnp.c | 217 drivers/isdn/hisax/hisax_fcpcipnp.h | 21 drivers/isdn/hisax/hisax_isac.c | 8 drivers/isdn/hisax/hisax_isac.h | 16 drivers/isdn/hisax/hscx.c | 269 - drivers/isdn/hisax/hscx.h | 14 drivers/isdn/hisax/hscx_irq.c | 267 - drivers/isdn/hisax/icc.c | 401 + drivers/isdn/hisax/icc.h | 8 drivers/isdn/hisax/ipac.h | 77 drivers/isdn/hisax/ipacx.c | 734 ++- drivers/isdn/hisax/ipacx.h | 8 drivers/isdn/hisax/isac.c | 395 + drivers/isdn/hisax/isac.h | 10 drivers/isdn/hisax/isar.c | 573 +- drivers/isdn/hisax/isar.h | 12 drivers/isdn/hisax/isdnhdlc.c | 669 ++ drivers/isdn/hisax/isdnhdlc.h | 72 drivers/isdn/hisax/isdnl1.c | 82 drivers/isdn/hisax/isdnl1.h | 574 -- drivers/isdn/hisax/isdnl2.c | 217 drivers/isdn/hisax/isdnl3.c | 38 drivers/isdn/hisax/isurf.c | 282 - drivers/isdn/hisax/ix1_micro.c | 305 - drivers/isdn/hisax/jade.c | 250 - drivers/isdn/hisax/jade.h | 7 drivers/isdn/hisax/jade_irq.c | 167 drivers/isdn/hisax/l3_1tr6.c | 158 drivers/isdn/hisax/l3dss1.c | 438 - drivers/isdn/hisax/l3ni1.c | 412 - drivers/isdn/hisax/mic.c | 247 - drivers/isdn/hisax/netjet.c | 228 - drivers/isdn/hisax/netjet.h | 14 drivers/isdn/hisax/niccy.c | 375 - drivers/isdn/hisax/nj_s.c | 303 - drivers/isdn/hisax/nj_u.c | 253 - drivers/isdn/hisax/q931.c | 71 drivers/isdn/hisax/s0box.c | 242 - drivers/isdn/hisax/saphir.c | 273 - drivers/isdn/hisax/sedlbauer.c | 1072 ++-- drivers/isdn/hisax/sedlbauer_cs.c | 31 drivers/isdn/hisax/sportster.c | 245 - drivers/isdn/hisax/st5481.h | 30 drivers/isdn/hisax/st5481_b.c | 43 drivers/isdn/hisax/st5481_d.c | 28 drivers/isdn/hisax/st5481_init.c | 9 drivers/isdn/hisax/st5481_usb.c | 10 drivers/isdn/hisax/tei.c | 50 drivers/isdn/hisax/teleint.c | 247 - drivers/isdn/hisax/teles0.c | 379 + drivers/isdn/hisax/teles3.c | 556 +- drivers/isdn/hisax/teles_cs.c | 549 ++ drivers/isdn/hisax/telespci.c | 374 - drivers/isdn/hisax/w6692.c | 871 ++- drivers/isdn/hisax/w6692.h | 5 drivers/isdn/i4l/Kconfig | 45 drivers/isdn/i4l/Makefile | 17 drivers/isdn/i4l/isdn_audio.c | 164 drivers/isdn/i4l/isdn_audio.h | 5 drivers/isdn/i4l/isdn_common.c | 3758 ++++++++-------- drivers/isdn/i4l/isdn_common.h | 140 drivers/isdn/i4l/isdn_concap.c | 163 drivers/isdn/i4l/isdn_concap.h | 8 drivers/isdn/i4l/isdn_net.c | 3253 ++++++++++++++ drivers/isdn/i4l/isdn_net.h | 190 drivers/isdn/i4l/isdn_ppp.c | 3534 +++++++++++---- drivers/isdn/i4l/isdn_ppp.h | 78 drivers/isdn/i4l/isdn_tty.c | 1161 ++--- drivers/isdn/i4l/isdn_tty.h | 40 drivers/isdn/i4l/isdn_ttyfax.c | 92 drivers/isdn/i4l/isdn_ttyfax.h | 5 drivers/isdn/i4l/isdn_v110.c | 188 drivers/isdn/i4l/isdn_v110.h | 22 drivers/isdn/i4l/isdn_x25iface.c | 31 drivers/isdn/i4l/isdn_x25iface.h | 11 drivers/isdn/icn/Kconfig | 2 drivers/isdn/pcbit/Kconfig | 2 drivers/isdn/sc/Kconfig | 2 drivers/isdn/tpam/Kconfig | 2 include/linux/concap.h | 3 include/linux/isdn.h | 368 + include/linux/isdn/capilli.h | 18 include/linux/isdn_ppp.h | 216 include/linux/isdnif.h | 24 141 files changed, 25844 insertions(+), 22500 deletions(-) diff -puN drivers/isdn/act2000/Kconfig~i4l drivers/isdn/act2000/Kconfig --- 25/drivers/isdn/act2000/Kconfig~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/act2000/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # config ISDN_DRV_ACT2000 tristate "IBM Active 2000 support" - depends on ISDN && ISA + depends on ISDN_I4L && ISA help Say Y here if you have an IBM Active 2000 ISDN card. In order to use this card, additional firmware is necessary, which has to be loaded diff -puN drivers/isdn/capi/capi.c~i4l drivers/isdn/capi/capi.c --- 25/drivers/isdn/capi/capi.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/capi.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: capi.c,v 1.1.4.1.2.2 2001/12/21 15:00:17 kai Exp $ +/* $Id: capi.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $ * * CAPI 2.0 Interface for Linux * @@ -44,7 +44,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.1.4.1.2.2 $"; +static char *revision = "$Revision: 1.1.2.3 $"; MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); @@ -203,7 +203,7 @@ static struct capiminor *capiminor_alloc struct list_head *l; unsigned int minor = 0; unsigned long flags; - + mp = kmalloc(sizeof(*mp), GFP_ATOMIC); if (!mp) { printk(KERN_ERR "capi: can't alloc capiminor\n"); @@ -220,19 +220,24 @@ static struct capiminor *capiminor_alloc skb_queue_head_init(&mp->outqueue); write_lock_irqsave(&capiminor_list_lock, flags); - list_for_each(l, &capiminor_list) { - p = list_entry(l, struct capiminor, list); - if (p->minor > minor) { - mp->minor = minor; - list_add_tail(&mp->list, &p->list); - break; + if (list_empty(&capiminor_list)) { + list_add(&mp->list, &capiminor_list); + write_unlock_irqrestore(&capiminor_list_lock, flags); + } else { + list_for_each(l, &capiminor_list) { + p = list_entry(l, struct capiminor, list); + if (p->minor > minor) { + mp->minor = minor; + list_add_tail(&mp->list, &p->list); + break; + } + minor++; + } + write_unlock_irqrestore(&capiminor_list_lock, flags); + if (l == &capiminor_list) { + kfree(mp); + return NULL; } - minor++; - } - write_unlock_irqrestore(&capiminor_list_lock, flags); - if (l == &capiminor_list) { - kfree(mp); - return NULL; } return mp; } @@ -297,7 +302,7 @@ static struct capincci *capincci_alloc(s printk(KERN_DEBUG "set mp->nccip\n"); #endif #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - capifs_new_ncci(0, mp->minor, MKDEV(capi_ttymajor, mp->minor)); + capifs_new_ncci(mp->minor, MKDEV(capi_ttymajor, mp->minor)); #endif } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -322,8 +327,7 @@ static void capincci_free(struct capidev #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if ((mp = np->minorp) != 0) { #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - capifs_free_ncci('r', mp->minor); - capifs_free_ncci(0, mp->minor); + capifs_free_ncci(mp->minor); #endif if (mp->tty) { mp->nccip = 0; diff -puN drivers/isdn/capi/capidrv.c~i4l drivers/isdn/capi/capidrv.c --- 25/drivers/isdn/capi/capidrv.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/capidrv.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: capidrv.c,v 1.39.6.7 2001/09/23 22:24:33 kai Exp $ +/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * @@ -34,7 +34,7 @@ #include #include "capidrv.h" -static char *revision = "$Revision: 1.39.6.7 $"; +static char *revision = "$Revision: 1.1.2.2 $"; static int debugmode = 0; MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux"); @@ -1263,6 +1263,10 @@ static void handle_ncci(_cmsg * cmsg) goto ignored; case CAPI_DATA_B3_CONF: /* ncci */ + if (cmsg->Info) { + printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n", + cmsg->Info, capi_info2str(cmsg->Info)); + } if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) goto notfound; @@ -1368,7 +1372,7 @@ static _cmsg s_cmsg; static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) { capi_message2cmsg(&s_cmsg, skb->data); - if (debugmode > 2) + if (debugmode > 3) printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n", ap->applid, capi_cmsg2str(&s_cmsg)); @@ -1825,7 +1829,7 @@ static int if_sendbuf(int id, int channe id); return 0; } - if (debugmode > 1) + if (debugmode > 4) printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n", card->contrnr, len, skb, doack); bchan = &card->bchans[channel % card->nbchan]; @@ -1866,6 +1870,9 @@ static int if_sendbuf(int id, int channe nccip->datahandle++; return len; } + if (debugmode > 3) + printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", + card->contrnr, errcode, capi_info2str(errcode)); (void)capidrv_del_ack(nccip, datahandle); dev_kfree_skb(nskb); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; @@ -1876,6 +1883,9 @@ static int if_sendbuf(int id, int channe nccip->datahandle++; return len; } + if (debugmode > 3) + printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", + card->contrnr, errcode, capi_info2str(errcode)); skb_pull(skb, msglen); (void)capidrv_del_ack(nccip, datahandle); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; diff -puN drivers/isdn/capi/capifs.c~i4l drivers/isdn/capi/capifs.c --- 25/drivers/isdn/capi/capifs.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/capifs.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: capifs.c,v 1.14.6.8 2001/09/23 22:24:33 kai Exp $ +/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $ * * Copyright 2000 by Carsten Paeth * @@ -20,99 +20,75 @@ MODULE_DESCRIPTION("CAPI4Linux: /dev/cap MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -static char *revision = "$Revision: 1.14.6.8 $"; +/* ------------------------------------------------------------------ */ + +static char *revision = "$Revision: 1.1.2.3 $"; + +/* ------------------------------------------------------------------ */ -struct options { +#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') + +static struct vfsmount *capifs_mnt; +static struct dentry *capifs_root; + +static struct { int setuid; int setgid; uid_t uid; gid_t gid; umode_t mode; -}; -static struct options options = {.mode = 0600}; - -#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') +} config = {.mode = 0600}; /* ------------------------------------------------------------------ */ - -static int capifs_parse_options(char *s, struct options *p) +static int capifs_remount(struct super_block *s, int *flags, char *data) { int setuid = 0; int setgid = 0; uid_t uid = 0; gid_t gid = 0; umode_t mode = 0600; - char *this_char, *value; + char *this_char; - if (!s) - return 0; - - while ((this_char = strsep(&s, ",")) != NULL) { + this_char = NULL; + while ((this_char = strsep(&data, ",")) != NULL) { + int n; + char dummy; if (!*this_char) continue; - if ((value = strchr(this_char,'=')) != NULL) - *value++ = 0; - if (!strcmp(this_char,"uid")) { - if (!value || !*value) - return 1; - uid = simple_strtoul(value,&value,0); - if (*value) - return 1; + if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) { setuid = 1; - } - else if (!strcmp(this_char,"gid")) { - if (!value || !*value) - return 1; - gid = simple_strtoul(value,&value,0); - if (*value) - return 1; + uid = n; + } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) { setgid = 1; + gid = n; + } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) + mode = n & ~S_IFMT; + else { + printk("capifs: called with bogus options\n"); + return -EINVAL; } - else if (!strcmp(this_char,"mode")) { - if (!value || !*value) - return 1; - mode = simple_strtoul(value,&value,8); - if (*value) - return 1; - } - } - p->setuid = setuid; - p->setgid = setgid; - p->uid = uid; - p->gid = gid; - p->mode = mode & ~S_IFMT; - - return 0; -} - -static int capifs_remount(struct super_block *s, int *flags, char *data) -{ - struct options new; - if (capifs_parse_options(data, &new)) { - printk("capifs: called with bogus options\n"); - return -EINVAL; } - options = new; + config.setuid = setuid; + config.setgid = setgid; + config.uid = uid; + config.gid = gid; + config.mode = mode; return 0; } - static struct super_operations capifs_sops = { .statfs = simple_statfs, .remount_fs = capifs_remount, }; -static int capifs_fill_super(struct super_block *s, void *data, int silent) + +static int +capifs_fill_super(struct super_block *s, void *data, int silent) { struct inode * inode; - if (capifs_parse_options(data, &options)) { - printk("capifs: called with bogus options\n"); - return -EINVAL; - } - s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = CAPIFS_SUPER_MAGIC; @@ -120,24 +96,25 @@ static int capifs_fill_super(struct supe inode = new_inode(s); if (!inode) - return -ENOMEM; + goto fail; + inode->i_ino = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = 0; inode->i_blksize = 1024; inode->i_uid = inode->i_gid = 0; - inode->i_ino = 1; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; inode->i_nlink = 2; - s->s_root = d_alloc_root(inode); - if (!s->s_root) { - printk("capifs: get root dentry failed\n"); - iput(inode); - return -ENOMEM; - } - return 0; + capifs_root = s->s_root = d_alloc_root(inode); + if (s->s_root) + return 0; + + printk("capifs: get root dentry failed\n"); + iput(inode); +fail: + return -ENOMEM; } static struct super_block *capifs_get_sb(struct file_system_type *fs_type, @@ -153,78 +130,48 @@ static struct file_system_type capifs_fs .kill_sb = kill_anon_super, }; -static struct vfsmount *capifs_mnt; -static int entry_count; - -static int grab_instance(void) -{ - return simple_pin_fs("capifs", &capifs_mnt, &entry_count); -} - -static void drop_instance(void) -{ - return simple_release_fs(&capifs_mnt, &entry_count); -} - -static struct dentry *get_node(int type, int num) +static struct dentry *get_node(int num) { char s[10]; - int len; - struct dentry *root = capifs_mnt->mnt_root; - if (type) - len = sprintf(s, "%d", num); - else - len = sprintf(s, "%c%d", type, num); + struct dentry *root = capifs_root; down(&root->d_inode->i_sem); - return lookup_one_len(s, root, len); + return lookup_one_len(s, root, sprintf(s, "%d", num)); } -void capifs_new_ncci(char type, unsigned int num, dev_t device) +void capifs_new_ncci(unsigned int number, dev_t device) { - struct super_block *sb; struct dentry *dentry; - struct inode *inode; - - if (grab_instance() < 0) + struct inode *inode = new_inode(capifs_mnt->mnt_sb); + if (!inode) return; - sb = capifs_mnt->mnt_sb; - inode = new_inode(sb); - if (inode) { - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_blocks = 0; - inode->i_blksize = 1024; - inode->i_uid = options.setuid ? options.uid : current->fsuid; - inode->i_gid = options.setgid ? options.gid : current->fsgid; - inode->i_nlink = 1; - init_special_inode(inode, S_IFCHR | options.mode, device); - dentry = get_node(type, num); - if (!IS_ERR(dentry) && !dentry->d_inode) { - grab_instance(); - d_instantiate(dentry, inode); - } else - iput(inode); - up(&sb->s_root->d_inode->i_sem); - } - drop_instance(); + inode->i_ino = number+2; + inode->i_blksize = 1024; + inode->i_uid = config.setuid ? config.uid : current->fsuid; + inode->i_gid = config.setgid ? config.gid : current->fsgid; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + init_special_inode(inode, S_IFCHR|config.mode, device); + //inode->i_op = &capifs_file_inode_operations; + + dentry = get_node(number); + if (!IS_ERR(dentry) && !dentry->d_inode) + d_instantiate(dentry, inode); + up(&capifs_root->d_inode->i_sem); } -void capifs_free_ncci(char type, unsigned int num) +void capifs_free_ncci(unsigned int number) { - if (grab_instance() == 0) { - struct dentry *dentry = get_node(type, num); - if (!IS_ERR(dentry)) { - struct inode *inode = dentry->d_inode; - if (inode) { - inode->i_nlink--; - d_delete(dentry); - dput(dentry); - drop_instance(); - } + struct dentry *dentry = get_node(number); + + if (!IS_ERR(dentry)) { + struct inode *inode = dentry->d_inode; + if (inode) { + inode->i_nlink--; + d_delete(dentry); dput(dentry); } - up(&capifs_mnt->mnt_root->d_inode->i_sem); - drop_instance(); + dput(dentry); } + up(&capifs_root->d_inode->i_sem); } static int __init capifs_init(void) @@ -241,14 +188,20 @@ static int __init capifs_init(void) strcpy(rev, "1.0"); err = register_filesystem(&capifs_fs_type); + if (!err) { + capifs_mnt = kern_mount(&capifs_fs_type); + if (IS_ERR(capifs_mnt)) + err = PTR_ERR(capifs_mnt); + } if (!err) printk(KERN_NOTICE "capifs: Rev %s\n", rev); - return 0; + return err; } static void __exit capifs_exit(void) { unregister_filesystem(&capifs_fs_type); + mntput(capifs_mnt); } EXPORT_SYMBOL(capifs_new_ncci); diff -puN drivers/isdn/capi/capifs.h~i4l drivers/isdn/capi/capifs.h --- 25/drivers/isdn/capi/capifs.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/capifs.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: capifs.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $ +/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $ * * Copyright 2000 by Carsten Paeth * @@ -7,5 +7,5 @@ * */ -void capifs_new_ncci(char type, unsigned int num, dev_t device); -void capifs_free_ncci(char type, unsigned int num); +void capifs_new_ncci(unsigned int num, dev_t device); +void capifs_free_ncci(unsigned int num); diff -puN drivers/isdn/capi/kcapi.c~i4l drivers/isdn/capi/kcapi.c --- 25/drivers/isdn/capi/kcapi.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/kcapi.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: kcapi.c,v 1.21.6.8 2001/09/23 22:24:33 kai Exp $ +/* $Id: kcapi.c,v 1.1.2.4 2004/02/10 01:07:11 keil Exp $ * * Kernel CAPI 2.0 Module * @@ -31,7 +31,7 @@ #include #endif -static char *revision = "$Revision: 1.21.6.8 $"; +static char *revision = "$Revision: 1.1.2.4 $"; /* ------------------------------------------------------------- */ @@ -61,7 +61,7 @@ static char capi_manufakturer[64] = "AVM #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) LIST_HEAD(capi_drivers); -spinlock_t capi_drivers_lock = SPIN_LOCK_UNLOCKED; +rwlock_t capi_drivers_list_lock = RW_LOCK_UNLOCKED; struct capi20_appl *capi_applications[CAPI_MAXAPPL]; struct capi_ctr *capi_cards[CAPI_MAXCONTR]; @@ -309,12 +309,10 @@ static void recv_handler(void *dummy) continue; } - if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 - && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) ap->nrecvdatapkt++; - } else { + else ap->nrecvctlpkt++; - } ap->recv_message(ap, skb); } } @@ -498,6 +496,28 @@ int detach_capi_ctr(struct capi_ctr *car EXPORT_SYMBOL(detach_capi_ctr); +void register_capi_driver(struct capi_driver *driver) +{ + unsigned long flags; + + write_lock_irqsave(&capi_drivers_list_lock, flags); + list_add_tail(&driver->list, &capi_drivers); + write_unlock_irqrestore(&capi_drivers_list_lock, flags); +} + +EXPORT_SYMBOL(register_capi_driver); + +void unregister_capi_driver(struct capi_driver *driver) +{ + unsigned long flags; + + write_lock_irqsave(&capi_drivers_list_lock, flags); + list_del(&driver->list); + write_unlock_irqrestore(&capi_drivers_list_lock, flags); +} + +EXPORT_SYMBOL(unregister_capi_driver); + /* ------------------------------------------------------------- */ /* -------- CAPI2.0 Interface ---------------------------------- */ /* ------------------------------------------------------------- */ @@ -704,12 +724,68 @@ EXPORT_SYMBOL(capi20_get_profile); static int old_capi_manufacturer(unsigned int cmd, void *data) { avmb1_loadandconfigdef ldef; + avmb1_extcarddef cdef; avmb1_resetdef rdef; + capicardparams cparams; struct capi_ctr *card; + struct capi_driver *driver = 0; capiloaddata ldata; + struct list_head *l; + unsigned long flags; int retval; switch (cmd) { + case AVMB1_ADDCARD: + case AVMB1_ADDCARD_WITH_TYPE: + if (cmd == AVMB1_ADDCARD) { + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(avmb1_carddef)))) + return retval; + cdef.cardtype = AVM_CARDTYPE_B1; + } else { + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(avmb1_extcarddef)))) + return retval; + } + cparams.port = cdef.port; + cparams.irq = cdef.irq; + cparams.cardnr = cdef.cardnr; + + read_lock_irqsave(&capi_drivers_list_lock, flags); + switch (cdef.cardtype) { + case AVM_CARDTYPE_B1: + list_for_each(l, &capi_drivers) { + driver = list_entry(l, struct capi_driver, list); + if (strcmp(driver->name, "b1isa") == 0) + break; + } + break; + case AVM_CARDTYPE_T1: + list_for_each(l, &capi_drivers) { + driver = list_entry(l, struct capi_driver, list); + if (strcmp(driver->name, "t1isa") == 0) + break; + } + break; + default: + driver = 0; + break; + } + if (!driver) { + read_unlock_irqrestore(&capi_drivers_list_lock, flags); + printk(KERN_ERR "kcapi: driver not loaded.\n"); + return -EIO; + } + if (!driver->add_card) { + read_unlock_irqrestore(&capi_drivers_list_lock, flags); + printk(KERN_ERR "kcapi: driver has no add card function.\n"); + return -EIO; + } + + retval = driver->add_card(driver, &cparams); + read_unlock_irqrestore(&capi_drivers_list_lock, flags); + return retval; + case AVMB1_LOAD: case AVMB1_LOAD_AND_CONFIG: @@ -832,6 +908,43 @@ int capi20_manufacturer(unsigned int cmd card->cnr, card->traceflag); return 0; } + case KCAPI_CMD_ADDCARD: + { + struct list_head *l; + struct capi_driver *driver = 0; + capicardparams cparams; + kcapi_carddef cdef; + int retval; + + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(cdef)))) + return retval; + + cparams.port = cdef.port; + cparams.irq = cdef.irq; + cparams.membase = cdef.membase; + cparams.cardnr = cdef.cardnr; + cparams.cardtype = 0; + cdef.driver[sizeof(cdef.driver)-1] = 0; + + list_for_each(l, &capi_drivers) { + driver = list_entry(l, struct capi_driver, list); + if (strcmp(driver->name, cdef.driver) == 0) + break; + } + if (driver == 0) { + printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", + cdef.driver); + return -ESRCH; + } + + if (!driver->add_card) { + printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver); + return -EIO; + } + + return driver->add_card(driver, &cparams); + } default: printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n", diff -puN drivers/isdn/capi/kcapi.h~i4l drivers/isdn/capi/kcapi.h --- 25/drivers/isdn/capi/kcapi.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/kcapi.h 2004-02-09 22:19:20.000000000 -0800 @@ -15,10 +15,13 @@ #include #include +#ifdef KCAPI_DEBUG #define DBG(format, arg...) do { \ printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ } while (0) - +#else +#define DBG(format, arg...) /* */ +#endif enum { CARD_DETECTED = 1, @@ -27,7 +30,7 @@ enum { }; extern struct list_head capi_drivers; -extern spinlock_t capi_drivers_lock; +extern rwlock_t capi_drivers_list_lock; extern struct capi20_appl *capi_applications[CAPI_MAXAPPL]; extern struct capi_ctr *capi_cards[CAPI_MAXCONTR]; diff -puN drivers/isdn/capi/kcapi_proc.c~i4l drivers/isdn/capi/kcapi_proc.c --- 25/drivers/isdn/capi/kcapi_proc.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/kcapi_proc.c 2004-02-09 22:19:20.000000000 -0800 @@ -243,16 +243,84 @@ create_seq_entry(char *name, mode_t mode // --------------------------------------------------------------------------- + +static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos) +{ + struct capi_driver *drv = 0; + struct list_head *l; + loff_t i; + + i = 0; + list_for_each(l, &capi_drivers) { + drv = list_entry(l, struct capi_driver, list); + if (i++ == pos) + return drv; + } + return 0; +} + +static void *capi_driver_start(struct seq_file *seq, loff_t *pos) +{ + struct capi_driver *drv; + read_lock(&capi_drivers_list_lock); + drv = capi_driver_get_idx(*pos); + return drv; +} + +static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct capi_driver *drv = (struct capi_driver *)v; + ++*pos; + if (drv->list.next == &capi_drivers) return 0; + return list_entry(drv->list.next, struct capi_driver, list); +} + +static void capi_driver_stop(struct seq_file *seq, void *v) +{ + read_unlock(&capi_drivers_list_lock); +} + +static int capi_driver_show(struct seq_file *seq, void *v) +{ + struct capi_driver *drv = (struct capi_driver *)v; + seq_printf(seq, "%-32s %s\n", drv->name, drv->revision); + return 0; +} + +struct seq_operations seq_capi_driver_ops = { + .start = capi_driver_start, + .next = capi_driver_next, + .stop = capi_driver_stop, + .show = capi_driver_show, +}; + +static int +seq_capi_driver_open(struct inode *inode, struct file *file) +{ + int err; + err = seq_open(file, &seq_capi_driver_ops); + return err; +} + +static struct file_operations proc_driver_ops = { + .open = seq_capi_driver_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +// --------------------------------------------------------------------------- + void __init kcapi_proc_init(void) { proc_mkdir("capi", NULL); proc_mkdir("capi/controllers", NULL); - proc_mkdir("capi/drivers", NULL); create_seq_entry("capi/controller", 0, &proc_controller_ops); create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops); create_seq_entry("capi/applications", 0, &proc_applications_ops); create_seq_entry("capi/applstats", 0, &proc_applstats_ops); + create_seq_entry("capi/driver", 0, &proc_driver_ops); } void __exit @@ -263,7 +331,6 @@ kcapi_proc_exit(void) remove_proc_entry("capi/contrstats", NULL); remove_proc_entry("capi/applications", NULL); remove_proc_entry("capi/applstats", NULL); - remove_proc_entry("capi/drivers", NULL); remove_proc_entry("capi/controllers", NULL); remove_proc_entry("capi", NULL); } diff -puN drivers/isdn/capi/Kconfig~i4l drivers/isdn/capi/Kconfig --- 25/drivers/isdn/capi/Kconfig~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/capi/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -44,7 +44,7 @@ config ISDN_CAPI_CAPIFS config ISDN_CAPI_CAPIDRV tristate "CAPI2.0 capidrv interface support" - depends on ISDN_CAPI && ISDN + depends on ISDN_CAPI && ISDN_I4L help This option provides the glue code to hook up CAPI driven cards to the legacy isdn4linux link layer. If you have a card which is diff -puN drivers/isdn/hardware/avm/b1.c~i4l drivers/isdn/hardware/avm/b1.c --- 25/drivers/isdn/hardware/avm/b1.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/b1.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: b1.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ +/* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ * * Common module for AVM B1 cards. * @@ -28,7 +28,7 @@ #include #include -static char *revision = "$Revision: 1.1.4.1.2.1 $"; +static char *revision = "$Revision: 1.1.2.2 $"; /* ------------------------------------------------------------- */ @@ -76,7 +76,7 @@ avmcard *b1_alloc_card(int nr_controller kfree(card); return 0; } - memset(cinfo, 0, sizeof(*cinfo)); + memset(cinfo, 0, sizeof(*cinfo) * nr_controllers); card->ctrlinfo = cinfo; for (i = 0; i < nr_controllers; i++) { @@ -308,14 +308,13 @@ int b1_load_firmware(struct capi_ctr *ct return -EIO; } - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_setinterrupt(port, card->irq, card->cardtype); b1_put_byte(port, SEND_INIT); b1_put_word(port, CAPI_MAXAPPL); b1_put_word(port, AVM_NCCI_PER_CHANNEL*2); b1_put_word(port, ctrl->cnr - 1); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); return 0; } @@ -348,15 +347,14 @@ void b1_register_appl(struct capi_ctr *c else nconn = ctrl->profile.nbchannel * -want; if (nconn == 0) nconn = ctrl->profile.nbchannel; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_REGISTER); b1_put_word(port, appl); b1_put_word(port, 1024 * (nconn+1)); b1_put_word(port, nconn); b1_put_word(port, rp->datablkcnt); b1_put_word(port, rp->datablklen); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); } void b1_release_appl(struct capi_ctr *ctrl, u16 appl) @@ -368,11 +366,10 @@ void b1_release_appl(struct capi_ctr *ct capilib_release_appl(&cinfo->ncci_head, appl); - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_RELEASE); b1_put_word(port, appl); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); } u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) @@ -396,20 +393,18 @@ u16 b1_send_message(struct capi_ctr *ctr dlen = CAPIMSG_DATALEN(skb->data); - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_DATA_B3_REQ); b1_put_slice(port, skb->data, len); b1_put_slice(port, skb->data + len, dlen); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); } else { retval = CAPI_NOERROR; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_MESSAGE); b1_put_slice(port, skb->data, len); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); } out: dev_kfree_skb_any(skb); @@ -505,9 +500,14 @@ irqreturn_t b1_interrupt(int interrupt, unsigned DataB3Len; unsigned NCCI; unsigned WindowSize; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); - if (!b1_rx_full(card->port)) - return IRQ_NONE; + if (!b1_rx_full(card->port)) { + spin_unlock_irqrestore(&card->lock, flags); + return IRQ_NONE; + } b1cmd = b1_get_byte(card->port); @@ -518,6 +518,7 @@ irqreturn_t b1_interrupt(int interrupt, ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); DataB3Len = b1_get_slice(card->port, card->databuf); + spin_unlock_irqrestore(&card->lock, flags); if (MsgLen < 30) { /* not CAPI 64Bit */ memset(card->msgbuf+MsgLen, 0, 30-MsgLen); @@ -538,6 +539,7 @@ irqreturn_t b1_interrupt(int interrupt, ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); + spin_unlock_irqrestore(&card->lock, flags); if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { printk(KERN_ERR "%s: incoming packet dropped\n", card->name); @@ -557,6 +559,7 @@ irqreturn_t b1_interrupt(int interrupt, ApplId = b1_get_word(card->port); NCCI = b1_get_word(card->port); WindowSize = b1_get_word(card->port); + spin_unlock_irqrestore(&card->lock, flags); capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); @@ -566,6 +569,7 @@ irqreturn_t b1_interrupt(int interrupt, ApplId = b1_get_word(card->port); NCCI = b1_get_word(card->port); + spin_unlock_irqrestore(&card->lock, flags); if (NCCI != 0xffffffff) capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); @@ -574,16 +578,19 @@ irqreturn_t b1_interrupt(int interrupt, case RECEIVE_START: /* b1_put_byte(card->port, SEND_POLLACK); */ + spin_unlock_irqrestore(&card->lock, flags); capi_ctr_resume_output(ctrl); break; case RECEIVE_STOP: + spin_unlock_irqrestore(&card->lock, flags); capi_ctr_suspend_output(ctrl); break; case RECEIVE_INIT: cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf); + spin_unlock_irqrestore(&card->lock, flags); b1_parse_version(cinfo); printk(KERN_INFO "%s: %s-card (%s) now active\n", card->name, @@ -595,6 +602,7 @@ irqreturn_t b1_interrupt(int interrupt, case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); + spin_unlock_irqrestore(&card->lock, flags); card->msgbuf[MsgLen] = 0; while ( MsgLen > 0 && ( card->msgbuf[MsgLen-1] == '\n' @@ -608,6 +616,7 @@ irqreturn_t b1_interrupt(int interrupt, case RECEIVE_DEBUGMSG: MsgLen = b1_get_slice(card->port, card->msgbuf); + spin_unlock_irqrestore(&card->lock, flags); card->msgbuf[MsgLen] = 0; while ( MsgLen > 0 && ( card->msgbuf[MsgLen-1] == '\n' @@ -619,9 +628,11 @@ irqreturn_t b1_interrupt(int interrupt, break; case 0xff: + spin_unlock_irqrestore(&card->lock, flags); printk(KERN_ERR "%s: card removed ?\n", card->name); return IRQ_NONE; default: + spin_unlock_irqrestore(&card->lock, flags); printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", card->name, b1cmd); return IRQ_HANDLED; diff -puN drivers/isdn/hardware/avm/b1dma.c~i4l drivers/isdn/hardware/avm/b1dma.c --- 25/drivers/isdn/hardware/avm/b1dma.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/b1dma.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: b1dma.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ +/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ * * Common module for AVM B1 cards that support dma with AMCC * @@ -28,11 +28,9 @@ #include #include -#if BITS_PER_LONG != 32 -#error FIXME: driver requires 32-bit platform -#endif +static char *revision = "$Revision: 1.1.2.3 $"; -static char *revision = "$Revision: 1.1.4.1.2.1 $"; +#undef CONFIG_B1DMA_DEBUG /* ------------------------------------------------------------- */ @@ -239,7 +237,7 @@ void b1dma_reset(avmcard *card) /* ------------------------------------------------------------- */ -int b1dma_detect(avmcard *card) +static int b1dma_detect(avmcard *card) { b1dma_writel(card, 0, AMCC_MCSR); mdelay(10); @@ -578,11 +576,16 @@ static void b1dma_handle_rx(avmcard *car static void b1dma_handle_interrupt(avmcard *card) { - u32 status = b1dma_readl(card, AMCC_INTCSR); + u32 status; u32 newcsr; - if ((status & ANY_S5933_INT) == 0) + spin_lock(&card->lock); + + status = b1dma_readl(card, AMCC_INTCSR); + if ((status & ANY_S5933_INT) == 0) { + spin_unlock(&card->lock); return; + } newcsr = card->csr | (status & ALL_INT); if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; @@ -593,20 +596,28 @@ static void b1dma_handle_interrupt(avmca struct avmcard_dmainfo *dma = card->dma; u32 rxlen; if (card->dma->recvlen == 0) { - dma->recvlen = *((u32 *)dma->recvbuf.dmabuf); - rxlen = (dma->recvlen + 3) & ~3; - b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR); - b1dma_writel(card, rxlen, AMCC_RXLEN); + rxlen = b1dma_readl(card, AMCC_RXLEN); + if (rxlen == 0) { + dma->recvlen = *((u32 *)dma->recvbuf.dmabuf); + rxlen = (dma->recvlen + 3) & ~3; + b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR); + b1dma_writel(card, rxlen, AMCC_RXLEN); +#ifdef CONFIG_B1DMA_DEBUG + } else { + printk(KERN_ERR "%s: rx not complete (%d).\n", + card->name, rxlen); +#endif + } } else { + spin_unlock(&card->lock); b1dma_handle_rx(card); dma->recvlen = 0; + spin_lock(&card->lock); b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR); b1dma_writel(card, 4, AMCC_RXLEN); } } - spin_lock(&card->lock); - if ((status & TX_TC_INT) != 0) { if (skb_queue_empty(&card->dma->send_queue)) card->csr &= ~EN_TX_TC_INT; @@ -736,18 +747,19 @@ void b1dma_reset_ctr(struct capi_ctr *ct { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; + unsigned long flags; + spin_lock_irqsave(&card->lock, flags); b1dma_reset(card); + spin_unlock_irqrestore(&card->lock, flags); memset(cinfo->version, 0, sizeof(cinfo->version)); capilib_release(&cinfo->ncci_head); capi_ctr_reseted(ctrl); } - /* ------------------------------------------------------------- */ - void b1dma_register_appl(struct capi_ctr *ctrl, u16 appl, capi_register_params *rp) @@ -844,6 +856,7 @@ int b1dmactl_read_proc(char *page, char int len = 0; char *s; u32 txoff, txlen, rxoff, rxlen, csr; + unsigned long flags; len += sprintf(page+len, "%-16s %s\n", "name", card->name); len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); @@ -896,6 +909,9 @@ int b1dmactl_read_proc(char *page, char } len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + spin_lock_irqsave(&card->lock, flags); + txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr; txlen = b1dma_readl(card, AMCC_TXLEN); @@ -904,6 +920,8 @@ int b1dmactl_read_proc(char *page, char csr = b1dma_readl(card, AMCC_INTCSR); + spin_unlock_irqrestore(&card->lock, flags); + len += sprintf(page+len, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr); len += sprintf(page+len, "%-16s 0x%lx\n", diff -puN drivers/isdn/hardware/avm/b1isa.c~i4l drivers/isdn/hardware/avm/b1isa.c --- 25/drivers/isdn/hardware/avm/b1isa.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/b1isa.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: b1isa.c,v 1.10.6.6 2001/09/23 22:24:33 kai Exp $ +/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ * * Module for AVM B1 ISA-card. * @@ -27,6 +27,10 @@ /* ------------------------------------------------------------- */ +static char *revision = "$Revision: 1.1.2.3 $"; + +/* ------------------------------------------------------------- */ + MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); @@ -56,7 +60,7 @@ static void b1isa_remove(struct pci_dev static char *b1isa_procinfo(struct capi_ctr *ctrl); -static int __init b1isa_probe(struct pci_dev *pdev) +static int b1isa_probe(struct pci_dev *pdev) { avmctrl_info *cinfo; avmcard *card; @@ -108,6 +112,7 @@ static int __init b1isa_probe(struct pci b1_reset(card->port); b1_getrevision(card); + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "b1isa"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1_register_appl; @@ -118,7 +123,6 @@ static int __init b1isa_probe(struct pci cinfo->capi_ctrl.procinfo = b1isa_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { @@ -170,23 +174,56 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(MA MODULE_PARM_DESC(io, "I/O base address(es)"); MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); +static int b1isa_add_card(struct capi_driver *driver, capicardparams *data) +{ + int i; + + for (i = 0; i < MAX_CARDS; i++) { + if (isa_dev[i].resource[0].start) + continue; + + isa_dev[i].resource[0].start = data->port; + isa_dev[i].irq = data->irq; + + if (b1isa_probe(&isa_dev[i]) == 0) + return 0; + } + return -ENODEV; +} + +static struct capi_driver capi_driver_b1isa = { + .name = "b1isa", + .revision = "1.0", + .add_card = b1isa_add_card, +}; + static int __init b1isa_init(void) { + char *p; + char rev[32]; int i; - int found = 0; + + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strlcpy(rev, p + 2, 32); + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; + } else + strcpy(rev, "1.0"); for (i = 0; i < MAX_CARDS; i++) { if (!io[i]) break; isa_dev[i].resource[0].start = io[i]; - isa_dev[i].irq_resource[0].start = irq[i]; + isa_dev[i].irq = irq[i]; - if (b1isa_probe(&isa_dev[i]) == 0) - found++; + if (b1isa_probe(&isa_dev[i]) != 0) + return -ENODEV; } - if (found == 0) - return -ENODEV; + + strlcpy(capi_driver_b1isa.revision, rev, 32); + register_capi_driver(&capi_driver_b1isa); + printk(KERN_INFO "b1isa: revision %s\n", rev); return 0; } @@ -201,6 +238,7 @@ static void __exit b1isa_exit(void) b1isa_remove(&isa_dev[i]); } + unregister_capi_driver(&capi_driver_b1isa); } module_init(b1isa_init); diff -puN drivers/isdn/hardware/avm/b1pci.c~i4l drivers/isdn/hardware/avm/b1pci.c --- 25/drivers/isdn/hardware/avm/b1pci.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/b1pci.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: b1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ +/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ * * Module for AVM B1 PCI-card. * @@ -28,6 +28,10 @@ /* ------------------------------------------------------------- */ +static char *revision = "$Revision: 1.1.2.2 $"; + +/* ------------------------------------------------------------- */ + static struct pci_device_id b1pci_pci_tbl[] = { { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID }, { } /* Terminating entry */ @@ -362,13 +366,50 @@ static struct pci_driver b1pci_pci_drive .remove = __devexit_p(b1pci_pci_remove), }; +static struct capi_driver capi_driver_b1pci = { + .name = "b1pci", + .revision = "1.0", +}; +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 +static struct capi_driver capi_driver_b1pciv4 = { + .name = "b1pciv4", + .revision = "1.0", +}; +#endif + static int __init b1pci_init(void) { - return pci_module_init(&b1pci_pci_driver); + char *p; + char rev[32]; + int err; + + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strlcpy(rev, p + 2, 32); + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; + } else + strcpy(rev, "1.0"); + + + err = pci_module_init(&b1pci_pci_driver); + if (!err) { + strlcpy(capi_driver_b1pci.revision, rev, 32); + register_capi_driver(&capi_driver_b1pci); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + strlcpy(capi_driver_b1pciv4.revision, rev, 32); + register_capi_driver(&capi_driver_b1pciv4); +#endif + printk(KERN_INFO "b1pci: revision %s\n", rev); + } + return err; } static void __exit b1pci_exit(void) { + unregister_capi_driver(&capi_driver_b1pci); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + unregister_capi_driver(&capi_driver_b1pciv4); +#endif pci_unregister_driver(&b1pci_pci_driver); } diff -puN drivers/isdn/hardware/avm/b1pcmcia.c~i4l drivers/isdn/hardware/avm/b1pcmcia.c --- 25/drivers/isdn/hardware/avm/b1pcmcia.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/b1pcmcia.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: b1pcmcia.c,v 1.12.6.5 2001/09/23 22:24:33 kai Exp $ +/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * @@ -27,6 +27,10 @@ /* ------------------------------------------------------------- */ +static char *revision = "$Revision: 1.1.2.2 $"; + +/* ------------------------------------------------------------- */ + MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); @@ -186,3 +190,36 @@ EXPORT_SYMBOL(b1pcmcia_addcard_b1); EXPORT_SYMBOL(b1pcmcia_addcard_m1); EXPORT_SYMBOL(b1pcmcia_addcard_m2); EXPORT_SYMBOL(b1pcmcia_delcard); + +static struct capi_driver capi_driver_b1pcmcia = { + .name = "b1pcmcia", + .revision = "1.0", +}; + +static int __init b1pcmcia_init(void) +{ + char *p; + char rev[32]; + int err; + + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strlcpy(rev, p + 2, 32); + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; + } else + strcpy(rev, "1.0"); + + strlcpy(capi_driver_b1pcmcia.revision, rev, 32); + register_capi_driver(&capi_driver_b1pcmcia); + printk(KERN_INFO "b1pci: revision %s\n", rev); + + return 0; +} + +static void __exit b1pcmcia_exit(void) +{ + unregister_capi_driver(&capi_driver_b1pcmcia); +} + +module_init(b1pcmcia_init); +module_exit(b1pcmcia_exit); diff -puN drivers/isdn/hardware/avm/c4.c~i4l drivers/isdn/hardware/avm/c4.c --- 25/drivers/isdn/hardware/avm/c4.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/c4.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: c4.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ +/* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ * * Module for AVM C4 & C2 card. * @@ -34,6 +34,10 @@ /* ------------------------------------------------------------- */ +static char *revision = "$Revision: 1.1.2.2 $"; + +/* ------------------------------------------------------------- */ + static int suppress_pollack; static struct pci_device_id c4_pci_tbl[] = { @@ -404,18 +408,14 @@ static int c4_detect(avmcard *card) static void c4_dispatch_tx(avmcard *card) { avmcard_dmainfo *dma = card->dma; - unsigned long flags; struct sk_buff *skb; u8 cmd, subcmd; u16 len; u32 txlen; void *p; - - save_flags(flags); - cli(); + if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ - restore_flags(flags); return; } @@ -424,7 +424,6 @@ static void c4_dispatch_tx(avmcard *card #ifdef CONFIG_C4_DEBUG printk(KERN_DEBUG "%s: tx underrun\n", card->name); #endif - restore_flags(flags); return; } @@ -470,7 +469,6 @@ static void c4_dispatch_tx(avmcard *card c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM); - restore_flags(flags); dev_kfree_skb_any(skb); } @@ -664,11 +662,15 @@ static void c4_handle_rx(avmcard *card) static irqreturn_t c4_handle_interrupt(avmcard *card) { - u32 status = c4inmeml(card->mbase+DOORBELL); + u32 status; + + spin_lock(&card->lock); + status = c4inmeml(card->mbase+DOORBELL); if (status & DBELL_RESET_HOST) { u_int i; c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); + spin_unlock(&card->lock); if (card->nlogcontr == 0) return IRQ_HANDLED; printk(KERN_ERR "%s: unexpected reset\n", card->name); @@ -683,8 +685,10 @@ static irqreturn_t c4_handle_interrupt(a } status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); - if (!status) + if (!status) { + spin_unlock(&card->lock); return IRQ_HANDLED; + } c4outmeml(card->mbase+DOORBELL, status); if ((status & DBELL_UP_HOST) != 0) { @@ -705,6 +709,7 @@ static irqreturn_t c4_handle_interrupt(a c4_dispatch_tx(card); } } + spin_unlock(&card->lock); return IRQ_HANDLED; } @@ -767,6 +772,7 @@ static int queue_sendconfigword(avmcard static int queue_sendconfig(avmcard *card, char cval[4]) { struct sk_buff *skb; + unsigned long flags; void *p; skb = alloc_skb(3+4, GFP_ATOMIC); @@ -786,7 +792,10 @@ static int queue_sendconfig(avmcard *car skb_put(skb, (u8 *)p - (u8 *)skb->data); skb_queue_tail(&card->dma->send_queue, skb); + + spin_lock_irqsave(&card->lock, flags); c4_dispatch_tx(card); + spin_unlock_irqrestore(&card->lock, flags); return 0; } @@ -835,7 +844,6 @@ static int c4_load_firmware(struct capi_ { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; - unsigned long flags; int retval; if ((retval = c4_load_t4file(card, &data->firmware))) { @@ -845,9 +853,6 @@ static int c4_load_firmware(struct capi_ return retval; } - save_flags(flags); - cli(); - card->csr = 0; c4outmeml(card->mbase+MBOX_UP_LEN, 0); c4outmeml(card->mbase+MBOX_DOWN_LEN, 0); @@ -862,7 +867,6 @@ static int c4_load_firmware(struct capi_ c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr); c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); - restore_flags(flags); if (data->configuration.len > 0 && data->configuration.data) { retval = c4_send_config(card, &data->configuration); @@ -885,9 +889,14 @@ void c4_reset_ctr(struct capi_ctr *ctrl) avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; avmctrl_info *cinfo; u_int i; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); c4_reset(card); + spin_unlock_irqrestore(&card->lock, flags); + for (i=0; i < card->nr_controllers; i++) { cinfo = &card->ctrlinfo[i]; memset(cinfo->version, 0, sizeof(cinfo->version)); @@ -931,6 +940,7 @@ void c4_register_appl(struct capi_ctr *c avmcard *card = cinfo->card; struct sk_buff *skb; int want = rp->level3cnt; + unsigned long flags; int nconn; void *p; @@ -958,7 +968,10 @@ void c4_register_appl(struct capi_ctr *c skb_put(skb, (u8 *)p - (u8 *)skb->data); skb_queue_tail(&card->dma->send_queue, skb); + + spin_lock_irqsave(&card->lock, flags); c4_dispatch_tx(card); + spin_unlock_irqrestore(&card->lock, flags); } } @@ -968,6 +981,7 @@ void c4_release_appl(struct capi_ctr *ct { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; + unsigned long flags; struct sk_buff *skb; void *p; @@ -988,7 +1002,9 @@ void c4_release_appl(struct capi_ctr *ct skb_put(skb, (u8 *)p - (u8 *)skb->data); skb_queue_tail(&card->dma->send_queue, skb); + spin_lock_irqsave(&card->lock, flags); c4_dispatch_tx(card); + spin_unlock_irqrestore(&card->lock, flags); } } @@ -1000,6 +1016,7 @@ static u16 c4_send_message(struct capi_c avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; u16 retval = CAPI_NOERROR; + unsigned long flags; if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { retval = capilib_data_b3_req(&cinfo->ncci_head, @@ -1009,7 +1026,9 @@ static u16 c4_send_message(struct capi_c } if (retval == CAPI_NOERROR) { skb_queue_tail(&card->dma->send_queue, skb); + spin_lock_irqsave(&card->lock, flags); c4_dispatch_tx(card); + spin_unlock_irqrestore(&card->lock, flags); } else { dev_kfree_skb_any(skb); } @@ -1164,6 +1183,7 @@ static int c4_add_card(struct capicardpa for (i=0; i < nr_controllers ; i++) { cinfo = &card->ctrlinfo[i]; + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "c4"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = c4_register_appl; @@ -1174,7 +1194,6 @@ static int c4_add_card(struct capicardpa cinfo->capi_ctrl.procinfo = c4_procinfo; cinfo->capi_ctrl.ctr_read_proc = c4_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { @@ -1247,13 +1266,44 @@ static struct pci_driver c4_pci_driver = .remove = c4_remove, }; +static struct capi_driver capi_driver_c2 = { + .name = "c2", + .revision = "1.0", +}; + +static struct capi_driver capi_driver_c4 = { + .name = "c4", + .revision = "1.0", +}; + static int __init c4_init(void) { - return pci_module_init(&c4_pci_driver); + char *p; + char rev[32]; + int err; + + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strlcpy(rev, p + 2, 32); + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; + } else + strcpy(rev, "1.0"); + + err = pci_module_init(&c4_pci_driver); + if (!err) { + strlcpy(capi_driver_c2.revision, rev, 32); + register_capi_driver(&capi_driver_c2); + strlcpy(capi_driver_c4.revision, rev, 32); + register_capi_driver(&capi_driver_c4); + printk(KERN_INFO "c4: revision %s\n", rev); + } + return err; } static void __exit c4_exit(void) { + unregister_capi_driver(&capi_driver_c2); + unregister_capi_driver(&capi_driver_c4); pci_unregister_driver(&c4_pci_driver); } diff -puN drivers/isdn/hardware/avm/Kconfig~i4l drivers/isdn/hardware/avm/Kconfig --- 25/drivers/isdn/hardware/avm/Kconfig~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # menu "Active AVM cards" - depends on NET && ISDN_BOOL && ISDN_CAPI!=n + depends on NET && ISDN && ISDN_CAPI!=n config CAPI_AVM bool "Support AVM cards" diff -puN drivers/isdn/hardware/avm/t1isa.c~i4l drivers/isdn/hardware/avm/t1isa.c --- 25/drivers/isdn/hardware/avm/t1isa.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/t1isa.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: t1isa.c,v 1.16.6.7 2001/09/23 22:24:34 kai Exp $ +/* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ * * Module for AVM T1 HEMA-card. * @@ -29,6 +29,10 @@ /* ------------------------------------------------------------- */ +static char *revision = "$Revision: 1.1.2.3 $"; + +/* ------------------------------------------------------------- */ + MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); @@ -58,7 +62,6 @@ static int t1_detectandinit(unsigned int { unsigned char cregs[8]; unsigned char reverse_cardnr; - unsigned long flags; unsigned char dummy; int i; @@ -73,8 +76,12 @@ static int t1_detectandinit(unsigned int cregs[6] = 0; cregs[7] = 0; - save_flags(flags); - cli(); + /* + * no one else should use the ISA bus in this moment, + * but no function there to prevent this :-( + * save_flags(flags); cli(); + */ + /* board reset */ t1outp(base, T1_RESETBOARD, 0xf); mdelay(100); @@ -87,7 +94,7 @@ static int t1_detectandinit(unsigned int t1outp(base, HEMA_PAL_ID >> 4, cregs[0]); for(i=1;i<7;i++) t1outp(base, 0, cregs[i]); t1outp(base, ((base >> 4)) & 0x3, cregs[7]); - restore_flags(flags); + /* restore_flags(flags); */ mdelay(100); t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); @@ -137,6 +144,9 @@ static irqreturn_t t1isa_interrupt(int i unsigned DataB3Len; unsigned NCCI; unsigned WindowSize; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); while (b1_rx_full(card->port)) { @@ -149,6 +159,7 @@ static irqreturn_t t1isa_interrupt(int i ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); DataB3Len = t1_get_slice(card->port, card->databuf); + spin_unlock_irqrestore(&card->lock, flags); if (MsgLen < 30) { /* not CAPI 64Bit */ memset(card->msgbuf+MsgLen, 0, 30-MsgLen); @@ -169,6 +180,7 @@ static irqreturn_t t1isa_interrupt(int i ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); + spin_unlock_irqrestore(&card->lock, flags); if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { printk(KERN_ERR "%s: incoming packet dropped\n", card->name); @@ -188,6 +200,7 @@ static irqreturn_t t1isa_interrupt(int i ApplId = b1_get_word(card->port); NCCI = b1_get_word(card->port); WindowSize = b1_get_word(card->port); + spin_unlock_irqrestore(&card->lock, flags); capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); @@ -197,6 +210,7 @@ static irqreturn_t t1isa_interrupt(int i ApplId = b1_get_word(card->port); NCCI = b1_get_word(card->port); + spin_unlock_irqrestore(&card->lock, flags); if (NCCI != 0xffffffff) capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); @@ -205,16 +219,19 @@ static irqreturn_t t1isa_interrupt(int i case RECEIVE_START: b1_put_byte(card->port, SEND_POLLACK); + spin_unlock_irqrestore(&card->lock, flags); capi_ctr_resume_output(ctrl); break; case RECEIVE_STOP: + spin_unlock_irqrestore(&card->lock, flags); capi_ctr_suspend_output(ctrl); break; case RECEIVE_INIT: cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf); + spin_unlock_irqrestore(&card->lock, flags); b1_parse_version(cinfo); printk(KERN_INFO "%s: %s-card (%s) now active\n", card->name, @@ -226,6 +243,7 @@ static irqreturn_t t1isa_interrupt(int i case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); + spin_unlock_irqrestore(&card->lock, flags); card->msgbuf[MsgLen] = 0; while ( MsgLen > 0 && ( card->msgbuf[MsgLen-1] == '\n' @@ -239,6 +257,7 @@ static irqreturn_t t1isa_interrupt(int i case RECEIVE_DEBUGMSG: MsgLen = t1_get_slice(card->port, card->msgbuf); + spin_unlock_irqrestore(&card->lock, flags); card->msgbuf[MsgLen] = 0; while ( MsgLen > 0 && ( card->msgbuf[MsgLen-1] == '\n' @@ -251,9 +270,11 @@ static irqreturn_t t1isa_interrupt(int i case 0xff: + spin_unlock_irqrestore(&card->lock, flags); printk(KERN_ERR "%s: card reseted ?\n", card->name); return IRQ_HANDLED; default: + spin_unlock_irqrestore(&card->lock, flags); printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", card->name, b1cmd); return IRQ_NONE; @@ -296,14 +317,13 @@ static int t1isa_load_firmware(struct ca return -EIO; } - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_setinterrupt(port, card->irq, card->cardtype); b1_put_byte(port, SEND_INIT); b1_put_word(port, CAPI_MAXAPPL); b1_put_word(port, AVM_NCCI_PER_CHANNEL*30); b1_put_word(port, ctrl->cnr - 1); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); return 0; } @@ -349,7 +369,7 @@ static void t1isa_remove(struct pci_dev static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); static char *t1isa_procinfo(struct capi_ctr *ctrl); -static int __init t1isa_probe(struct pci_dev *pdev, int cardnr) +static int t1isa_probe(struct pci_dev *pdev, int cardnr) { avmctrl_info *cinfo; avmcard *card; @@ -401,6 +421,7 @@ static int __init t1isa_probe(struct pci t1_disable_irq(card->port); b1_reset(card->port); + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "t1isa"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1_register_appl; @@ -411,7 +432,6 @@ static int __init t1isa_probe(struct pci cinfo->capi_ctrl.procinfo = t1isa_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { @@ -456,20 +476,18 @@ static u16 t1isa_send_message(struct cap dlen = CAPIMSG_DATALEN(skb->data); - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_DATA_B3_REQ); t1_put_slice(port, skb->data, len); t1_put_slice(port, skb->data + len, dlen); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); } else { retval = CAPI_NOERROR; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); b1_put_byte(port, SEND_MESSAGE); t1_put_slice(port, skb->data, len); - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); } out: dev_kfree_skb_any(skb); @@ -509,23 +527,56 @@ MODULE_PARM_DESC(io, "I/O base address(e MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)"); +static int t1isa_add_card(struct capi_driver *driver, capicardparams *data) +{ + int i; + + for (i = 0; i < MAX_CARDS; i++) { + if (isa_dev[i].resource[0].start) + continue; + + isa_dev[i].resource[0].start = data->port; + isa_dev[i].irq = data->irq; + + if (t1isa_probe(&isa_dev[i], data->cardnr) == 0) + return 0; + } + return -ENODEV; +} + +static struct capi_driver capi_driver_t1isa = { + .name = "t1isa", + .revision = "1.0", + .add_card = t1isa_add_card, +}; + static int __init t1isa_init(void) { + char rev[32]; + char *p; int i; - int found = 0; + + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strlcpy(rev, p + 2, 32); + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; + } else + strcpy(rev, "1.0"); for (i = 0; i < MAX_CARDS; i++) { if (!io[i]) break; isa_dev[i].resource[0].start = io[i]; - isa_dev[i].irq_resource[0].start = irq[i]; + isa_dev[i].irq = irq[i]; - if (t1isa_probe(&isa_dev[i], cardnr[i]) == 0) - found++; + if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0) + return -ENODEV; } - if (found == 0) - return -ENODEV; + + strlcpy(capi_driver_t1isa.revision, rev, 32); + register_capi_driver(&capi_driver_t1isa); + printk(KERN_INFO "t1isa: revision %s\n", rev); return 0; } diff -puN drivers/isdn/hardware/avm/t1pci.c~i4l drivers/isdn/hardware/avm/t1pci.c --- 25/drivers/isdn/hardware/avm/t1pci.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/avm/t1pci.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: t1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ +/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ * * Module for AVM T1 PCI-card. * @@ -30,6 +30,8 @@ #undef CONFIG_T1PCI_POLLDEBUG /* ------------------------------------------------------------- */ +static char *revision = "$Revision: 1.1.2.2 $"; +/* ------------------------------------------------------------- */ static struct pci_device_id t1pci_pci_tbl[] = { { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID }, @@ -221,13 +223,36 @@ static struct pci_driver t1pci_pci_drive .remove = t1pci_remove, }; +static struct capi_driver capi_driver_t1pci = { + .name = "t1pci", + .revision = "1.0", +}; + static int __init t1pci_init(void) { - return pci_module_init(&t1pci_pci_driver); + char *p; + char rev[32]; + int err; + + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strlcpy(rev, p + 2, 32); + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; + } else + strcpy(rev, "1.0"); + + err = pci_module_init(&t1pci_pci_driver); + if (!err) { + strlcpy(capi_driver_t1pci.revision, rev, 32); + register_capi_driver(&capi_driver_t1pci); + printk(KERN_INFO "t1pci: revision %s\n", rev); + } + return err; } static void __exit t1pci_exit(void) { + unregister_capi_driver(&capi_driver_t1pci); pci_unregister_driver(&t1pci_pci_driver); } diff -puN drivers/isdn/hardware/eicon/Kconfig~i4l drivers/isdn/hardware/eicon/Kconfig --- 25/drivers/isdn/hardware/eicon/Kconfig~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/eicon/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # menu "Active Eicon DIVA Server cards" - depends on NET && ISDN_BOOL && ISDN_CAPI!=n + depends on NET && ISDN && ISDN_CAPI!=n config CAPI_EICON bool "Support Eicon cards" diff -puN drivers/isdn/hardware/Kconfig~i4l drivers/isdn/hardware/Kconfig --- 25/drivers/isdn/hardware/Kconfig~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hardware/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -2,32 +2,9 @@ # ISDN hardware drivers # comment "CAPI hardware drivers" - depends on NET && ISDN_BOOL && ISDN_CAPI + depends on NET && ISDN && ISDN_CAPI source "drivers/isdn/hardware/avm/Kconfig" source "drivers/isdn/hardware/eicon/Kconfig" -comment "ISDN4Linux hardware drivers" - depends on NET && ISDN_BOOL && ISDN - -source "drivers/isdn/hisax/Kconfig" - - -menu "Active cards" - depends on NET && ISDN_BOOL && ISDN!=n - -source "drivers/isdn/icn/Kconfig" - -source "drivers/isdn/pcbit/Kconfig" - -source "drivers/isdn/sc/Kconfig" - -source "drivers/isdn/act2000/Kconfig" - -source "drivers/isdn/tpam/Kconfig" - -source "drivers/isdn/hysdn/Kconfig" - -endmenu - diff -puN drivers/isdn/hisax/amd7930_fn.c~i4l drivers/isdn/hisax/amd7930_fn.c --- 25/drivers/isdn/hisax/amd7930_fn.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/amd7930_fn.c 2004-02-09 22:19:20.000000000 -0800 @@ -62,42 +62,53 @@ static void Amd7930_new_ph(struct IsdnCardState *cs); -static inline u8 -HIBYTE(u16 w) -{ - return (w >> 8) & 0xff; -} +static WORD initAMD[] = { + 0x0100, -static inline u8 -LOBYTE(u16 w) -{ - return w & 0xff; -} + 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2 + 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on) + 0x0087, 1, 0xFF, // DMR2 + 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on) + 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition ) + 0x0084, 2, 0x80, 0x00, // DRLR + 0x00C0, 1, 0x47, // PPCR1 + 0x00C8, 1, 0x01, // PPCR2 -static inline u8 -rByteAMD(struct IsdnCardState *cs, u8 reg) -{ - return cs->dc_hw_ops->read_reg(cs, reg); -} + 0x0102, + 0x0107, + 0x01A1, 1, + 0x0121, 1, + 0x0189, 2, -static inline void -wByteAMD(struct IsdnCardState *cs, u8 reg, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, reg, val); -} + 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4 + 0x0063, 2, 0x08, 0x08, // GX + 0x0064, 2, 0x08, 0x08, // GR + 0x0065, 2, 0x99, 0x00, // GER + 0x0066, 2, 0x7C, 0x8B, // STG + 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2 + 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2 + 0x0069, 1, 0x4F, // MMR1 + 0x006A, 1, 0x00, // MMR2 + 0x006C, 1, 0x40, // MMR3 + 0x0021, 1, 0x02, // INIT + 0x00A3, 1, 0x40, // LMR1 -static void -wWordAMD(struct IsdnCardState *cs, u8 reg, u16 val) + 0xFFFF +}; + + +void /* macro wWordAMD */ +WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val) { wByteAMD(cs, 0x00, reg); wByteAMD(cs, 0x01, LOBYTE(val)); wByteAMD(cs, 0x01, HIBYTE(val)); } -static u16 -rWordAMD(struct IsdnCardState *cs, u8 reg) +WORD /* macro rWordAMD */ +ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg) { - u16 res; + WORD res; /* direct access register */ if(reg < 8) { res = rByteAMD(cs, reg); @@ -112,20 +123,9 @@ rWordAMD(struct IsdnCardState *cs, u8 re return (res); } -static inline void -AmdIrqOff(struct IsdnCardState *cs) -{ - cs->dc.amd7930.setIrqMask(cs, 0); -} - -static inline void -AmdIrqOn(struct IsdnCardState *cs) -{ - cs->dc.amd7930.setIrqMask(cs, 1); -} static void -Amd7930_ph_command(struct IsdnCardState *cs, u8 command, char *s) +Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command); @@ -136,7 +136,7 @@ Amd7930_ph_command(struct IsdnCardState -static u8 i430States[] = { +static BYTE i430States[] = { // to reset F3 F4 F5 F6 F7 F8 AR from 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset @@ -150,14 +150,14 @@ static u8 i430States[] = { /* Row init - reset F3 F4 F5 F6 F7 F8 AR */ -static u8 stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; +static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; static void Amd7930_get_state(struct IsdnCardState *cs) { - u8 lsr = rByteAMD(cs, 0xA1); + BYTE lsr = rByteAMD(cs, 0xA1); cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; Amd7930_new_ph(cs); } @@ -167,8 +167,8 @@ Amd7930_get_state(struct IsdnCardState * static void Amd7930_new_ph(struct IsdnCardState *cs) { - u8 index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1; - u8 message = i430States[index]; + u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1; + u_char message = i430States[index]; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d", @@ -176,7 +176,7 @@ Amd7930_new_ph(struct IsdnCardState *cs) cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state; - /* abort transmit if necessary */ + /* abort transmit if nessesary */ if ((message & 0xf0) && (cs->tx_skb)) { wByteAMD(cs, 0x21, 0xC2); wByteAMD(cs, 0x21, 0x02); @@ -232,9 +232,9 @@ Amd7930_new_ph(struct IsdnCardState *cs) static void -Amd7930_bh(void *data) +Amd7930_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; + struct PStack *stptr; if (!cs) @@ -244,7 +244,7 @@ Amd7930_bh(void *data) debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - stptr->l2.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -267,13 +267,12 @@ Amd7930_bh(void *data) } } - static void Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag) { - u8 stat, der; - u8 *ptr; + BYTE stat, der; + BYTE *ptr; struct sk_buff *skb; @@ -317,7 +316,7 @@ Amd7930_empty_Dfifo(struct IsdnCardState QuickHex(t, cs->rcvbuf, cs->rcvidx); debugl1(cs, cs->dlog); } - /* moves received data in sk-buffer */ + /* moves recieved data in sk-buffer */ memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx); skb_queue_tail(&cs->rq, skb); } @@ -327,10 +326,10 @@ Amd7930_empty_Dfifo(struct IsdnCardState /* throw damaged packets away, reset recieve-buffer, indicate RX */ ptr = cs->rcvbuf; cs->rcvidx = 0; - sched_d_event(cs, D_RCVBUFREADY); + schedule_event(cs, D_RCVBUFREADY); } } - /* Packet too long, overflow */ + /* Packet to long, overflow */ if(cs->rcvidx >= MAX_DFRAME_LEN_L1) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun"); @@ -346,9 +345,9 @@ static void Amd7930_fill_Dfifo(struct IsdnCardState *cs) { - u16 dtcrr, dtcrw, len, count; - u8 txstat, dmr3; - u8 *ptr, *deb_ptr; + WORD dtcrr, dtcrw, len, count; + BYTE txstat, dmr3; + BYTE *ptr, *deb_ptr; if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) debugl1(cs, "Amd7930: fill_Dfifo"); @@ -414,10 +413,10 @@ Amd7930_fill_Dfifo(struct IsdnCardState } -void Amd7930_interrupt(struct IsdnCardState *cs, u8 irflags) +void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags) { - u8 dsr1, dsr2, lsr; - u16 der; + BYTE dsr1, dsr2, lsr; + WORD der; while (irflags) { @@ -443,7 +442,7 @@ void Amd7930_interrupt(struct IsdnCardSt if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); /* restart frame */ if (cs->tx_skb) { skb_push(cs->tx_skb, cs->tx_cnt); @@ -461,7 +460,7 @@ void Amd7930_interrupt(struct IsdnCardSt if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); /* restart TX-Frame */ if (cs->tx_skb) { skb_push(cs->tx_skb, cs->tx_cnt); @@ -482,7 +481,7 @@ void Amd7930_interrupt(struct IsdnCardSt if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); if (cs->tx_skb) { if (cs->tx_skb->len) Amd7930_fill_Dfifo(cs); @@ -511,7 +510,7 @@ void Amd7930_interrupt(struct IsdnCardSt if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); if (cs->tx_skb) { if (cs->debug & L1_DEB_ISAC) @@ -529,7 +528,7 @@ void Amd7930_interrupt(struct IsdnCardSt Amd7930_fill_Dfifo(cs); } else - sched_d_event(cs, D_XMTBUFREADY); + schedule_event(cs, D_XMTBUFREADY); /* AMD interrupts on */ AmdIrqOn(cs); } @@ -544,7 +543,7 @@ void Amd7930_interrupt(struct IsdnCardSt cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); /* AMD interrupts on */ AmdIrqOn(cs); } @@ -560,6 +559,7 @@ Amd7930_l1hw(struct PStack *st, int pr, { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; + u_long flags; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr); @@ -570,6 +570,7 @@ Amd7930_l1hw(struct PStack *st, int pr, LogFrame(cs, skb->data, skb->len); if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb); #ifdef L2FRAME_DEBUG /* psa */ @@ -586,8 +587,10 @@ Amd7930_l1hw(struct PStack *st, int pr, #endif Amd7930_fill_Dfifo(cs); } + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | INDICATION): + spin_lock_irqsave(&cs->lock, flags); if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); @@ -606,6 +609,7 @@ Amd7930_l1hw(struct PStack *st, int pr, Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0); #endif Amd7930_fill_Dfifo(cs); + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): #ifdef L2FRAME_DEBUG /* psa */ @@ -614,21 +618,23 @@ Amd7930_l1hw(struct PStack *st, int pr, #endif if (!cs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l2.l1l2(st, PH_PULL | CONFIRM, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): - - if ((cs->dc.amd7930.ph_state == 8)) - /* b-channels off, PH-AR cleared - * change to F3 */ - Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5 - else { - Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST"); - cs->dc.amd7930.ph_state = 2; - Amd7930_new_ph(cs); - } + spin_lock_irqsave(&cs->lock, flags); + if ((cs->dc.amd7930.ph_state == 8)) { + /* b-channels off, PH-AR cleared + * change to F3 */ + Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5 + spin_unlock_irqrestore(&cs->lock, flags); + } else { + Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST"); + cs->dc.amd7930.ph_state = 2; + spin_unlock_irqrestore(&cs->lock, flags); + Amd7930_new_ph(cs); + } break; case (HW_ENABLE | REQUEST): cs->dc.amd7930.ph_state = 9; @@ -650,7 +656,7 @@ Amd7930_l1hw(struct PStack *st, int pr, if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); break; default: if (cs->debug & L1_DEB_WARN) @@ -659,7 +665,7 @@ Amd7930_l1hw(struct PStack *st, int pr, } } -static int +void setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs) { @@ -667,21 +673,30 @@ setstack_Amd7930(struct PStack *st, stru debugl1(cs, "Amd7930: setstack called"); st->l1.l1hw = Amd7930_l1hw; - return 0; } + +void +DC_Close_Amd7930(struct IsdnCardState *cs) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Amd7930: DC_Close called"); +} + + static void dbusy_timer_handler(struct IsdnCardState *cs) { + u_long flags; struct PStack *stptr; - u16 dtcr, der; - u8 dsr1, dsr2; + WORD dtcr, der; + BYTE dsr1, dsr2; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: dbusy_timer expired!"); if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + spin_lock_irqsave(&cs->lock, flags); /* D Transmit Byte Count Register: * Counts down packet's number of Bytes, 0 if packet ready */ dtcr = rWordAMD(cs, 0x85); @@ -689,14 +704,15 @@ dbusy_timer_handler(struct IsdnCardState dsr2 = rByteAMD(cs, 0x07); der = rWordAMD(cs, 0x03); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt); - if ((int)(cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */ + if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); stptr = cs->stlist; + spin_unlock_irqrestore(&cs->lock, flags); while (stptr != NULL) { - stptr->l2.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } @@ -716,7 +732,8 @@ dbusy_timer_handler(struct IsdnCardState /* Transmitter reset, abort transmit */ wByteAMD(cs, 0x21, 0x82); wByteAMD(cs, 0x21, 0x02); - cs->card_ops->irq_func(cs->irq, cs, NULL); /* FIXME? */ + spin_unlock_irqrestore(&cs->lock, flags); + cs->irq_func(cs->irq, cs, NULL); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset"); @@ -724,59 +741,23 @@ dbusy_timer_handler(struct IsdnCardState } } -static u16 initAMD[] = { - 0x0100, - 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2 - 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on) - 0x0087, 1, 0xFF, // DMR2 - 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on) - 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition ) - 0x0084, 2, 0x80, 0x00, // DRLR - 0x00C0, 1, 0x47, // PPCR1 - 0x00C8, 1, 0x01, // PPCR2 - - 0x0102, - 0x0107, - 0x01A1, 1, - 0x0121, 1, - 0x0189, 2, - - 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4 - 0x0063, 2, 0x08, 0x08, // GX - 0x0064, 2, 0x08, 0x08, // GR - 0x0065, 2, 0x99, 0x00, // GER - 0x0066, 2, 0x7C, 0x8B, // STG - 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2 - 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2 - 0x0069, 1, 0x4F, // MMR1 - 0x006A, 1, 0x00, // MMR2 - 0x006C, 1, 0x40, // MMR3 - 0x0021, 1, 0x02, // INIT - 0x00A3, 1, 0x40, // LMR1 - - 0xFFFF}; - -static struct dc_l1_ops amd7930_l1_ops = { - .open = setstack_Amd7930, - .bh_func = Amd7930_bh, - .dbusy_func = dbusy_timer_handler, -}; void __devinit Amd7930_init(struct IsdnCardState *cs) { - u16 *ptr; - u8 cmd, cnt; + WORD *ptr; + BYTE cmd, cnt; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: initamd called"); - dc_l1_init(cs, &amd7930_l1_ops); cs->dc.amd7930.tx_xmtlen = 0; cs->dc.amd7930.old_state = 0; cs->dc.amd7930.lmr1 = 0x40; cs->dc.amd7930.ph_command = Amd7930_ph_command; + cs->setstack_d = setstack_Amd7930; + cs->DC_Close = DC_Close_Amd7930; /* AMD Initialisation */ for (ptr = initAMD; *ptr != 0xFFFF; ) { @@ -805,11 +786,11 @@ Amd7930_init(struct IsdnCardState *cs) } } -int -amd7930_setup(struct IsdnCardState *cs, struct dc_hw_ops *amd7930_ops, - void (*set_irq_mask)(struct IsdnCardState *, u8 val)) -{ - cs->dc_hw_ops = amd7930_ops; - cs->dc.amd7930.setIrqMask = set_irq_mask; - return 0; +void __devinit +setup_Amd7930(struct IsdnCardState *cs) +{ + INIT_WORK(&cs->tqueue, (void *)(void *) Amd7930_bh, cs); + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); } diff -puN drivers/isdn/hisax/amd7930_fn.h~i4l drivers/isdn/hisax/amd7930_fn.h --- 25/drivers/isdn/hisax/amd7930_fn.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/amd7930_fn.h 2004-02-09 22:19:20.000000000 -0800 @@ -12,13 +12,26 @@ */ + + +#define BYTE unsigned char +#define WORD unsigned int +#define rByteAMD(cs, reg) cs->readisac(cs, reg) +#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val) +#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg) +#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val) +#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256)) +#define LOBYTE(w) ((unsigned char)(w & 0x00ff)) + +#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0) +#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1) + #define AMD_CR 0x00 #define AMD_DR 0x01 #define DBUSY_TIMER_VALUE 80 -void Amd7930_interrupt(struct IsdnCardState *cs, unsigned char irflags); -void Amd7930_init(struct IsdnCardState *cs); -int amd7930_setup(struct IsdnCardState *cs, struct dc_hw_ops *amd7930_ops, - void (*set_irq_mask)(struct IsdnCardState *, u8 val)); +extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char); +extern void Amd7930_init(struct IsdnCardState *); +extern void setup_Amd7930(struct IsdnCardState *); diff -puN drivers/isdn/hisax/arcofi.c~i4l drivers/isdn/hisax/arcofi.c --- 25/drivers/isdn/hisax/arcofi.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/arcofi.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: arcofi.c,v 1.12.6.2 2001/09/23 22:24:46 kai Exp $ +/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $ * * Ansteuerung ARCOFI 2165 * @@ -17,19 +17,6 @@ #define ARCOFI_TIMER_VALUE 20 - -static inline u8 -isac_read(struct IsdnCardState *cs, u8 addr) -{ - return cs->dc_hw_ops->read_reg(cs, addr); -} - -static inline void -isac_write(struct IsdnCardState *cs, u8 addr, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, addr, val); -} - static void add_arcofi_timer(struct IsdnCardState *cs) { if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { @@ -42,7 +29,7 @@ add_arcofi_timer(struct IsdnCardState *c static void send_arcofi(struct IsdnCardState *cs) { - u8 val; + u_char val; add_arcofi_timer(cs); cs->dc.isac.mon_txp = 0; @@ -56,11 +43,11 @@ send_arcofi(struct IsdnCardState *cs) { } cs->dc.isac.mocr &= 0x0f; cs->dc.isac.mocr |= 0xa0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); - val = isac_read(cs, ISAC_MOSR); - isac_write(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + val = cs->readisac(cs, ISAC_MOSR); + cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); cs->dc.isac.mocr |= 0x10; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); } int diff -puN drivers/isdn/hisax/asuscom.c~i4l drivers/isdn/hisax/asuscom.c --- 25/drivers/isdn/hisax/asuscom.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/asuscom.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: asuscom.c,v 1.11.6.3 2001/09/23 22:24:46 kai Exp $ +/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * @@ -22,9 +22,8 @@ extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.11.6.3 $"; +const char *Asuscom_revision = "$Revision: 1.14.2.4 $"; -static spinlock_t asuscom_lock = SPIN_LOCK_UNLOCKED; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -43,237 +42,258 @@ static spinlock_t asuscom_lock = SPIN_LO /* CARD_ADR (Write) */ #define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */ -static inline u8 -readreg(struct IsdnCardState *cs, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&asuscom_lock, flags); - byteout(cs->hw.asus.adr, off); + byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&asuscom_lock, flags); - return ret; + return (ret); } static inline void -writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&asuscom_lock, flags); - byteout(cs->hw.asus.adr, off); - byteout(adr, data); - spin_unlock_irqrestore(&asuscom_lock, flags); + byteout(ale, off); + insb(adr, data, size); } + static inline void -readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - byteout(cs->hw.asus.adr, off); - insb(adr, data, size); + byteout(ale, off); + byteout(adr, data); } - static inline void -writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - byteout(cs->hw.asus.adr, off); + byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.asus.isac, offset); + return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.asus.isac, offset, value); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.asus.isac, 0, data, size); + readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.asus.isac, 0, data, size); + writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value); } static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.asus.hscx, hscx ? 0x40 : 0, data, size); + readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.asus.hscx, hscx ? 0x40 : 0, data, size); + writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static inline u8 -ipac_read(struct IsdnCardState *cs, u8 off) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - u8 ret; - unsigned long flags; - - spin_lock_irqsave(&asuscom_lock, flags); - byteout(cs->hw.asus.adr, off); - ret = bytein(cs->hw.asus.isac); - spin_unlock_irqrestore(&asuscom_lock, flags); - return ret; + return (readreg(cs->hw.asus.adr, + cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0))); } -static inline void -ipac_write(struct IsdnCardState *cs, u8 off, u8 data) -{ - unsigned long flags; - - spin_lock_irqsave(&asuscom_lock, flags); - byteout(cs->hw.asus.adr, off); - byteout(cs->hw.asus.isac, data); - spin_unlock_irqrestore(&asuscom_lock, flags); -} - -static inline void -ipac_readfifo(struct IsdnCardState *cs, u8 off, u8 * data, int size) +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - byteout(cs->hw.asus.adr, off); - insb(cs->hw.asus.isac, data, size); + writereg(cs->hw.asus.adr, + cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value); } +/* + * fast interrupt HSCX stuff goes here + */ -static inline void -ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 * data, int size) -{ - byteout(cs->hw.asus.adr, off); - outsb(cs->hw.asus.isac, data, size); +#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \ + cs->hw.asus.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \ + cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data) + +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \ + cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \ + cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t +asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 5; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "ASUS IRQ LOOP\n"); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } -/* This will generate ipac_dc_ops and ipac_bc_ops using the functions - * above */ +void +release_io_asuscom(struct IsdnCardState *cs) +{ + int bytecnt = 8; -BUILD_IPAC_OPS(ipac); + if (cs->hw.asus.cfg_reg) + release_region(cs->hw.asus.cfg_reg, bytecnt); +} -static int -asuscom_reset(struct IsdnCardState *cs) +static void +reset_asuscom(struct IsdnCardState *cs) { - byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - byteout(cs->hw.asus.adr, 0); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - return 0; + if (cs->subtyp == ASUS_IPAC) + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20); + else + byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ + mdelay(10); + if (cs->subtyp == ASUS_IPAC) + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); + else + byteout(cs->hw.asus.adr, 0); /* Reset Off */ + mdelay(10); + if (cs->subtyp == ASUS_IPAC) { + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12); + } } static int -asuscom_ipac_reset(struct IsdnCardState *cs) +Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - writereg(cs, cs->hw.asus.isac, IPAC_POTA2, 0x20); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writereg(cs, cs->hw.asus.isac, IPAC_POTA2, 0x0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writereg(cs, cs->hw.asus.isac, IPAC_CONF, 0x0); - writereg(cs, cs->hw.asus.isac, IPAC_ACFG, 0xff); - writereg(cs, cs->hw.asus.isac, IPAC_AOE, 0x0); - writereg(cs, cs->hw.asus.isac, IPAC_MASK, 0xc0); - writereg(cs, cs->hw.asus.isac, IPAC_PCFG, 0x12); - return 0; -} - -static struct card_ops asuscom_ops = { - .init = inithscxisac, - .reset = asuscom_reset, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - -static struct card_ops asuscom_ipac_ops = { - .init = ipac_init, - .reset = asuscom_ipac_reset, - .release = hisax_release_resources, - .irq_func = ipac_irq, -}; + u_long flags; -static int __init -asuscom_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - int rc; - u8 val; - - printk(KERN_INFO "ISDNLink: defined at %#lx IRQ %lu\n", - card->para[1], card->para[0]); - - cs->hw.asus.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - - rc = -EBUSY; - if (!request_io(&cs->rs, cs->hw.asus.cfg_reg, 8, "asuscom isdn")) - goto err; - - rc = -ENODEV; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; - val = readreg(cs, cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); - if ((val == 1) || (val == 2)) { - cs->subtyp = ASUS_IPAC; - cs->card_ops = &asuscom_ipac_ops; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; - } else { - cs->subtyp = ASUS_ISACHSCX; - cs->card_ops = &asuscom_ops; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; - cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; - cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_asuscom(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_asuscom(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + cs->debug |= L1_DEB_IPAC; + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); } - printk(KERN_INFO "ISDNLink: resetting card\n"); - cs->card_ops->reset(cs); - return 0; - - err: - hisax_release_resources(cs); - return rc; + return(0); } #ifdef __ISAPNP__ @@ -293,66 +313,115 @@ static struct isapnp_device_id asus_ids[ { 0, } }; -static struct isapnp_device_id *adev = &asus_ids[0]; +static struct isapnp_device_id *ipid __initdata = &asus_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif int __init setup_asuscom(struct IsdnCard *card) { + int bytecnt; + struct IsdnCardState *cs = card->cs; + u_char val; char tmp[64]; strcpy(tmp, Asuscom_revision); printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_ASUSCOM) + return (0); #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; - while(adev->card_vendor) { - if ((pb = pnp_find_card(adev->card_vendor, - adev->card_device, - pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - adev->vendor, - adev->function, - pd))) { printk(KERN_INFO "HiSax: %s detected\n", - (char *)adev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "AsusPnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "AsusPnP: activate failed\n"); - pnp_device_detach(pd); - return 0; + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) { + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); break; } else { printk(KERN_ERR "AsusPnP: PnP error card found, no device\n"); } } - adev++; - pnp_c=NULL; + ipid++; + pnp_c = NULL; } - if (!adev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "AsusPnP: no ISAPnP card found\n"); return(0); } } #endif - if (asuscom_probe(card->cs, card) < 0) - return 0; - return 1; + bytecnt = 8; + cs->hw.asus.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.asus.cfg_reg, + cs->hw.asus.cfg_reg + bytecnt); + return (0); + } + printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n", + cs->hw.asus.cfg_reg, cs->irq); + setup_isac(cs); + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Asus_card_msg; + val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, + cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); + if ((val == 1) || (val == 2)) { + cs->subtyp = ASUS_IPAC; + cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; + cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; + cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &asuscom_interrupt_ipac; + printk(KERN_INFO "Asus: IPAC version %x\n", val); + } else { + cs->subtyp = ASUS_ISACHSCX; + cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; + cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; + cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; + cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; + cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->irq_func = &asuscom_interrupt; + ISACVersion(cs, "ISDNLink:"); + if (HscxVersion(cs, "ISDNLink:")) { + printk(KERN_WARNING + "ISDNLink: wrong HSCX versions check IO address\n"); + release_io_asuscom(cs); + return (0); + } + } + return (1); } diff -puN drivers/isdn/hisax/avm_a1.c~i4l drivers/isdn/hisax/avm_a1.c --- 25/drivers/isdn/hisax/avm_a1.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/avm_a1.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: avm_a1.c,v 2.13.6.2 2001/09/23 22:24:46 kai Exp $ +/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $ * * low level stuff for AVM A1 (Fritz) isdn cards * @@ -17,7 +17,7 @@ #include "isdnl1.h" extern const char *CardType[]; -static const char *avm_revision = "$Revision: 2.13.6.2 $"; +static const char *avm_revision = "$Revision: 2.15.2.4 $"; #define AVM_A1_STAT_ISAC 0x01 #define AVM_A1_STAT_HSCX 0x02 @@ -26,172 +26,237 @@ static const char *avm_revision = "$Revi #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static inline u8 -readreg(unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int adr, u_char off) { return (bytein(adr + off)); } static inline void -writereg(unsigned int adr, u8 off, u8 data) +writereg(unsigned int adr, u_char off, u_char data) { byteout(adr + off, data); } static inline void -read_fifo(unsigned int adr, u8 * data, int size) +read_fifo(unsigned int adr, u_char * data, int size) { insb(adr, data, size); } static void -write_fifo(unsigned int adr, u8 * data, int size) +write_fifo(unsigned int adr, u_char * data, int size) { outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs->hw.avm.isac, offset); + return (readreg(cs->hw.avm.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writereg(cs->hw.avm.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { read_fifo(cs->hw.avm.isacfifo, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { write_fifo(cs->hw.avm.isacfifo, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return (readreg(cs->hw.avm.hscx[hscx], offset)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { writereg(cs->hw.avm.hscx[hscx], offset, value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - read_fifo(cs->hw.avm.hscxfifo[hscx], data, size); -} +/* + * fast interrupt HSCX stuff goes here + */ -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - write_fifo(cs->hw.avm.hscxfifo[hscx], data, size); -} +#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +#include "hscx_irq.c" static irqreturn_t avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val, sval; - int handled = 0; + u_char val, sval; + u_long flags; - spin_lock(&cs->lock); + spin_lock_irqsave(&cs->lock, flags); while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) { - handled = 1; if (!(sval & AVM_A1_STAT_TIMER)) { byteout(cs->hw.avm.cfg_reg, 0x1E); sval = bytein(cs->hw.avm.cfg_reg); } else if (cs->debug & L1_DEB_INTSTAT) debugl1(cs, "avm IntStatus %x", sval); if (!(sval & AVM_A1_STAT_HSCX)) { - val = hscx_read(cs, 1, HSCX_ISTA); + val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA); if (val) hscx_int_main(cs, val); } if (!(sval & AVM_A1_STAT_ISAC)) { - val = isac_read(cs, ISAC_ISTA); + val = readreg(cs->hw.avm.isac, ISAC_ISTA); if (val) isac_interrupt(cs, val); } } - hscx_write(cs, 0, HSCX_MASK, 0xFF); - hscx_write(cs, 1, HSCX_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0x0); - hscx_write(cs, 0, HSCX_MASK, 0x0); - hscx_write(cs, 1, HSCX_MASK, 0x0); - spin_unlock(&cs->lock); - return IRQ_RETVAL(handled); + writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF); + writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF); + writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.avm.isac, ISAC_MASK, 0x0); + writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0); + writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +inline static void +release_ioregs(struct IsdnCardState *cs, int mask) +{ + release_region(cs->hw.avm.cfg_reg, 8); + if (mask & 1) + release_region(cs->hw.avm.isac + 32, 32); + if (mask & 2) + release_region(cs->hw.avm.isacfifo, 1); + if (mask & 4) + release_region(cs->hw.avm.hscx[0] + 32, 32); + if (mask & 8) + release_region(cs->hw.avm.hscxfifo[0], 1); + if (mask & 0x10) + release_region(cs->hw.avm.hscx[1] + 32, 32); + if (mask & 0x20) + release_region(cs->hw.avm.hscxfifo[1], 1); +} + +static int +AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + u_long flags; + + switch (mt) { + case CARD_RESET: + return(0); + case CARD_RELEASE: + release_ioregs(cs, 0x3f); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 1); + byteout(cs->hw.avm.cfg_reg, 0x16); + byteout(cs->hw.avm.cfg_reg, 0x1E); + inithscxisac(cs, 2); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } -static void -avm_a1_init(struct IsdnCardState *cs) +int __init +setup_avm_a1(struct IsdnCard *card) { - byteout(cs->hw.avm.cfg_reg, 0x16); - byteout(cs->hw.avm.cfg_reg, 0x1E); - inithscxisac(cs); -} - -static struct card_ops avm_a1_ops = { - .init = avm_a1_init, - .release = hisax_release_resources, - .irq_func = avm_a1_interrupt, -}; - -static int __init -avm_a1_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - int rc; - u8 val; - - printk(KERN_INFO "AVM A1: defined at %#lx IRQ %lu\n", - card->para[1], card->para[0]); - - rc = -EBUSY; - cs->hw.avm.cfg_reg = request_io(&cs->rs, card->para[1] + 0x1800, 8, "avm cfg"); - if (!cs->hw.avm.cfg_reg) goto err; - cs->hw.avm.isac = request_io(&cs->rs, card->para[1] + 0x1400, 32, "HiSax isac"); - if (!cs->hw.avm.isac) goto err; - cs->hw.avm.isacfifo = request_io(&cs->rs, card->para[1] + 0x1000, 1, "HiSax isac fifo"); - if (!cs->hw.avm.isacfifo) goto err; - cs->hw.avm.hscx[0] = request_io(&cs->rs, card->para[1] + 0x400, 32, "HiSax hscx A"); - if (!cs->hw.avm.hscx[0]) goto err; - cs->hw.avm.hscxfifo[0] = request_io(&cs->rs, card->para[1], 1, "HiSax hscx A fifo"); - if (!cs->hw.avm.hscxfifo[0]) goto err; - cs->hw.avm.hscx[1] = request_io(&cs->rs, card->para[1] + 0xc00, 32, "HiSax hscx B"); - if (!cs->hw.avm.hscx[1]) goto err; - cs->hw.avm.hscxfifo[1] = request_io(&cs->rs, card->para[1] + 0x800, 1, "HiSax hscx B fifo"); - if (!cs->hw.avm.hscxfifo[1]) goto err; - cs->hw.avm.isac -= 0x20; - cs->hw.avm.hscx[0] -= 0x20; - cs->hw.avm.hscx[1] -= 0x20; - cs->irq = card->para[0]; + u_char val; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, avm_revision); + printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_A1) + return (0); + cs->hw.avm.cfg_reg = card->para[1] + 0x1800; + cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20; + cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20; + cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20; + cs->hw.avm.isacfifo = card->para[1] + 0x1000; + cs->hw.avm.hscxfifo[0] = card->para[1]; + cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800; + cs->irq = card->para[0]; + if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.avm.cfg_reg, + cs->hw.avm.cfg_reg + 8); + return (0); + } + if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) { + printk(KERN_WARNING + "HiSax: %s isac ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.avm.isac + 32, + cs->hw.avm.isac + 64); + release_ioregs(cs, 0); + return (0); + } + if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) { + printk(KERN_WARNING + "HiSax: %s isac fifo port %x already in use\n", + CardType[cs->typ], + cs->hw.avm.isacfifo); + release_ioregs(cs, 1); + return (0); + } + if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) { + printk(KERN_WARNING + "HiSax: %s hscx A ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.avm.hscx[0] + 32, + cs->hw.avm.hscx[0] + 64); + release_ioregs(cs, 3); + return (0); + } + if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) { + printk(KERN_WARNING + "HiSax: %s hscx A fifo port %x already in use\n", + CardType[cs->typ], + cs->hw.avm.hscxfifo[0]); + release_ioregs(cs, 7); + return (0); + } + if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) { + printk(KERN_WARNING + "HiSax: %s hscx B ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.avm.hscx[1] + 32, + cs->hw.avm.hscx[1] + 64); + release_ioregs(cs, 0xf); + return (0); + } + if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) { + printk(KERN_WARNING + "HiSax: %s hscx B fifo port %x already in use\n", + CardType[cs->typ], + cs->hw.avm.hscxfifo[1]); + release_ioregs(cs, 0x1f); + return (0); + } byteout(cs->hw.avm.cfg_reg, 0x0); HZDELAY(HZ / 5 + 1); byteout(cs->hw.avm.cfg_reg, 0x1); @@ -219,24 +284,34 @@ avm_a1_probe(struct IsdnCardState *cs, s printk(KERN_INFO "AVM A1: Byte at %x is %x\n", cs->hw.avm.cfg_reg, val); - cs->card_ops = &avm_a1_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return rc; -} - -int __init -setup_avm_a1(struct IsdnCard *card) -{ - char tmp[64]; - - strcpy(tmp, avm_revision); - printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp)); - - if (avm_a1_probe(card->cs, card) < 0) - return 0; - return 1; + printk(KERN_INFO + "HiSax: %s config irq:%d cfg:0x%X\n", + CardType[cs->typ], cs->irq, + cs->hw.avm.cfg_reg); + printk(KERN_INFO + "HiSax: isac:0x%X/0x%X\n", + cs->hw.avm.isac + 32, cs->hw.avm.isacfifo); + printk(KERN_INFO + "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n", + cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0], + cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]); + + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + setup_isac(cs); + cs->cardmsg = &AVM_card_msg; + cs->irq_func = &avm_a1_interrupt; + ISACVersion(cs, "AVM A1:"); + if (HscxVersion(cs, "AVM A1:")) { + printk(KERN_WARNING + "AVM A1: wrong HSCX versions check IO address\n"); + release_ioregs(cs, 0x3f); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/avma1_cs.c~i4l drivers/isdn/hisax/avma1_cs.c --- 25/drivers/isdn/hisax/avma1_cs.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/avma1_cs.c 2004-02-09 22:19:20.000000000 -0800 @@ -26,15 +26,12 @@ #include #include #include +#include "hisax_cfg.h" MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot); -void HiSax_closecard(int cardnr); - - /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not define PCMCIA_DEBUG at all, all the debug code will be @@ -156,6 +153,15 @@ static dev_link_t *avma1cs_attach(void) return NULL; memset(link, 0, sizeof(struct dev_link_t)); + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + kfree(link); + return NULL; + } + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + /* The io structure describes IO port mapping */ link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -183,15 +189,6 @@ static dev_link_t *avma1cs_attach(void) link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - /* Allocate space for private device-specific data */ - local = kmalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) { - kfree(link); - return NULL; - } - memset(local, 0, sizeof(local_info_t)); - link->priv = local; - /* Register with Card Services */ link->next = dev_list; dev_list = link; @@ -252,7 +249,7 @@ static void avma1cs_detach(dev_link_t *l /* Break the link with Card Services */ if (link->handle) - pcmcia_deregister_client(link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; @@ -303,8 +300,9 @@ static void avma1cs_config(dev_link_t *l cistpl_cftable_entry_t *cf = &parse.cftable_entry; local_info_t *dev; int i; - u8 buf[64]; + u_char buf[64]; char devname[128]; + IsdnCard_t icard; int busy = 0; handle = link->handle; @@ -365,9 +363,9 @@ static void avma1cs_config(dev_link_t *l link->io.BasePort1 = cf->io.win[0].base; link->io.NumPorts1 = cf->io.win[0].len; link->io.NumPorts2 = 0; - printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", + printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", link->io.BasePort1, - link->io.BasePort1+link->io.NumPorts1 - 1); + link->io.BasePort1+link->io.NumPorts1 - 1); i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -391,8 +389,8 @@ found_port: } /* - * configure the PCMCIA socket - */ + * configure the PCMCIA socket + */ i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); @@ -421,15 +419,17 @@ found_port: printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n", link->io.BasePort1, link->irq.AssignedIRQ); - if (avm_a1_init_pcmcia((void *)(int)link->io.BasePort1, - link->irq.AssignedIRQ, - &busy, isdnprot) != 0) { - printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); - return; + icard.para[0] = link->irq.AssignedIRQ; + icard.para[1] = link->io.BasePort1; + icard.protocol = isdnprot; + icard.typ = ISDN_CTYPE_A1_PCMCIA; + + i = hisax_init_pcmcia(link, &busy, &icard); + if (i < 0) { + printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); + avma1cs_release(link); + return; } - - i = 0; /* no returncode for cardnr :-( */ - dev->node.minor = i; } /* avma1cs_config */ @@ -486,29 +486,28 @@ static int avma1cs_event(event_t event, DEBUG(1, "avma1cs_event(0x%06x)\n", event); switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) + case CS_EVENT_CARD_REMOVAL: + if (link->state & DEV_CONFIG) avma1cs_release(link); - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - avma1cs_config(link); - break; - case CS_EVENT_PM_SUSPEND: - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - break; + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + avma1cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + pcmcia_release_configuration(link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + pcmcia_request_configuration(link->handle, &link->conf); + break; } return 0; } /* avma1cs_event */ @@ -521,10 +520,12 @@ static struct pcmcia_driver avma1cs_driv .attach = avma1cs_attach, .detach = avma1cs_detach, }; + +/*====================================================================*/ static int __init init_avma1_cs(void) { - return pcmcia_register_driver(&avma1cs_driver); + return(pcmcia_register_driver(&avma1cs_driver)); } static void __exit exit_avma1_cs(void) diff -puN drivers/isdn/hisax/avm_a1p.c~i4l drivers/isdn/hisax/avm_a1p.c --- 25/drivers/isdn/hisax/avm_a1p.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/avm_a1p.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: avm_a1p.c,v 2.7.6.2 2001/09/23 22:24:46 kai Exp $ +/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $ * * low level stuff for the following AVM cards: * A1 PCMCIA @@ -56,176 +56,182 @@ #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static const char *avm_revision = "$Revision: 2.7.6.2 $"; -static spinlock_t avm_a1p_lock = SPIN_LOCK_UNLOCKED; +static const char *avm_revision = "$Revision: 2.9.2.5 $"; -static inline u8 -readreg(struct IsdnCardState *cs, int offset, u8 adr) +static inline u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - unsigned long flags; - u8 ret; + u_char ret; - spin_lock_irqsave(&avm_a1p_lock, flags); - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, offset + adr - 0x20); - ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET); - spin_unlock_irqrestore(&avm_a1p_lock, flags); + offset -= 0x20; + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset); + ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET); return ret; } static inline void -writereg(struct IsdnCardState *cs, int offset, u8 adr, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - unsigned long flags; - - spin_lock_irqsave(&avm_a1p_lock, flags); - byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, offset + adr - 0x20); + offset -= 0x20; + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset); byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value); - spin_unlock_irqrestore(&avm_a1p_lock, flags); } static inline void -readfifo(struct IsdnCardState *cs, int offset, u8 *data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, offset); - insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET); + insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); } static inline void -writefifo(struct IsdnCardState *cs, int offset, u8 *data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, offset); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET); outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 adr) -{ - return readreg(cs, ISAC_REG_OFFSET, adr); -} - -static void -isac_write(struct IsdnCardState *cs, u8 adr, u8 value) +static inline u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - writereg(cs, ISAC_REG_OFFSET, adr, value); -} + u_char ret; -static void -isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size) -{ - readfifo(cs, ISAC_FIFO_OFFSET, data, size); + offset -= 0x20; + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset); + ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET); + return ret; } -static void -isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size) +static inline void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writefifo(cs, ISAC_FIFO_OFFSET, data, size); + offset -= 0x20; + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset); + byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 adr) +static inline void +ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) { - return readreg(cs, HSCX_REG_OFFSET + hscx*HSCX_CH_DIFF, adr); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF); + insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); } -static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 adr, u8 value) +static inline void +WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) { - writereg(cs, HSCX_REG_OFFSET + hscx*HSCX_CH_DIFF, adr, value); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF); + outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - return readfifo(cs, HSCX_FIFO_OFFSET + hscx*HSCX_CH_DIFF, data, size); -} +/* + * fast interrupt HSCX stuff goes here + */ -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - writefifo(cs, HSCX_FIFO_OFFSET + hscx*HSCX_CH_DIFF, data, size); -} +#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +#include "hscx_irq.c" static irqreturn_t avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val, sval; + u_char val, sval; + u_long flags; - spin_lock(&cs->lock); + spin_lock_irqsave(&cs->lock, flags); while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) { if (cs->debug & L1_DEB_INTSTAT) debugl1(cs, "avm IntStatus %x", sval); if (sval & ASL0_R_HSCX) { - val = hscx_read(cs, 1, HSCX_ISTA); + val = ReadHSCX(cs, 1, HSCX_ISTA); if (val) hscx_int_main(cs, val); } if (sval & ASL0_R_ISAC) { - val = isac_read(cs, ISAC_ISTA); + val = ReadISAC(cs, ISAC_ISTA); if (val) isac_interrupt(cs, val); } } - hscx_write(cs, 0, HSCX_MASK, 0xFF); - hscx_write(cs, 1, HSCX_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0x0); - hscx_write(cs, 0, HSCX_MASK, 0x0); - hscx_write(cs, 1, HSCX_MASK, 0x0); - spin_unlock(&cs->lock); + WriteHSCX(cs, 0, HSCX_MASK, 0xff); + WriteHSCX(cs, 1, HSCX_MASK, 0xff); + WriteISAC(cs, ISAC_MASK, 0xff); + WriteISAC(cs, ISAC_MASK, 0x00); + WriteHSCX(cs, 0, HSCX_MASK, 0x00); + WriteHSCX(cs, 1, HSCX_MASK, 0x00); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static void -avm_a1p_init(struct IsdnCardState *cs) -{ - byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, - ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE); - inithscxisac(cs); -} - static int -avm_a1p_reset(struct IsdnCardState *cs) +AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + u_long flags; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + HZDELAY(HZ / 5 + 1); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET); + HZDELAY(HZ / 5 + 1); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + spin_unlock_irqrestore(&cs->lock, flags); + return 0; + + case CARD_RELEASE: + /* free_irq is done in HiSax_closecard(). */ + /* free_irq(cs->irq, cs); */ + return 0; + + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE); + clear_pending_isac_ints(cs); + clear_pending_hscx_ints(cs); + inithscxisac(cs, 1); + inithscxisac(cs, 2); + spin_unlock_irqrestore(&cs->lock, flags); + return 0; + + case CARD_TEST: + /* we really don't need it for the PCMCIA Version */ + return 0; + + default: + /* all card drivers ignore others, so we do the same */ + return 0; + } return 0; } -static struct card_ops avm_a1p_ops = { - .init = avm_a1p_init, - .reset = avm_a1p_reset, - .irq_func = avm_a1p_interrupt, -}; - -static int __init -avm_a1p_probe(struct IsdnCardState *cs, struct IsdnCard *card) +int +setup_avm_a1_pcmcia(struct IsdnCard *card) { - u8 model, vers; + u_char model, vers; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + + strcpy(tmp, avm_revision); + printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n", + HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_A1_PCMCIA) + return (0); - cs->irq = card->para[0]; cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; - outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0); + outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0); byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); HZDELAY(HZ / 5 + 1); byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET); @@ -238,26 +244,25 @@ avm_a1p_probe(struct IsdnCardState *cs, vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET); printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n", - cs->hw.avm.cfg_reg, cs->irq, model, vers); - - cs->card_ops = &avm_a1p_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -int __devinit -setup_avm_a1_pcmcia(struct IsdnCard *card) -{ - char tmp[64]; + cs->hw.avm.cfg_reg, cs->irq, model, vers); - strcpy(tmp, avm_revision); - printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n", - HiSax_getrev(tmp)); - if (avm_a1p_probe(card->cs, card)) - return 0; - return 1; + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &AVM_card_msg; + cs->irq_flags = SA_SHIRQ; + cs->irq_func = &avm_a1p_interrupt; + + ISACVersion(cs, "AVM A1 PCMCIA:"); + if (HscxVersion(cs, "AVM A1 PCMCIA:")) { + printk(KERN_WARNING + "AVM A1 PCMCIA: wrong HSCX versions check IO address\n"); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/avm_pci.c~i4l drivers/isdn/hisax/avm_pci.c --- 25/drivers/isdn/hisax/avm_pci.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/avm_pci.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.22.6.6 2001/09/23 22:24:46 kai Exp $ +/* $Id: avm_pci.c,v 1.29.2.3 2004/01/13 14:31:24 keil Exp $ * * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * @@ -22,8 +22,7 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.22.6.6 $"; -static spinlock_t avm_pci_lock = SPIN_LOCK_UNLOCKED; +static const char *avm_pci_rev = "$Revision: 1.29.2.3 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -76,137 +75,91 @@ static spinlock_t avm_pci_lock = SPIN_LO /* Interface functions */ -static u8 -ReadISAC(struct IsdnCardState *cs, u8 offset) +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - u8 val; - unsigned long flags; + register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + register u_char val; - spin_lock_irqsave(&avm_pci_lock, flags); outb(idx, cs->hw.avm.cfg_reg + 4); val = inb(cs->hw.avm.isac + (offset & 0xf)); - spin_unlock_irqrestore(&avm_pci_lock, flags); return (val); } static void -WriteISAC(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - unsigned long flags; + register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - spin_lock_irqsave(&avm_pci_lock, flags); outb(idx, cs->hw.avm.cfg_reg + 4); outb(value, cs->hw.avm.isac + (offset & 0xf)); - spin_unlock_irqrestore(&avm_pci_lock, flags); } static void -ReadISACfifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); insb(cs->hw.avm.isac, data, size); } static void -WriteISACfifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); outsb(cs->hw.avm.isac, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = ReadISAC, - .write_reg = WriteISAC, - .read_fifo = ReadISACfifo, - .write_fifo = WriteISACfifo, -}; - static inline u_int -ReadHDLCPCI(struct IsdnCardState *cs, int chan, u8 offset) +ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset) { - u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - u_int val; - unsigned long flags; + register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; + register u_int val; - spin_lock_irqsave(&avm_pci_lock, flags); outl(idx, cs->hw.avm.cfg_reg + 4); val = inl(cs->hw.avm.isac + offset); - spin_unlock_irqrestore(&avm_pci_lock, flags); return (val); } static inline void -WriteHDLCPCI(struct IsdnCardState *cs, int chan, u8 offset, u_int value) +WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value) { - u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - unsigned long flags; + register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - spin_lock_irqsave(&avm_pci_lock, flags); outl(idx, cs->hw.avm.cfg_reg + 4); outl(value, cs->hw.avm.isac + offset); - spin_unlock_irqrestore(&avm_pci_lock, flags); } -static inline u8 -ReadHDLCPnP(struct IsdnCardState *cs, int chan, u8 offset) +static inline u_char +ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset) { - u8 idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - u8 val; - unsigned long flags; + register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; + register u_char val; - spin_lock_irqsave(&avm_pci_lock, flags); outb(idx, cs->hw.avm.cfg_reg + 4); val = inb(cs->hw.avm.isac + offset); - spin_unlock_irqrestore(&avm_pci_lock, flags); return (val); } static inline void -WriteHDLCPnP(struct IsdnCardState *cs, int chan, u8 offset, u8 value) +WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value) { - u8 idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - unsigned long flags; + register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - spin_lock_irqsave(&avm_pci_lock, flags); outb(idx, cs->hw.avm.cfg_reg + 4); outb(value, cs->hw.avm.isac + offset); - spin_unlock_irqrestore(&avm_pci_lock, flags); } -static void -hdlc_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int len) +static u_char +ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset) { - u8 idx = hscx ? AVM_HDLC_2 : AVM_HDLC_1; - int i; - - if (cs->subtyp == AVM_FRITZ_PCI) { - u32 *ptr = (u32 *) data; - - outl(idx, cs->hw.avm.cfg_reg + 4); - for (i = 0; i < len; i += 4) { -#ifdef __powerpc__ -#ifdef CONFIG_APUS - *ptr++ = in_le32((u32 *)(cs->hw.avm.isac +_IO_BASE)); -#else - *ptr++ = in_be32((u32 *)(cs->hw.avm.isac +_IO_BASE)); -#endif /* CONFIG_APUS */ -#else - *ptr++ = inl(cs->hw.avm.isac); -#endif /* __powerpc__ */ - } - } else { - outb(idx, cs->hw.avm.cfg_reg + 4); - for (i = 0; i < len; i++) { - *data++ = inb(cs->hw.avm.isac); - } - } + return(0xff & ReadHDLCPCI(cs, chan, offset)); } -static struct bc_hw_ops hdlc_hw_ops = { - .read_fifo = hdlc_read_fifo, -}; +static void +WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value) +{ + WriteHDLCPCI(cs, chan, offset, value); +} static inline struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) @@ -273,7 +226,7 @@ modehdlc(struct BCState *bcs, int mode, bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; write_ctrl(bcs, 1); bcs->hw.hdlc.ctrl.sr.cmd = 0; - sched_b_event(bcs, B_XMTBUFREADY); + schedule_event(bcs, B_XMTBUFREADY); break; case (L1_MODE_HDLC): bcs->mode = mode; @@ -284,7 +237,7 @@ modehdlc(struct BCState *bcs, int mode, bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; write_ctrl(bcs, 1); bcs->hw.hdlc.ctrl.sr.cmd = 0; - sched_b_event(bcs, B_XMTBUFREADY); + schedule_event(bcs, B_XMTBUFREADY); break; } } @@ -292,31 +245,87 @@ modehdlc(struct BCState *bcs, int mode, static inline void hdlc_empty_fifo(struct BCState *bcs, int count) { - recv_empty_fifo_b(bcs, count); + register u_int *ptr; + u_char *p; + u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1; + int cnt=0; + struct IsdnCardState *cs = bcs->cs; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hdlc_empty_fifo %d", count); + if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hdlc_empty_fifo: incoming packet too large"); + return; + } + ptr = (u_int *) p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; + bcs->hw.hdlc.rcvidx += count; + if (cs->subtyp == AVM_FRITZ_PCI) { + outl(idx, cs->hw.avm.cfg_reg + 4); + while (cnt < count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#else + *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#endif /* CONFIG_APUS */ +#else + *ptr++ = inl(cs->hw.avm.isac); +#endif /* __powerpc__ */ + cnt += 4; + } + } else { + outb(idx, cs->hw.avm.cfg_reg + 4); + while (cnt < count) { + *p++ = inb(cs->hw.avm.isac); + cnt++; + } + } + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + if (cs->subtyp == AVM_FRITZ_PNP) + p = (u_char *) ptr; + t += sprintf(t, "hdlc_empty_fifo %c cnt %d", + bcs->channel ? 'B' : 'A', count); + QuickHex(t, p, count); + debugl1(cs, bcs->blog); + } } -static void +static inline void hdlc_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - int count, more, cnt =0; + int count, cnt =0; int fifo_size = 32; - unsigned char *p; - unsigned int *ptr; + u_char *p; + u_int *ptr; - p = xmit_fill_fifo_b(bcs, fifo_size, &count, &more); - if (!p) + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hdlc_fill_fifo"); + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) return; - if (more) - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME; - else - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME; - + bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME; + if (bcs->tx_skb->len > fifo_size) { + count = fifo_size; + } else { + count = bcs->tx_skb->len; + if (bcs->mode != L1_MODE_TRANS) + bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME; + } + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len); + ptr = (u_int *) p = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hdlc.count += count; bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count); write_ctrl(bcs, 3); /* sets the correct index too */ if (cs->subtyp == AVM_FRITZ_PCI) { - ptr = (unsigned int *) p; while (cntdebug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; -static void -reset_xmit(struct BCState *bcs) -{ - bcs->hw.hdlc.ctrl.sr.xml = 0; - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS; - write_ctrl(bcs, 1); - hdlc_fill_fifo(bcs); + if (cs->subtyp == AVM_FRITZ_PNP) + p = (u_char *) ptr; + t += sprintf(t, "hdlc_fill_fifo %c cnt %d", + bcs->channel ? 'B' : 'A', count); + QuickHex(t, p, count); + debugl1(cs, bcs->blog); + } } static inline void -HDLC_irq(struct BCState *bcs, u_int stat) -{ +HDLC_irq(struct BCState *bcs, u_int stat) { int len; + struct sk_buff *skb; if (bcs->cs->debug & L1_DEB_HSCX) debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); - if (stat & HDLC_INT_RPR) { if (stat & HDLC_STAT_RDO) { if (bcs->cs->debug & L1_DEB_HSCX) @@ -367,7 +374,7 @@ HDLC_irq(struct BCState *bcs, u_int stat write_ctrl(bcs, 1); bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS; write_ctrl(bcs, 1); - bcs->rcvidx = 0; + bcs->hw.hdlc.rcvidx = 0; } else { if (!(len = (stat & HDLC_STAT_RML_MASK)>>8)) len = 32; @@ -375,21 +382,65 @@ HDLC_irq(struct BCState *bcs, u_int stat if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) || (bcs->mode == L1_MODE_TRANS)) { - recv_rme_b(bcs); + if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx))) + printk(KERN_WARNING "HDLC: receive out of memory\n"); + else { + memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx), + bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hdlc.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); } else { if (bcs->cs->debug & L1_DEB_HSCX) debugl1(bcs->cs, "invalid frame"); else debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat); - bcs->rcvidx = 0; + bcs->hw.hdlc.rcvidx = 0; } } } } if (stat & HDLC_INT_XDU) { - xmit_xdu_b(bcs, reset_xmit); + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hdlc.count); + bcs->tx_cnt += bcs->hw.hdlc.count; + bcs->hw.hdlc.count = 0; + if (bcs->cs->debug & L1_DEB_WARN) + debugl1(bcs->cs, "ch%d XDU", bcs->channel); + } else if (bcs->cs->debug & L1_DEB_WARN) + debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel); + bcs->hw.hdlc.ctrl.sr.xml = 0; + bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; + write_ctrl(bcs, 1); + bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS; + write_ctrl(bcs, 1); + hdlc_fill_fifo(bcs); } else if (stat & HDLC_INT_XPR) { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + hdlc_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.hdlc.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hdlc.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + hdlc_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } } } @@ -399,7 +450,6 @@ HDLC_irq_main(struct IsdnCardState *cs) u_int stat; struct BCState *bcs; - spin_lock(&cs->lock); if (cs->subtyp == AVM_FRITZ_PCI) { stat = ReadHDLCPCI(cs, 0, HDLC_STATUS); } else { @@ -428,37 +478,64 @@ HDLC_irq_main(struct IsdnCardState *cs) } else HDLC_irq(bcs, stat); } - spin_unlock(&cs->lock); } void hdlc_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->hw.hdlc.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n"); + } else { + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->hw.hdlc.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - modehdlc(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + modehdlc(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - modehdlc(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + modehdlc(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -467,38 +544,69 @@ void close_hdlcstate(struct BCState *bcs) { modehdlc(bcs, 0, 0); - bc_close(bcs); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hdlc.rcvbuf) { + kfree(bcs->hw.hdlc.rcvbuf); + bcs->hw.hdlc.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } } int open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) { - return bc_open(bcs); + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hdlc.rcvbuf\n"); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hdlc.rcvbuf); + bcs->hw.hdlc.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hdlc.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); } int setstack_hdlc(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; - bcs->unit = bcs->channel; if (open_hdlcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = hdlc_l2l1; + st->l2.l2l1 = hdlc_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); return (0); } -static struct bc_l1_ops hdlc_l1_ops = { - .fill_fifo = hdlc_fill_fifo, - .open = setstack_hdlc, - .close = close_hdlcstate, -}; - -static void __init -inithdlc(struct IsdnCardState *cs) +void __init +clear_pending_hdlc_ints(struct IsdnCardState *cs) { u_int val; @@ -525,7 +633,15 @@ inithdlc(struct IsdnCardState *cs) val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3); debugl1(cs, "HDLC 2 VIN %x", val); } +} +void __init +inithdlc(struct IsdnCardState *cs) +{ + cs->bcs[0].BC_SetStack = setstack_hdlc; + cs->bcs[1].BC_SetStack = setstack_hdlc; + cs->bcs[0].BC_Close = close_hdlcstate; + cs->bcs[1].BC_Close = close_hdlcstate; modehdlc(cs->bcs, -1, 0); modehdlc(cs->bcs + 1, -1, 1); } @@ -534,13 +650,17 @@ static irqreturn_t avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; - u8 sval; + u_long flags; + u_char val; + u_char sval; + spin_lock_irqsave(&cs->lock, flags); sval = inb(cs->hw.avm.cfg_reg + 2); - if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) + if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { /* possible a shared IRQ reqest */ + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; + } if (!(sval & AVM_STATUS0_IRQ_ISAC)) { val = ReadISAC(cs, ISAC_ISTA); isac_interrupt(cs, val); @@ -550,192 +670,187 @@ avm_pcipnp_interrupt(int intno, void *de } WriteISAC(cs, ISAC_MASK, 0xFF); WriteISAC(cs, ISAC_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static int -avm_pcipnp_reset(struct IsdnCardState *cs) +static void +reset_avmpcipnp(struct IsdnCardState *cs) { printk(KERN_INFO "AVM PCI/PnP: reset\n"); outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + mdelay(10); outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + mdelay(10); printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); - return 0; -} - -static void -avm_pcipnp_init(struct IsdnCardState *cs) -{ - initisac(cs); - inithdlc(cs); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER, - cs->hw.avm.cfg_reg + 2); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | - AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); -} - -static void -avm_pcipnp_release(struct IsdnCardState *cs) -{ - outb(0, cs->hw.avm.cfg_reg + 2); - hisax_release_resources(cs); } -static struct card_ops avm_pci_ops = { - .init = avm_pcipnp_init, - .reset = avm_pcipnp_reset, - .release = avm_pcipnp_release, - .irq_func = avm_pcipnp_interrupt, -}; - -static int __init -avm_pcipnp_hw_init(struct IsdnCardState *cs) -{ - cs->bc_hw_ops = &hdlc_hw_ops; - cs->bc_l1_ops = &hdlc_l1_ops; - cs->card_ops = &avm_pci_ops; - avm_pcipnp_reset(cs); - return isac_setup(cs, &isac_ops); -} - -static int __init -avm_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - int rc; - u32 val; - - printk(KERN_INFO "AVM PCI: defined at %#lx IRQ %u\n", - pci_resource_start(pdev, 1), pdev->irq); - - rc = -EBUSY; - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = AVM_FRITZ_PCI; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.avm.cfg_reg = pci_resource_start(pdev, 1); - cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; - if (!request_io(&cs->rs, cs->hw.avm.cfg_reg, 32, "avm PCI")) - goto err; - - val = inl(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM PCI: stat %#x\n", val); - printk(KERN_INFO "AVM PCI: Class %X Rev %d\n", - val & 0xff, (val>>8) & 0xff); - - if (avm_pcipnp_hw_init(cs)) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return rc; -} - -static int __init -avm_pnp_probe(struct IsdnCardState *cs, struct IsdnCard *card) +static int +AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int rc; - u8 val, ver; + u_long flags; - printk(KERN_INFO "AVM PnP: defined at %#lx IRQ %lu\n", - card->para[1], card->para[0]); - - cs->subtyp = AVM_FRITZ_PNP; - cs->irq = card->para[0]; - cs->hw.avm.cfg_reg = card->para[1]; - cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; - - rc = -EBUSY; - if (!request_io(&cs->rs, cs->hw.avm.cfg_reg, 32, "avm PnP")) - goto err; - - val = inb(cs->hw.avm.cfg_reg); - ver = inb(cs->hw.avm.cfg_reg + 1); - printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver); - - if (avm_pcipnp_hw_init(cs)) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return rc; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_avmpcipnp(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + outb(0, cs->hw.avm.cfg_reg + 2); + release_region(cs->hw.avm.cfg_reg, 32); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + reset_avmpcipnp(cs); + clear_pending_isac_ints(cs); + initisac(cs); + inithdlc(cs); + outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER, + cs->hw.avm.cfg_reg + 2); + WriteISAC(cs, ISAC_MASK, 0); + outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | + AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); + /* RESET Receiver and Transmitter */ + WriteISAC(cs, ISAC_CMDR, 0x41); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } static struct pci_dev *dev_avm __initdata = NULL; #ifdef __ISAPNP__ -static struct pnp_card *card_avm __initdata = NULL; -static struct pnp_dev *pnp_avm __initdata = NULL; +static struct pnp_card *pnp_avm_c __initdata = NULL; #endif int __init setup_avm_pcipnp(struct IsdnCard *card) { + u_int val, ver; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, avm_pci_rev); printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_FRITZPCI) + return (0); if (card->para[1]) { /* old manual method */ - if (avm_pnp_probe(card->cs, card)) - return 0; - return 1; + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->subtyp = AVM_FRITZ_PNP; } else { #ifdef __ISAPNP__ if (isapnp_present()) { - struct pnp_card *ba; - if ((ba = pnp_find_card( + struct pnp_dev *pnp_avm_d = NULL; + if ((pnp_avm_c = pnp_find_card( ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), card_avm))) { - card_avm = ba; - pnp_avm = NULL; - if ((pnp_avm = pnp_find_dev(card_avm, + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm))) { - if (pnp_device_attach(pnp_avm) < 0) { - printk(KERN_ERR "FritzPnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pnp_avm) < 0) { - printk(KERN_ERR "FritzPnP: activate failed\n"); - pnp_device_detach(pnp_avm); - return 0; + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; + + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_irq_valid(pnp_avm, 0)) { + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { printk(KERN_ERR "FritzPnP:No IRQ\n"); - pnp_device_detach(pnp_avm); return(0); } - if (!pnp_port_valid(pnp_avm, 0)) { + if (!cs->hw.avm.cfg_reg) { printk(KERN_ERR "FritzPnP:No IO address\n"); - pnp_device_detach(pnp_avm); return(0); } - card->para[1] = pnp_port_start(pnp_avm, 0); - card->para[0] = pnp_irq(pnp_avm, 0); - if (avm_pnp_probe(card->cs, card)) - return 0; - return 1; + cs->subtyp = AVM_FRITZ_PNP; + goto ready; } } + } else { + printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); } #endif -#ifdef CONFIG_PCI +#if CONFIG_PCI if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, dev_avm))) { - if (avm_pci_probe(card->cs, dev_avm)) - return 0; - return 1; + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + if (pci_enable_device(dev_avm)) + return(0); + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); } + cs->irq_flags |= SA_SHIRQ; +#else + printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); + return (0); #endif /* CONFIG_PCI */ } - printk(KERN_WARNING "FritzPCI: No card found\n"); - return 0; +ready: + cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; + if (!request_region(cs->hw.avm.cfg_reg, 32, + (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.avm.cfg_reg, + cs->hw.avm.cfg_reg + 31); + return (0); + } + switch (cs->subtyp) { + case AVM_FRITZ_PCI: + val = inl(cs->hw.avm.cfg_reg); + printk(KERN_INFO "AVM PCI: stat %#x\n", val); + printk(KERN_INFO "AVM PCI: Class %X Rev %d\n", + val & 0xff, (val>>8) & 0xff); + cs->BC_Read_Reg = &ReadHDLC_s; + cs->BC_Write_Reg = &WriteHDLC_s; + break; + case AVM_FRITZ_PNP: + val = inb(cs->hw.avm.cfg_reg); + ver = inb(cs->hw.avm.cfg_reg + 1); + printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver); + cs->BC_Read_Reg = &ReadHDLCPnP; + cs->BC_Write_Reg = &WriteHDLCPnP; + break; + default: + printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp); + return(0); + } + printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n", + (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP", + cs->irq, cs->hw.avm.cfg_reg); + + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Send_Data = &hdlc_fill_fifo; + cs->cardmsg = &AVM_card_msg; + cs->irq_func = &avm_pcipnp_interrupt; + cs->writeisac(cs, ISAC_MASK, 0xFF); + ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); + return (1); } diff -puN drivers/isdn/hisax/bkm_a4t.c~i4l drivers/isdn/hisax/bkm_a4t.c --- 25/drivers/isdn/hisax/bkm_a4t.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/bkm_a4t.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.13.6.6 2001/09/23 22:24:46 kai Exp $ +/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $ * * low level stuff for T-Berkom A4T * @@ -10,6 +10,7 @@ * */ + #include #include #include "hisax.h" @@ -21,51 +22,47 @@ #include "bkm_ax.h" extern const char *CardType[]; -// FIXME needs per card lock -static spinlock_t bkm_a4t_lock = SPIN_LOCK_UNLOCKED; -const char *bkm_a4t_revision = "$Revision: 1.13.6.6 $"; +const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $"; + -static inline u8 -readreg(unsigned int ale, unsigned long adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned long adr, u_char off) { - u_int ret; - unsigned long flags; + register u_int ret; unsigned int *po = (unsigned int *) adr; /* Postoffice */ - spin_lock_irqsave(&bkm_a4t_lock, flags); + *po = (GCS_2 | PO_WRITE | off); __WAITI20__(po); *po = (ale | PO_READ); __WAITI20__(po); ret = *po; - spin_unlock_irqrestore(&bkm_a4t_lock, flags); return ((unsigned char) ret); } + static inline void -writereg(unsigned int ale, unsigned long adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size) +{ + int i; + for (i = 0; i < size; i++) + *data++ = readreg(ale, adr, off); +} + + +static inline void +writereg(unsigned int ale, unsigned long adr, u_char off, u_char data) { - unsigned long flags; unsigned int *po = (unsigned int *) adr; /* Postoffice */ - spin_lock_irqsave(&bkm_a4t_lock, flags); *po = (GCS_2 | PO_WRITE | off); __WAITI20__(po); *po = (ale | PO_WRITE | data); __WAITI20__(po); - spin_unlock_irqrestore(&bkm_a4t_lock, flags); } -static inline void -readfifo(unsigned int ale, unsigned long adr, u8 off, u8 * data, int size) -{ - int i; - - for (i = 0; i < size; i++) - *data++ = readreg(ale, adr, off); -} static inline void -writefifo(unsigned int ale, unsigned long adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size) { int i; @@ -73,84 +70,74 @@ writefifo(unsigned int ale, unsigned lon writereg(ale, adr, off, *data++); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -jade_read(struct IsdnCardState *cs, int jade, u8 offset) +static u_char +ReadJADE(struct IsdnCardState *cs, int jade, u_char offset) { - return readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))); + return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)))); } static void -jade_write(struct IsdnCardState *cs, int jade, u8 offset, u8 value) +WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value) { writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value); } -static void -jade_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - readfifo(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, - (hscx == -1 ? 0 : (hscx ? 0xc0 : 0x80)), data, size); -} +/* + * fast interrupt JADE stuff goes here + */ -static void -jade_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - writefifo(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, - (hscx == -1 ? 0 : (hscx ? 0xc0 : 0x80)), data, size); -} +#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80))) +#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data) + +#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) +#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) -static struct bc_hw_ops jade_ops = { - .read_reg = jade_read, - .write_reg = jade_write, - .read_fifo = jade_read_fifo, - .write_fifo = jade_write_fifo, -}; +#include "jade_irq.c" static irqreturn_t bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val = 0; + u_char val = 0; + u_long flags; I20_REGISTER_FILE *pI20_Regs; - int handled = 0; - spin_lock(&cs->lock); + spin_lock_irqsave(&cs->lock, flags); pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); /* ISDN interrupt pending? */ if (pI20_Regs->i20IntStatus & intISDN) { - handled = 1; /* Reset the ISDN interrupt */ pI20_Regs->i20IntStatus = intISDN; /* Disable ISDN interrupt */ @@ -172,129 +159,101 @@ bkm_interrupt(int intno, void *dev_id, s } /* Reenable ISDN interrupt */ pI20_Regs->i20IntCtrl |= intISDN; + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; + } else { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; } - spin_unlock(&cs->lock); - return IRQ_RETVAL(handled); } -static void -enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) +void +release_io_bkm(struct IsdnCardState *cs) { - I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - if (bEnable) - pI20_Regs->i20IntCtrl |= (intISDN | intPCI); - else - /* CAUTION: This disables the video capture driver too */ - pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI); + if (cs->hw.ax.base) { + iounmap((void *) cs->hw.ax.base); + cs->hw.ax.base = 0; + } } static void -reset_bkm(struct IsdnCardState *cs) +enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) { - I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - /* Issue the I20 soft reset */ - pI20_Regs->i20SysControl = 0xFF; /* all in */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - /* Remove the soft reset */ - pI20_Regs->i20SysControl = sysRESET | 0xFF; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - /* Set our configuration */ - pI20_Regs->i20SysControl = sysRESET | sysCFG; - /* Issue ISDN reset */ - pI20_Regs->i20GuestControl = guestWAIT_CFG | - g_A4T_JADE_RES | - g_A4T_ISAR_RES | - g_A4T_ISAC_RES | - g_A4T_JADE_BOOTR | - g_A4T_ISAR_BOOTR; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - - /* Remove RESET state from ISDN */ - pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | - g_A4T_JADE_RES | - g_A4T_ISAR_RES); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); + if (cs->typ == ISDN_CTYPE_BKM_A4T) { + I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + if (bEnable) + pI20_Regs->i20IntCtrl |= (intISDN | intPCI); + else + /* CAUTION: This disables the video capture driver too */ + pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI); + } } static void -bkm_a4t_init(struct IsdnCardState *cs) +reset_bkm(struct IsdnCardState *cs) { - initisac(cs); - initjade(cs); - /* Enable ints */ - enable_bkm_int(cs, 1); + if (cs->typ == ISDN_CTYPE_BKM_A4T) { + I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + /* Issue the I20 soft reset */ + pI20_Regs->i20SysControl = 0xFF; /* all in */ + mdelay(10); + /* Remove the soft reset */ + pI20_Regs->i20SysControl = sysRESET | 0xFF; + mdelay(10); + /* Set our configuration */ + pI20_Regs->i20SysControl = sysRESET | sysCFG; + /* Issue ISDN reset */ + pI20_Regs->i20GuestControl = guestWAIT_CFG | + g_A4T_JADE_RES | + g_A4T_ISAR_RES | + g_A4T_ISAC_RES | + g_A4T_JADE_BOOTR | + g_A4T_ISAR_BOOTR; + mdelay(10); + + /* Remove RESET state from ISDN */ + pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | + g_A4T_JADE_RES | + g_A4T_ISAR_RES); + mdelay(10); + } } static int -bkm_a4t_reset(struct IsdnCardState *cs) +BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - /* Disable ints */ - enable_bkm_int(cs, 0); - reset_bkm(cs); - return 0; -} - -static void -bkm_a4t_release(struct IsdnCardState *cs) -{ - reset_bkm(cs); - hisax_release_resources(cs); -} - -static struct card_ops bkm_a4t_ops = { - .init = bkm_a4t_init, - .reset = bkm_a4t_reset, - .release = bkm_a4t_release, - .irq_func = bkm_interrupt, -}; + u_long flags; -static int __init -bkm_a4t_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - I20_REGISTER_FILE *pI20_Regs; - int rc; - - printk(KERN_INFO "BKM A4T: defined at %#lx IRQ %u\n", - pci_resource_start(pdev, 0), pdev->irq); - - rc = -EBUSY; - if (pci_enable_device(pdev)) - goto err; - - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.avm.cfg_reg = pci_resource_start(pdev, 1); - - cs->hw.ax.base = (unsigned long)request_mmio(&cs->rs, pci_resource_start(pdev, 0), 4096, "Telekom A4T"); - if (!cs->hw.ax.base) - goto err; - - /* Check suspicious address */ - // FIXME needs to use read[bl] - pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { - printk(KERN_WARNING "HiSax: address %lx suspicious\n", - cs->hw.ax.base); - goto err; + switch (mt) { + case CARD_RESET: + /* Disable ints */ + spin_lock_irqsave(&cs->lock, flags); + enable_bkm_int(cs, 0); + reset_bkm(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_RELEASE: + /* Sanity */ + spin_lock_irqsave(&cs->lock, flags); + enable_bkm_int(cs, 0); + reset_bkm(cs); + spin_unlock_irqrestore(&cs->lock, flags); + release_io_bkm(cs); + return (0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + clear_pending_isac_ints(cs); + clear_pending_jade_ints(cs); + initisac(cs); + initjade(cs); + /* Enable ints */ + enable_bkm_int(cs, 1); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_TEST: + return (0); } - cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; - cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; - cs->hw.ax.isac_ale = GCS_1; - cs->hw.ax.jade_ale = GCS_3; - - reset_bkm(cs); - cs->card_ops = &bkm_a4t_ops; - isac_setup(cs, &isac_ops); - jade_setup(cs, &jade_ops); - return 0; - - err: - hisax_release_resources(cs); - return rc; + return (0); } static struct pci_dev *dev_a4t __initdata = NULL; @@ -302,10 +261,21 @@ static struct pci_dev *dev_a4t __initdat int __init setup_bkm_a4t(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; + u_int pci_memaddr = 0, found = 0; + I20_REGISTER_FILE *pI20_Regs; +#if CONFIG_PCI +#endif strcpy(tmp, bkm_a4t_revision); printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_BKM_A4T) { + cs->subtyp = BKM_A4T; + } else + return (0); + +#if CONFIG_PCI while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { u16 sub_sys; @@ -313,13 +283,62 @@ setup_bkm_a4t(struct IsdnCard *card) sub_vendor = dev_a4t->subsystem_vendor; sub_sys = dev_a4t->subsystem_device; - if (sub_sys == PCI_DEVICE_ID_BERKOM_A4T && - sub_vendor == PCI_VENDOR_ID_BERKOM) { - if (bkm_a4t_probe(card->cs, dev_a4t)) - return 0; - return 1; + if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) { + if (pci_enable_device(dev_a4t)) + return(0); + found = 1; + pci_memaddr = pci_resource_start(dev_a4t, 0); + cs->irq = dev_a4t->irq; + break; } } - printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]); - return 0; + if (!found) { + printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]); + return (0); + } + if (!cs->irq) { /* IRQ range check ?? */ + printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]); + return (0); + } + if (!pci_memaddr) { + printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]); + return (0); + } + cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096); + /* Check suspecious address */ + pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { + printk(KERN_WARNING "HiSax: %s address %lx-%lx suspecious\n", + CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096); + iounmap((void *) cs->hw.ax.base); + cs->hw.ax.base = 0; + return (0); + } + cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; + cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; + cs->hw.ax.isac_ale = GCS_1; + cs->hw.ax.jade_ale = GCS_3; +#else + printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]); + printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]); + return (0); +#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n", + CardType[card->typ], cs->hw.ax.base, cs->irq); + + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadJADE; + cs->BC_Write_Reg = &WriteJADE; + cs->BC_Send_Data = &jade_fill_fifo; + cs->cardmsg = &BKM_card_msg; + cs->irq_func = &bkm_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "Telekom A4T:"); + /* Jade version */ + JadeVersion(cs, "Telekom A4T:"); + return (1); } diff -puN drivers/isdn/hisax/bkm_a8.c~i4l drivers/isdn/hisax/bkm_a8.c --- 25/drivers/isdn/hisax/bkm_a8.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/bkm_a8.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.14.6.7 2001/09/23 22:24:46 kai Exp $ +/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $ * * low level stuff for Scitel Quadro (4*S0, passive) * @@ -10,6 +10,7 @@ * */ + #include #include #include "hisax.h" @@ -20,11 +21,13 @@ #include #include "bkm_ax.h" +#if CONFIG_PCI + #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; -static spinlock_t bkm_a8_lock = SPIN_LOCK_UNLOCKED; -const char sct_quadro_revision[] = "$Revision: 1.14.6.7 $"; + +const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $"; static const char *sct_quadro_subtypes[] = { @@ -39,70 +42,174 @@ static const char *sct_quadro_subtypes[] #define wordout(addr,val) outw(val,addr) #define wordin(addr) inw(addr) -static inline u8 -ipac_read(struct IsdnCardState *cs, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; - - spin_lock_irqsave(&bkm_a8_lock, flags); - wordout(cs->hw.ax.base, off); - ret = wordin(cs->hw.ax.data_adr) & 0xFF; - spin_unlock_irqrestore(&bkm_a8_lock, flags); - return ret; + register u_char ret; + wordout(ale, off); + ret = wordin(adr) & 0xFF; + return (ret); } static inline void -ipac_write(struct IsdnCardState *cs, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; + int i; + wordout(ale, off); + for (i = 0; i < size; i++) + data[i] = wordin(adr) & 0xFF; +} - spin_lock_irqsave(&bkm_a8_lock, flags); - wordout(cs->hw.ax.base, off); - wordout(cs->hw.ax.data_adr, data); - spin_unlock_irqrestore(&bkm_a8_lock, flags); + +static inline void +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) +{ + wordout(ale, off); + wordout(adr, data); } static inline void -ipac_readfifo(struct IsdnCardState *cs, u8 off, u8 *data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { int i; - - wordout(cs->hw.ax.base, off); + wordout(ale, off); for (i = 0; i < size; i++) - data[i] = wordin(cs->hw.ax.data_adr) & 0xFF; + wordout(adr, data[i]); } -static inline void -ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 *data, int size) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - int i; + return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80)); +} - wordout(cs->hw.ax.base, off); - for (i = 0; i < size; i++) - wordout(cs->hw.ax.data_adr, data[i]); +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); } -/* This will generate ipac_dc_ops and ipac_bc_ops using the functions - * above */ -BUILD_IPAC_OPS(ipac); - +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0))); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); +} + /* Set the specific ipac to active */ static void set_ipac_active(struct IsdnCardState *cs, u_int active) { /* set irq mask */ - ipac_write(cs, IPAC_MASK, active ? 0xc0 : 0xff); + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, + active ? 0xc0 : 0xff); +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \ + cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \ + cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data) +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \ + cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \ + cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 5; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); + if (!(ista & 0x3f)) { /* not this IPAC */ + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; + } + Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) { + hscx_int_main(cs, val); + } + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n", + CardType[cs->typ], + sct_quadro_subtypes[cs->subtyp]); + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +void +release_io_sct_quadro(struct IsdnCardState *cs) +{ + release_region(cs->hw.ax.base & 0xffffffc0, 128); + if (cs->subtyp == SCT_1) + release_region(cs->hw.ax.plx_adr, 64); } static void enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) { - if (bEnable) - wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); - else - wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); + if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { + if (bEnable) + wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); + else + wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); + } } static void @@ -110,66 +217,88 @@ reset_bkm(struct IsdnCardState *cs) { if (cs->subtyp == SCT_1) { wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); + mdelay(10); /* Remove the soft reset */ wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); + mdelay(10); } } -static void -bkm_a8_init(struct IsdnCardState *cs) -{ - cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs, 1); - ipac_init(cs); - /* Enable ints */ - enable_bkm_int(cs, 1); -} - static int -bkm_a8_reset(struct IsdnCardState *cs) +BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - /* Disable ints */ - set_ipac_active(cs, 0); - enable_bkm_int(cs, 0); - reset_bkm(cs); - return 0; + u_long flags; + + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + /* Disable ints */ + set_ipac_active(cs, 0); + enable_bkm_int(cs, 0); + reset_bkm(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_RELEASE: + /* Sanity */ + spin_lock_irqsave(&cs->lock, flags); + set_ipac_active(cs, 0); + enable_bkm_int(cs, 0); + spin_unlock_irqrestore(&cs->lock, flags); + release_io_sct_quadro(cs); + return (0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + cs->debug |= L1_DEB_IPAC; + set_ipac_active(cs, 1); + inithscxisac(cs, 3); + /* Enable ints */ + enable_bkm_int(cs, 1); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_TEST: + return (0); + } + return (0); } -static void -bkm_a8_release(struct IsdnCardState *cs) +int __init +sct_alloc_io(u_int adr, u_int len) { - set_ipac_active(cs, 0); - enable_bkm_int(cs, 0); - hisax_release_resources(cs); + if (!request_region(adr, len, "scitel")) { + printk(KERN_WARNING + "HiSax: Scitel port %#x-%#x already in use\n", + adr, adr + len); + return (1); + } + return(0); } -static struct card_ops bkm_a8_ops = { - .init = bkm_a8_init, - .reset = bkm_a8_reset, - .release = bkm_a8_release, - .irq_func = ipac_irq, -}; - static struct pci_dev *dev_a8 __initdata = NULL; static u16 sub_vendor_id __initdata = 0; static u16 sub_sys_id __initdata = 0; -static u8 pci_irq __initdata = 0; +static u_char pci_bus __initdata = 0; +static u_char pci_device_fn __initdata = 0; +static u_char pci_irq __initdata = 0; + +#endif /* CONFIG_PCI */ int __init setup_sct_quadro(struct IsdnCard *card) { +#if CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; - u8 pci_rev_id; + u_char pci_rev_id; u_int found = 0; u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; strcpy(tmp, sct_quadro_revision); printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { + cs->subtyp = SCT_1; /* Preset */ + } else + return (0); + /* Identify subtype by para[0] */ if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) cs->subtyp = card->para[0]; @@ -193,6 +322,8 @@ setup_sct_quadro(struct IsdnCard *card) return(0); pci_ioaddr1 = pci_resource_start(dev_a8, 1); pci_irq = dev_a8->irq; + pci_bus = dev_a8->bus->number; + pci_device_fn = dev_a8->devfn; found = 1; break; } @@ -253,31 +384,40 @@ setup_sct_quadro(struct IsdnCard *card) cs->hw.ax.plx_adr = pci_ioaddr1; /* Enter all ipac_base addresses */ switch(cs->subtyp) { - case 1: - cs->hw.ax.base = pci_ioaddr5 + 0x00; - if (!request_io(&cs->rs, pci_ioaddr1, 128, "scitel")) - goto err; - if (!request_io(&cs->rs, pci_ioaddr5, 64, "scitel")) - goto err; - break; - case 2: - cs->hw.ax.base = pci_ioaddr4 + 0x08; - if (!request_io(&cs->rs, pci_ioaddr4, 64, "scitel")) - goto err; - break; - case 3: - cs->hw.ax.base = pci_ioaddr3 + 0x10; - if (!request_io(&cs->rs, pci_ioaddr3, 64, "scitel")) - goto err; - break; - case 4: - cs->hw.ax.base = pci_ioaddr2 + 0x20; - if (!request_io(&cs->rs, pci_ioaddr2, 64, "scitel")) - goto err; - break; + case 1: + cs->hw.ax.base = pci_ioaddr5 + 0x00; + if (sct_alloc_io(pci_ioaddr1, 128)) + return(0); + if (sct_alloc_io(pci_ioaddr5, 64)) + return(0); + /* disable all IPAC */ + writereg(pci_ioaddr5, pci_ioaddr5 + 4, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, + IPAC_MASK, 0xFF); + break; + case 2: + cs->hw.ax.base = pci_ioaddr4 + 0x08; + if (sct_alloc_io(pci_ioaddr4, 64)) + return(0); + break; + case 3: + cs->hw.ax.base = pci_ioaddr3 + 0x10; + if (sct_alloc_io(pci_ioaddr3, 64)) + return(0); + break; + case 4: + cs->hw.ax.base = pci_ioaddr2 + 0x20; + if (sct_alloc_io(pci_ioaddr2, 64)) + return(0); + break; } + /* For isac and hscx data path */ cs->hw.ax.data_adr = cs->hw.ax.base + 4; - ipac_write(cs, IPAC_MASK, 0xFF); printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n", CardType[card->typ], @@ -287,12 +427,25 @@ setup_sct_quadro(struct IsdnCard *card) cs->hw.ax.data_adr, cs->irq); - cs->card_ops = &bkm_a8_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; - - return 1; - err: - hisax_release_resources(cs); - return 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &BKM_card_msg; + cs->irq_func = &bkm_interrupt_ipac; + + printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp], + readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); + return (1); +#else + printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); +#endif /* CONFIG_PCI */ } diff -puN drivers/isdn/hisax/callc.c~i4l drivers/isdn/hisax/callc.c --- 25/drivers/isdn/hisax/callc.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/callc.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.51.6.6 2001/09/23 22:24:46 kai Exp $ +/* $Id: callc.c,v 2.59.2.3 2004/01/13 14:31:24 keil Exp $ * * Author Karsten Keil * Copyright by Karsten Keil @@ -21,8 +21,7 @@ #include "hisax.h" #include - -const char *lli_revision = "$Revision: 2.51.6.6 $"; +const char *lli_revision = "$Revision: 2.59.2.3 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -32,7 +31,6 @@ static void release_b_st(struct Channel static struct Fsm callcfsm; static int chancount; -static spinlock_t callc_lock = SPIN_LOCK_UNLOCKED; /* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ #define ALERT_REJECT 0 @@ -205,49 +203,13 @@ lli_deliver_cause(struct Channel *chanp) } static inline void -mdl_info_setup(struct Channel *chanp) -{ - if (chanp->chan) - chanp->cs->status |= 0x0200; - else - chanp->cs->status |= 0x0100; - - if (chanp->cs->card_ops->led_handler) - chanp->cs->card_ops->led_handler(chanp->cs); -} - -static inline void -mdl_info_connect(struct Channel *chanp) -{ - if (chanp->chan) - chanp->cs->status |= 0x2000; - else - chanp->cs->status |= 0x1000; - - if (chanp->cs->card_ops->led_handler) - chanp->cs->card_ops->led_handler(chanp->cs); -} - -static inline void -mdl_info_release(struct Channel *chanp) -{ - if (chanp->chan) - chanp->cs->status &= ~0x2200; - else - chanp->cs->status &= ~0x1100; - - if (chanp->cs->card_ops->led_handler) - chanp->cs->card_ops->led_handler(chanp->cs); -} - -static void lli_close(struct FsmInst *fi) { struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_NULL); chanp->Flags = 0; - mdl_info_release(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } static void @@ -259,8 +221,7 @@ lli_leased_in(struct FsmInst *fi, int ev if (!chanp->leased) return; - - mdl_info_setup(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); FsmChangeState(fi, ST_IN_WAIT_LL); if (chanp->debug & 1) link_debug(chanp, 0, "STAT_ICALL_LEASED"); @@ -277,11 +238,12 @@ lli_leased_in(struct FsmInst *fi, int ev if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); if (!ret) { - mdl_info_release(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); } } + /* * Dial out */ @@ -295,7 +257,7 @@ lli_init_bchan_out(struct FsmInst *fi, i link_debug(chanp, 0, "STAT_DCONN"); HL_LL(chanp, ISDN_STAT_DCONN); init_b_st(chanp, 0); - L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -307,12 +269,12 @@ lli_prep_dialout(struct FsmInst *fi, int FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; - mdl_info_setup(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); if (chanp->leased) { lli_init_bchan_out(fi, event, arg); } else { FsmChangeState(fi, ST_OUT_DIAL); - L4L3(chanp->d_st, CC_SETUP | REQUEST, chanp); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp); } } @@ -325,12 +287,12 @@ lli_resume(struct FsmInst *fi, int event FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; - mdl_info_setup(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); if (chanp->leased) { lli_init_bchan_out(fi, event, arg); } else { FsmChangeState(fi, ST_OUT_DIAL); - L4L3(chanp->d_st, CC_RESUME | REQUEST, chanp); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp); } } @@ -353,7 +315,7 @@ lli_go_active(struct FsmInst *fi, int ev ic.command = ISDN_STAT_BCONN; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); - mdl_info_connect(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan); } @@ -370,7 +332,7 @@ lli_deliver_call(struct FsmInst *fi, int isdn_ctrl ic; int ret; - mdl_info_setup(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); /* * Report incoming calls only once to linklevel, use CallFlags * which is set to 3 with each broadcast message in isdnl1.c @@ -397,34 +359,34 @@ lli_deliver_call(struct FsmInst *fi, int case 1: /* OK, someone likes this call */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_ALERT_SENT); - L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); break; case 5: /* direct redirect */ case 4: /* Proceeding desired */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_PROCEED_SEND); - L4L3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); - L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; case 2: /* Rejecting Call */ break; case 3: /* incomplete number */ FsmDelTimer(&chanp->drel_timer, 61); - L4L3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ - L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); - mdl_info_release(chanp); + chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); break; } } else { - L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); - mdl_info_release(chanp); + chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } } @@ -434,7 +396,7 @@ lli_send_dconnect(struct FsmInst *fi, in struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); } static void @@ -443,7 +405,7 @@ lli_send_alert(struct FsmInst *fi, int e struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_IN_ALERT_SENT); - L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); } static void @@ -451,7 +413,7 @@ lli_send_redir(struct FsmInst *fi, int e { struct Channel *chanp = fi->userdata; - L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } static void @@ -466,7 +428,7 @@ lli_init_bchan_in(struct FsmInst *fi, in chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = !0; init_b_st(chanp, !0); - L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -479,9 +441,9 @@ lli_setup_rsp(struct FsmInst *fi, int ev } else { FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); #ifdef WANT_ALERT - L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); #endif - L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); } } @@ -492,7 +454,7 @@ lli_suspend(struct FsmInst *fi, int even { struct Channel *chanp = fi->userdata; - L4L3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc); } /* Call clearing */ @@ -524,7 +486,8 @@ lli_disconnect_req(struct FsmInst *fi, i FsmChangeState(fi, ST_WAIT_DRELEASE); if (chanp->proc) chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, + chanp->proc); } } @@ -539,7 +502,8 @@ lli_disconnect_reject(struct FsmInst *fi FsmChangeState(fi, ST_WAIT_DRELEASE); if (chanp->proc) chanp->proc->para.cause = 0x15; /* Call Rejected */ - L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, + chanp->proc); } } @@ -571,12 +535,12 @@ lli_reject_req(struct FsmInst *fi, int e #ifndef ALERT_REJECT if (chanp->proc) chanp->proc->para.cause = 0x15; /* Call Rejected */ - L4L3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); lli_dhup_close(fi, event, arg); #else FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); FsmChangeState(fi, ST_IN_ALERT_SENT); - L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); #endif } @@ -587,7 +551,7 @@ lli_disconn_bchan(struct FsmInst *fi, in chanp->data_open = 0; FsmChangeState(fi, ST_WAIT_BRELEASE); - L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } static void @@ -642,7 +606,7 @@ lli_release_bchan(struct FsmInst *fi, in chanp->data_open = 0; FsmChangeState(fi, ST_WAIT_BREL_DISC); - L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } @@ -672,7 +636,7 @@ lli_abort(struct FsmInst *fi, int event, struct Channel *chanp = fi->userdata; chanp->data_open = 0; - L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); lli_bhup_dhup(fi, event, arg); } @@ -685,7 +649,8 @@ lli_release_req(struct FsmInst *fi, int lli_leased_hup(fi, chanp); } else { FsmChangeState(fi, ST_WAIT_D_REL_CNF); - L4L3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, + chanp->proc); } } @@ -767,7 +732,7 @@ lli_failure_l(struct FsmInst *fi, int ev chanp->cs->iif.statcallb(&ic); HL_LL(chanp, ISDN_STAT_DHUP); chanp->Flags = 0; - mdl_info_release(chanp); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } static void @@ -796,7 +761,7 @@ lli_failure_a(struct FsmInst *fi, int ev struct Channel *chanp = fi->userdata; chanp->data_open = 0; - L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); lli_bhup_fail(fi, event, arg); } @@ -890,11 +855,10 @@ CallcFree(void) static void release_b_st(struct Channel *chanp) { - struct IsdnCardState *cs = chanp->cs; struct PStack *st = chanp->b_st; if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) { - cs->bc_l1_ops->close(chanp->bcs); + chanp->bcs->BC_Close(chanp->bcs); switch (chanp->l2_active_protocol) { case (ISDN_PROTO_L2_X75I): releasestack_isdnl2(st); @@ -971,7 +935,7 @@ dchan_l3l4(struct PStack *st, int pr, vo if (pr == (CC_SETUP | INDICATION)) { if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) { pc->para.cause = 0x11; /* User busy */ - L4L3(pc->st, CC_REJECT | REQUEST, pc); + pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc); } else { chanp->proc = pc; pc->chan = chanp; @@ -1054,16 +1018,16 @@ init_PStack(struct PStack **stp) { if (!*stp) return -ENOMEM; (*stp)->next = NULL; + (*stp)->l1.l1l2 = dummy_pstack; (*stp)->l1.l1hw = dummy_pstack; (*stp)->l1.l1tei = dummy_pstack; - (*stp)->l1.l2l1 = dummy_pstack; - (*stp)->l2.l1l2 = dummy_pstack; (*stp)->l2.l2tei = dummy_pstack; - (*stp)->l2.l3l2 = dummy_pstack; - (*stp)->l3.l2l3 = dummy_pstack; + (*stp)->l2.l2l1 = dummy_pstack; + (*stp)->l2.l2l3 = dummy_pstack; + (*stp)->l3.l3l2 = dummy_pstack; (*stp)->l3.l3ml3 = dummy_pstack; - (*stp)->l3.l4l3 = dummy_pstack; - (*stp)->lli.l3l4 = dummy_pstack; + (*stp)->l3.l3l4 = dummy_pstack; + (*stp)->lli.l4l3 = dummy_pstack; (*stp)->ma.layer = dummy_pstack; return 0; } @@ -1101,7 +1065,8 @@ init_d_st(struct Channel *chanp) setstack_isdnl2(st, tmp); setstack_l3dc(st, chanp); st->lli.userdata = chanp; - st->lli.l3l4 = dchan_l3l4; + st->lli.l2writewakeup = NULL; + st->l3.l3l4 = dchan_l3l4; return 0; } @@ -1175,7 +1140,8 @@ CallcNewChan(struct IsdnCardState *csta) printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); - L4L3(csta->channel->d_st, DL_ESTABLISH | REQUEST, NULL); + csta->channel->d_st->lli.l4l3(csta->channel->d_st, + DL_ESTABLISH | REQUEST, NULL); } return (0); } @@ -1209,7 +1175,7 @@ CallcFreeChan(struct IsdnCardState *csta kfree(csta->channel[i].b_st); csta->channel[i].b_st = NULL; } else - printk(KERN_WARNING "CallcFreeChan b_st ch%d already freed\n", i); + printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i); if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { release_d_st(csta->channel + i); } else @@ -1218,30 +1184,13 @@ CallcFreeChan(struct IsdnCardState *csta } static void -ll_writewakeup(struct Channel *chanp, struct sk_buff *skb) -{ - isdn_ctrl ic; - - if (skb->pkt_type != PACKET_NOACK) { - if (chanp->debug & 0x800) - link_debug(chanp, 0, "llwakeup: %d", skb->truesize); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BSENT; - ic.arg = chanp->chan; - ic.parm.length = skb->truesize; - chanp->cs->iif.statcallb(&ic); - } - dev_kfree_skb(skb); -} - -static void lldata_handler(struct PStack *st, int pr, void *arg) { struct Channel *chanp = (struct Channel *) st->lli.userdata; struct sk_buff *skb = arg; switch (pr) { - case (DL_DATA | INDICATION): + case (DL_DATA | INDICATION): if (chanp->data_open) { if (chanp->debug & 0x800) link_debug(chanp, 0, "lldata: %d", skb->len); @@ -1251,9 +1200,6 @@ lldata_handler(struct PStack *st, int pr dev_kfree_skb(skb); } break; - case (DL_DATA | CONFIRM): - ll_writewakeup(chanp, skb); - break; case (DL_ESTABLISH | INDICATION): case (DL_ESTABLISH | CONFIRM): FsmEvent(&chanp->fi, EV_BC_EST, NULL); @@ -1286,9 +1232,6 @@ lltrans_handler(struct PStack *st, int p dev_kfree_skb(skb); } break; - case (PH_DATA | CONFIRM): - ll_writewakeup(chanp, skb); - break; case (PH_ACTIVATE | INDICATION): case (PH_ACTIVATE | CONFIRM): FsmEvent(&chanp->fi, EV_BC_EST, NULL); @@ -1304,6 +1247,21 @@ lltrans_handler(struct PStack *st, int p } } +static void +ll_writewakeup(struct PStack *st, int len) +{ + struct Channel *chanp = st->lli.userdata; + isdn_ctrl ic; + + if (chanp->debug & 0x800) + link_debug(chanp, 0, "llwakeup: %d", len); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_BSENT; + ic.arg = chanp->chan; + ic.parm.length = len; + chanp->cs->iif.statcallb(&ic); +} + static int init_b_st(struct Channel *chanp, int incoming) { @@ -1335,7 +1293,7 @@ init_b_st(struct Channel *chanp, int inc break; } chanp->bcs->conmsg = NULL; - if (cs->bc_l1_ops->open(st, chanp->bcs)) + if (chanp->bcs->BC_SetStack(st, chanp->bcs)) return (-1); st->l2.flag = 0; test_and_set_bit(FLG_LAPB, &st->l2.flag); @@ -1352,8 +1310,10 @@ init_b_st(struct Channel *chanp, int inc sprintf(tmp, "Ch%d X.75", chanp->chan); setstack_isdnl2(st, tmp); setstack_l3bc(st, chanp); - st->l3.l2l3 = lldata_handler; + st->l2.l2l3 = lldata_handler; st->lli.userdata = chanp; + st->lli.l1writewakeup = NULL; + st->lli.l2writewakeup = ll_writewakeup; st->l2.l2m.debug = chanp->debug & 16; st->l2.debug = chanp->debug & 64; break; @@ -1362,8 +1322,9 @@ init_b_st(struct Channel *chanp, int inc case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): case (ISDN_PROTO_L2_FAX): - st->l2.l1l2 = lltrans_handler; + st->l1.l1l2 = lltrans_handler; st->lli.userdata = chanp; + st->lli.l1writewakeup = ll_writewakeup; setstack_transl2(st); setstack_l3bc(st, chanp); break; @@ -1384,7 +1345,7 @@ leased_l4l3(struct PStack *st, int pr, v dev_kfree_skb(skb); break; case (DL_ESTABLISH | REQUEST): - L2L1(st, PH_ACTIVATE | REQUEST, NULL); + st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); break; case (DL_RELEASE | REQUEST): break; @@ -1462,7 +1423,7 @@ capi_debug(struct Channel *chanp, capi_m { char *t = tmpbuf; - t += QuickHex(t, (u8 *)cm, (cm->Length>50)? 50: cm->Length); + t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length); t--; *t= 0; HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf); @@ -1478,11 +1439,11 @@ lli_got_fac_req(struct Channel *chanp, c return; switch(cm->para[3]) { case 4: /* Suspend */ - strlcpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); + strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); FsmEvent(&chanp->fi, EV_SUSPEND, cm); break; case 5: /* Resume */ - strlcpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); + strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); if (chanp->fi.state == ST_NULL) { FsmEvent(&chanp->fi, EV_RESUME, cm); } else { @@ -1495,8 +1456,12 @@ lli_got_fac_req(struct Channel *chanp, c void lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) { - if (cs->card_ops->aux_ind) - cs->card_ops->aux_ind(cs, cm->para); + if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) || + (cs->typ == ISDN_CTYPE_ELSA_PCI)) { + if (cs->hw.elsa.MFlag) { + cs->cardmsg(cs, CARD_AUX_IND, cm->para); + } + } } @@ -1654,15 +1619,16 @@ HiSax_command(isdn_ctrl * ic) HiSax_putstatus(csta, "Card", "%d channel %d set leased mode\n", csta->cardnr + 1, num + 1); - chanp->d_st->l2.l1l2 = leased_l1l2; - chanp->d_st->l3.l4l3 = leased_l4l3; - L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); + chanp->d_st->l1.l1l2 = leased_l1l2; + chanp->d_st->lli.l4l3 = leased_l4l3; + chanp->d_st->lli.l4l3(chanp->d_st, + DL_ESTABLISH | REQUEST, NULL); } break; case (6): /* set B-channel test loop */ num = *(unsigned int *) ic->parm.num; if (csta->stlist) - csta->stlist->l1.l2l1(csta->stlist, + csta->stlist->l2.l2l1(csta->stlist, PH_TESTLOOP | REQUEST, (void *) (long)num); break; case (7): /* set card in PTP mode */ @@ -1676,7 +1642,8 @@ HiSax_command(isdn_ctrl * ic) HiSax_putstatus(csta, "set card ", "in PTP mode"); printk(KERN_DEBUG "HiSax: set card in PTP mode\n"); printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); - L4L3(csta->channel[0].d_st, DL_ESTABLISH | REQUEST, NULL); + csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st, + DL_ESTABLISH | REQUEST, NULL); } else { test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); @@ -1700,7 +1667,8 @@ HiSax_command(isdn_ctrl * ic) printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", num); } - L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, + DL_ESTABLISH | REQUEST, NULL); break; case (11): num = csta->debug & DEB_DLOG_HEX; @@ -1758,8 +1726,8 @@ HiSax_command(isdn_ctrl * ic) /* protocol specific io commands */ case (ISDN_CMD_PROT_IO): for (st = csta->stlist; st; st = st->next) - if ((u_int)st->protocol == (ic->arg & 0xFF)) - return(st->l3.l4l3_proto(st, ic)); + if (st->protocol == (ic->arg & 0xFF)) + return(st->lli.l4l3_proto(st, ic)); return(-EINVAL); break; default: @@ -1777,7 +1745,6 @@ HiSax_writebuf_skb(int id, int chan, int struct Channel *chanp; struct PStack *st; int len = skb->len; - unsigned long flags; struct sk_buff *nskb; if (!csta) { @@ -1807,22 +1774,20 @@ HiSax_writebuf_skb(int id, int chan, int return 0; } else if (chanp->debug & 0x800) link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt,MAX_DATA_MEM); - spin_lock_irqsave(&callc_lock, flags); nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { nskb->truesize = nskb->len; if (!ack) nskb->pkt_type = PACKET_NOACK; if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I) - L3L2(st, DL_DATA | REQUEST, nskb); + st->l3.l3l2(st, DL_DATA | REQUEST, nskb); else { chanp->bcs->tx_cnt += len; - st->l1.l2l1(st, PH_DATA | REQUEST, nskb); + st->l2.l2l1(st, PH_DATA | REQUEST, nskb); } dev_kfree_skb(skb); } else len = 0; - spin_unlock_irqrestore(&callc_lock, flags); } return (len); } diff -puN -L drivers/isdn/hisax/cert.c drivers/isdn/hisax/cert.c~i4l /dev/null --- 25/drivers/isdn/hisax/cert.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,50 +0,0 @@ -/* $Id: cert.c,v 2.3.6.3 2001/09/23 22:24:47 kai Exp $ - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * ../../../Documentation/isdn/HiSax.cert - * - */ - -#include - -int -certification_check(int output) { - -#ifdef CERTIFICATION -#if CERTIFICATION == 0 - if (output) { - printk(KERN_INFO "HiSax: Approval certification valid\n"); - printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n"); - printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n"); - printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n"); - printk(KERN_INFO "HiSax: Approved with HFC-S PCI A based cards\n"); - } - return(0); -#endif -#if CERTIFICATION == 1 - if (output) { - printk(KERN_INFO "HiSax: Approval certification failed because of\n"); - printk(KERN_INFO "HiSax: unauthorized source code changes\n"); - } - return(1); -#endif -#if CERTIFICATION == 127 - if (output) { - printk(KERN_INFO "HiSax: Approval certification not possible\n"); - printk(KERN_INFO "HiSax: because \"md5sum\" is not available\n"); - } - return(2); -#endif -#else - if (output) { - printk(KERN_INFO "HiSax: Certification not verified\n"); - } - return(3); -#endif -} diff -puN drivers/isdn/hisax/config.c~i4l drivers/isdn/hisax/config.c --- 25/drivers/isdn/hisax/config.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/config.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: config.c,v 1.1.4.2.2.1 2001/12/09 20:18:40 kai Exp $ +/* $Id: config.c,v 2.84.2.4 2004/01/24 20:47:20 keil Exp $ * * Author Karsten Keil * Copyright by Karsten Keil @@ -24,7 +24,6 @@ #include #include #include -#include "isdnl1.h" #define HISAX_STATUS_BUFSIZE 4096 #define INCLUDE_INLINE_FUNCS @@ -99,14 +98,9 @@ const char *CardType[] = { "Hotplug", "Formula-n enter:now PCI a/b", }; -void HiSax_closecard(int cardnr); -static spinlock_t hisax_config_lock = SPIN_LOCK_UNLOCKED; - #ifdef CONFIG_HISAX_ELSA #define DEFAULT_CARD ISDN_CTYPE_ELSA #define DEFAULT_CFG {0,0,0,0} -int elsa_init_pcmcia(void *, int, int *, int); -EXPORT_SYMBOL(elsa_init_pcmcia); #endif #ifdef CONFIG_HISAX_AVM_A1 @@ -121,8 +115,6 @@ EXPORT_SYMBOL(elsa_init_pcmcia); #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA #define DEFAULT_CFG {11,0x170,0,0} -int avm_a1_init_pcmcia(void *, int, int *, int); -EXPORT_SYMBOL(avm_a1_init_pcmcia); #endif #ifdef CONFIG_HISAX_FRITZPCI @@ -193,8 +185,6 @@ EXPORT_SYMBOL(avm_a1_init_pcmcia); #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER #define DEFAULT_CFG {11,0x270,0,0} -int sedl_init_pcmcia(void *, int, int *, int); -EXPORT_SYMBOL(sedl_init_pcmcia); #endif #ifdef CONFIG_HISAX_SPORTSTER @@ -237,8 +227,6 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_HFC_SX #define DEFAULT_CFG {5,0x2E0,0,0} -int hfc_init_pcmcia(void *, int, int *, int); -EXPORT_SYMBOL(hfc_init_pcmcia); #endif @@ -330,10 +318,6 @@ EXPORT_SYMBOL(hfc_init_pcmcia); #define DEFAULT_CFG {0,0,0,0} #endif -int hisax_init_pcmcia(void *, int *, struct IsdnCard *); -EXPORT_SYMBOL(hisax_init_pcmcia); -EXPORT_SYMBOL(HiSax_closecard); - #define FIRST_CARD { \ DEFAULT_CARD, \ DEFAULT_PROTO, \ @@ -346,14 +330,14 @@ struct IsdnCard cards[HISAX_MAX_CARDS] = }; #define HISAX_IDSIZE (HISAX_MAX_CARDS*8) -static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, }; +static char HiSaxID[HISAX_IDSIZE] = { 0, }; -char *HiSax_id __devinitdata = HiSaxID; +char *HiSax_id = HiSaxID; #ifdef MODULE /* Variables for insmod */ -static int type[HISAX_MAX_CARDS] __devinitdata = { 0, }; -static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, }; -static int io[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int type[HISAX_MAX_CARDS] = { 0, }; +static int protocol[HISAX_MAX_CARDS] = { 0, }; +static int io[HISAX_MAX_CARDS] = { 0, }; #undef IO0_IO1 #ifdef CONFIG_HISAX_16_3 #define IO0_IO1 @@ -368,7 +352,7 @@ static int io1[HISAX_MAX_CARDS] __devini #endif static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, }; static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, }; -static char *id __devinitdata = HiSaxID; +static char *id = HiSaxID; #define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i" @@ -430,7 +414,6 @@ void __init HiSaxVersion(void) strcpy(tmp, lli_revision); printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp)); - certification_check(1); } #ifndef MODULE @@ -490,36 +473,125 @@ static int __init HiSax_setup(char *line __setup("hisax=", HiSax_setup); #endif /* MODULES */ +#if CARD_TELES0 extern int setup_teles0(struct IsdnCard *card); +#endif + +#if CARD_TELES3 extern int setup_teles3(struct IsdnCard *card); +#endif + +#if CARD_S0BOX extern int setup_s0box(struct IsdnCard *card); +#endif + +#if CARD_TELESPCI extern int setup_telespci(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1 extern int setup_avm_a1(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1_PCMCIA extern int setup_avm_a1_pcmcia(struct IsdnCard *card); +#endif + +#if CARD_FRITZPCI extern int setup_avm_pcipnp(struct IsdnCard *card); +#endif + +#if CARD_ELSA extern int setup_elsa(struct IsdnCard *card); +#endif + +#if CARD_IX1MICROR2 extern int setup_ix1micro(struct IsdnCard *card); +#endif + +#if CARD_DIEHLDIVA extern int setup_diva(struct IsdnCard *card); +#endif + +#if CARD_ASUSCOM extern int setup_asuscom(struct IsdnCard *card); +#endif + +#if CARD_TELEINT extern int setup_TeleInt(struct IsdnCard *card); +#endif + +#if CARD_SEDLBAUER extern int setup_sedlbauer(struct IsdnCard *card); +#endif + +#if CARD_SPORTSTER extern int setup_sportster(struct IsdnCard *card); +#endif + +#if CARD_MIC extern int setup_mic(struct IsdnCard *card); +#endif + +#if CARD_NETJET_S extern int setup_netjet_s(struct IsdnCard *card); +#endif + +#if CARD_HFCS extern int setup_hfcs(struct IsdnCard *card); +#endif + +#if CARD_HFC_PCI extern int setup_hfcpci(struct IsdnCard *card); +#endif + +#if CARD_HFC_SX extern int setup_hfcsx(struct IsdnCard *card); +#endif + +#if CARD_AMD7930 extern int setup_amd7930(struct IsdnCard *card); +#endif + +#if CARD_NICCY extern int setup_niccy(struct IsdnCard *card); +#endif + +#if CARD_ISURF extern int setup_isurf(struct IsdnCard *card); +#endif + +#if CARD_HSTSAPHIR extern int setup_saphir(struct IsdnCard *card); +#endif + +#if CARD_TESTEMU extern int setup_testemu(struct IsdnCard *card); +#endif + +#if CARD_BKM_A4T extern int setup_bkm_a4t(struct IsdnCard *card); +#endif + +#if CARD_SCT_QUADRO extern int setup_sct_quadro(struct IsdnCard *card); +#endif + +#if CARD_GAZEL extern int setup_gazel(struct IsdnCard *card); +#endif + +#if CARD_W6692 extern int setup_w6692(struct IsdnCard *card); +#endif + +#if CARD_NETJET_U extern int setup_netjet_u(struct IsdnCard *card); +#endif + +#if CARD_FN_ENTERNOW_PCI extern int setup_enternow_pci(struct IsdnCard *card); +#endif /* * Find card with given driverId @@ -546,10 +618,10 @@ struct IsdnCardState *hisax_get_card(int return NULL; } -int HiSax_readstatus(u8 * buf, int len, int user, int id, int channel) +int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) { int count, cnt; - u8 *p = buf; + u_char *p = buf; struct IsdnCardState *cs = hisax_findcard(id); if (cs) { @@ -561,10 +633,9 @@ int HiSax_readstatus(u8 * buf, int len, count = cs->status_end - cs->status_read + 1; if (count >= len) count = len; - if (user) { - if (copy_to_user(p, cs->status_read, count)) - return -EFAULT; - } else + if (user) + copy_to_user(p, cs->status_read, count); + else memcpy(p, cs->status_read, count); cs->status_read += count; if (cs->status_read > cs->status_end) @@ -576,10 +647,9 @@ int HiSax_readstatus(u8 * buf, int len, cnt = HISAX_STATUS_BUFSIZE; else cnt = count; - if (user) { - if (copy_to_user(p, cs->status_read, cnt)) - return -EFAULT; - } else + if (user) + copy_to_user(p, cs->status_read, cnt); + else memcpy(p, cs->status_read, cnt); p += cnt; cs->status_read += cnt % HISAX_STATUS_BUFSIZE; @@ -614,20 +684,24 @@ int jiftime(char *s, long mark) return 8; } -static char tmpbuf[HISAX_STATUS_BUFSIZE]; +static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) { /* if head == NULL the fmt contains the full info */ - unsigned long flags; - int count, i; - char *p; - isdn_ctrl ic; - int len; + u_long flags; + int count, i; + u_char *p; + isdn_ctrl ic; + int len; - spin_lock_irqsave(&hisax_config_lock, flags); + if (!cs) { + printk(KERN_WARNING "HiSax: No CardStatus for message"); + return; + } + spin_lock_irqsave(&cs->statlock, flags); p = tmpbuf; if (head) { p += jiftime(p, jiffies); @@ -638,19 +712,13 @@ void VHiSax_putstatus(struct IsdnCardSta len = p - tmpbuf; p = tmpbuf; } else { - p = (char *) fmt; + p = fmt; len = strlen(fmt); } - if (!cs) { - printk(KERN_WARNING "HiSax: No CardStatus for message %s", - p); - spin_unlock_irqrestore(&hisax_config_lock, flags); - return; - } if (len > HISAX_STATUS_BUFSIZE) { + spin_unlock_irqrestore(&cs->statlock, flags); printk(KERN_WARNING "HiSax: status overflow %d/%d\n", len, HISAX_STATUS_BUFSIZE); - spin_unlock_irqrestore(&hisax_config_lock, flags); return; } count = len; @@ -679,7 +747,7 @@ void VHiSax_putstatus(struct IsdnCardSta count++; } #endif - spin_unlock_irqrestore(&hisax_config_lock, flags); + spin_unlock_irqrestore(&cs->statlock, flags); if (count) { ic.command = ISDN_STAT_STAVAIL; ic.driver = cs->myid; @@ -725,15 +793,22 @@ static void ll_unload(struct IsdnCardSta ic.command = ISDN_STAT_UNLOAD; ic.driver = cs->myid; cs->iif.statcallb(&ic); + if (cs->status_buf) + kfree(cs->status_buf); + cs->status_read = NULL; + cs->status_write = NULL; + cs->status_end = NULL; + kfree(cs->dlog); + cs->dlog = NULL; } static void closecard(int cardnr) { struct IsdnCardState *csta = cards[cardnr].cs; - if (csta->bc_l1_ops->close) { - csta->bc_l1_ops->close(csta->bcs + 1); - csta->bc_l1_ops->close(csta->bcs); + if (csta->bcs->BC_Close != NULL) { + csta->bcs->BC_Close(csta->bcs + 1); + csta->bcs->BC_Close(csta->bcs); } skb_queue_purge(&csta->rq); @@ -746,32 +821,34 @@ static void closecard(int cardnr) dev_kfree_skb(csta->tx_skb); csta->tx_skb = NULL; } - if (csta->dc_l1_ops->close) - csta->dc_l1_ops->close(csta); - - if (csta->card_ops->release) - csta->card_ops->release(csta); + if (csta->DC_Close != NULL) { + csta->DC_Close(csta); + } + if (csta->cardmsg) + csta->cardmsg(csta, CARD_RELEASE, NULL); if (csta->dbusytimer.function != NULL) // FIXME? del_timer(&csta->dbusytimer); ll_unload(csta); } -static int __devinit init_card(struct IsdnCardState *cs) +static int init_card(struct IsdnCardState *cs) { - int irq_cnt, cnt = 3; - - cs->card_ops->init(cs); + int irq_cnt, cnt = 3, ret; + if (!cs->irq) { + ret = cs->cardmsg(cs, CARD_INIT, NULL); + return(ret); + } irq_cnt = kstat_irqs(cs->irq); printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, irq_cnt); - if (request_irq(cs->irq, cs->card_ops->irq_func, cs->irq_flags, "HiSax", cs)) { + if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) { printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", cs->irq); return 1; } while (cnt) { - cs->card_ops->init(cs); + cs->cardmsg(cs, CARD_INIT, NULL); set_current_state(TASK_UNINTERRUPTIBLE); /* Timeout 10ms */ schedule_timeout((10 * HZ) / 1000); @@ -785,86 +862,74 @@ static int __devinit init_card(struct Is free_irq(cs->irq, cs); return 2; } else { - if (cs->card_ops->reset) - cs->card_ops->reset(cs); + cs->cardmsg(cs, CARD_RESET, NULL); cnt--; } } else { - if (cs->card_ops->test) - cs->card_ops->test(cs); + cs->cardmsg(cs, CARD_TEST, NULL); return 0; } } return 3; } -static struct IsdnCardState * -alloc_IsdnCardState(void) +static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner) { + int ret = 0; + struct IsdnCard *card = cards + cardnr; struct IsdnCardState *cs; - cs = kmalloc(sizeof(*cs), GFP_ATOMIC); // FIXME - if (!cs) - goto err; - - memset(cs, 0, sizeof(*cs)); - - cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC); - if (!cs->dlog) - goto err_cs; - - cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC); - if (!cs->status_buf) - goto err_dlog; - - cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC); - if (!cs->rcvbuf) - goto err_status_buf; - + cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC); + if (!cs) { + printk(KERN_WARNING + "HiSax: No memory for IsdnCardState(card %d)\n", + cardnr + 1); + goto out; + } + memset(cs, 0, sizeof(struct IsdnCardState)); + card->cs = cs; + spin_lock_init(&cs->statlock); + spin_lock_init(&cs->lock); cs->chanlimit = 2; /* maximum B-channel number */ + cs->logecho = 0; /* No echo logging */ + cs->cardnr = cardnr; cs->debug = L1_DEB_WARN; + cs->HW_Flags = 0; + cs->busy_flag = busy_flag; cs->irq_flags = I4L_IRQ_FLAG; +#if TEI_PER_CARD + if (card->protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#else + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#endif + cs->protocol = card->protocol; + + if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { + printk(KERN_WARNING + "HiSax: Card Type %d out of range\n", card->typ); + goto outf_cs; + } + if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for dlog(card %d)\n", cardnr + 1); + goto outf_cs; + } + if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + goto outf_dlog; + } cs->stlist = NULL; cs->status_read = cs->status_buf; cs->status_write = cs->status_buf; cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; - cs->rcvidx = 0; - cs->tx_skb = NULL; - cs->tx_cnt = 0; - cs->event = 0; - - skb_queue_head_init(&cs->rq); - skb_queue_head_init(&cs->sq); - - spin_lock_init(&cs->lock); - resources_init(&cs->rs); - return cs; - - err_status_buf: - kfree(cs->status_buf); - err_dlog: - kfree(cs->dlog); - err_cs: - kfree(cs); - err: - return NULL; -} - -static void -free_IsdnCardState(struct IsdnCardState *cs) -{ - kfree(cs->rcvbuf); - kfree(cs->status_buf); - kfree(cs->dlog); - kfree(cs); -} - -static void -do_register_isdn(struct IsdnCardState *cs) -{ - if (!cs->iif.owner) - cs->iif.owner = THIS_MODULE; - + cs->typ = card->typ; +#ifdef MODULE + cs->iif.owner = lockowner; +#endif + strcpy(cs->iif.id, id); cs->iif.channels = 2; cs->iif.maxbufsize = MAX_DATA_SIZE; cs->iif.hl_hdrlen = MAX_HEADER_LEN; @@ -892,72 +957,20 @@ do_register_isdn(struct IsdnCardState *c register_isdn(&cs->iif); cs->myid = cs->iif.channels; printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cs->cardnr + 1, - (cs->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (cs->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (cs->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (cs->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, + (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : "NONE", cs->iif.id, cs->myid); -} - -static int -do_init(struct IsdnCardState *cs) -{ - int ret; - - init_tei(cs, cs->protocol); - ret = CallcNewChan(cs); - if (ret) - return -EIO; - - /* ISAR needs firmware download first */ - if (!test_bit(HW_ISAR, &cs->HW_Flags)) - ll_run(cs, 0); - - return 0; -} - - -static int __devinit checkcard(int cardnr, char *id, int *busy_flag) -{ - int ret = 0; - struct IsdnCard *card = cards + cardnr; - struct IsdnCardState *cs; - - cs = alloc_IsdnCardState(); - if (!cs) { - printk(KERN_WARNING - "HiSax: No memory for IsdnCardState(card %d)\n", - cardnr + 1); - goto out; - } - card->cs = cs; -#if TEI_PER_CARD - if (card->protocol == ISDN_PTYPE_NI1) - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#else - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#endif - cs->cardnr = cardnr; - cs->protocol = card->protocol; - cs->typ = card->typ; - cs->busy_flag = busy_flag; - - if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { - printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", card->typ); - goto outf_cs; - } - strcpy(cs->iif.id, id); - do_register_isdn(cs); switch (card->typ) { -#ifdef CONFIG_HISAX_16_0 +#if CARD_TELES0 case ISDN_CTYPE_16_0: case ISDN_CTYPE_8_0: ret = setup_teles0(card); break; #endif -#ifdef CONFIG_HISAX_16_3 +#if CARD_TELES3 case ISDN_CTYPE_16_3: case ISDN_CTYPE_PNP: case ISDN_CTYPE_TELESPCMCIA: @@ -965,32 +978,32 @@ static int __devinit checkcard(int cardn ret = setup_teles3(card); break; #endif -#ifdef CONFIG_HISAX_S0BOX +#if CARD_S0BOX case ISDN_CTYPE_S0BOX: ret = setup_s0box(card); break; #endif -#ifdef CONFIG_HISAX_TELESPCI +#if CARD_TELESPCI case ISDN_CTYPE_TELESPCI: ret = setup_telespci(card); break; #endif -#ifdef CONFIG_HISAX_AVM_A1 +#if CARD_AVM_A1 case ISDN_CTYPE_A1: ret = setup_avm_a1(card); break; #endif -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#if CARD_AVM_A1_PCMCIA case ISDN_CTYPE_A1_PCMCIA: ret = setup_avm_a1_pcmcia(card); break; #endif -#ifdef CONFIG_HISAX_FRITZPCI +#if CARD_FRITZPCI case ISDN_CTYPE_FRITZPCI: ret = setup_avm_pcipnp(card); break; #endif -#ifdef CONFIG_HISAX_ELSA +#if CARD_ELSA case ISDN_CTYPE_ELSA: case ISDN_CTYPE_ELSA_PNP: case ISDN_CTYPE_ELSA_PCMCIA: @@ -998,115 +1011,115 @@ static int __devinit checkcard(int cardn ret = setup_elsa(card); break; #endif -#ifdef CONFIG_HISAX_IX1MICROR2 +#if CARD_IX1MICROR2 case ISDN_CTYPE_IX1MICROR2: ret = setup_ix1micro(card); break; #endif -#ifdef CONFIG_HISAX_DIEHLDIVA +#if CARD_DIEHLDIVA case ISDN_CTYPE_DIEHLDIVA: ret = setup_diva(card); break; #endif -#ifdef CONFIG_HISAX_ASUSCOM +#if CARD_ASUSCOM case ISDN_CTYPE_ASUSCOM: ret = setup_asuscom(card); break; #endif -#ifdef CONFIG_HISAX_TELEINT +#if CARD_TELEINT case ISDN_CTYPE_TELEINT: ret = setup_TeleInt(card); break; #endif -#ifdef CONFIG_HISAX_SEDLBAUER +#if CARD_SEDLBAUER case ISDN_CTYPE_SEDLBAUER: case ISDN_CTYPE_SEDLBAUER_PCMCIA: case ISDN_CTYPE_SEDLBAUER_FAX: ret = setup_sedlbauer(card); break; #endif -#ifdef CONFIG_HISAX_SPORTSTER +#if CARD_SPORTSTER case ISDN_CTYPE_SPORTSTER: ret = setup_sportster(card); break; #endif -#ifdef CONFIG_HISAX_MIC +#if CARD_MIC case ISDN_CTYPE_MIC: ret = setup_mic(card); break; #endif -#ifdef CONFIG_HISAX_NETJET +#if CARD_NETJET_S case ISDN_CTYPE_NETJET_S: ret = setup_netjet_s(card); break; #endif -#ifdef CONFIG_HISAX_HFCS +#if CARD_HFCS case ISDN_CTYPE_TELES3C: case ISDN_CTYPE_ACERP10: ret = setup_hfcs(card); break; #endif -#ifdef CONFIG_HISAX_HFC_PCI +#if CARD_HFC_PCI case ISDN_CTYPE_HFC_PCI: ret = setup_hfcpci(card); break; #endif -#ifdef CONFIG_HISAX_HFC_SX +#if CARD_HFC_SX case ISDN_CTYPE_HFC_SX: ret = setup_hfcsx(card); break; #endif -#ifdef CONFIG_HISAX_NICCY +#if CARD_NICCY case ISDN_CTYPE_NICCY: ret = setup_niccy(card); break; #endif -#ifdef CONFIG_HISAX_AMD7930 +#if CARD_AMD7930 case ISDN_CTYPE_AMD7930: ret = setup_amd7930(card); break; #endif -#ifdef CONFIG_HISAX_ISURF +#if CARD_ISURF case ISDN_CTYPE_ISURF: ret = setup_isurf(card); break; #endif -#ifdef CONFIG_HISAX_HSTSAPHIR +#if CARD_HSTSAPHIR case ISDN_CTYPE_HSTSAPHIR: ret = setup_saphir(card); break; #endif -#ifdef CONFIG_HISAX_TESTEMU +#if CARD_TESTEMU case ISDN_CTYPE_TESTEMU: ret = setup_testemu(card); break; #endif -#ifdef CONFIG_HISAX_BKM_A4T +#if CARD_BKM_A4T case ISDN_CTYPE_BKM_A4T: ret = setup_bkm_a4t(card); break; #endif -#ifdef CONFIG_HISAX_SCT_QUADRO +#if CARD_SCT_QUADRO case ISDN_CTYPE_SCT_QUADRO: ret = setup_sct_quadro(card); break; #endif -#ifdef CONFIG_HISAX_GAZEL +#if CARD_GAZEL case ISDN_CTYPE_GAZEL: ret = setup_gazel(card); break; #endif -#ifdef CONFIG_HISAX_W6692 +#if CARD_W6692 case ISDN_CTYPE_W6692: ret = setup_w6692(card); break; #endif -#ifdef CONFIG_HISAX_NETJET_U +#if CARD_NETJET_U case ISDN_CTYPE_NETJET_U: ret = setup_netjet_u(card); break; #endif -#ifdef CONFIG_HISAX_ENTERNOW_PCI +#if CARD_FN_ENTERNOW_PCI case ISDN_CTYPE_ENTERNOW: ret = setup_enternow_pci(card); break; @@ -1125,40 +1138,62 @@ static int __devinit checkcard(int cardn ll_unload(cs); goto outf_cs; } + if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { + printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n"); + ll_unload(cs); + goto outf_cs; + } + cs->rcvidx = 0; + cs->tx_skb = NULL; + cs->tx_cnt = 0; + cs->event = 0; + cs->tqueue.data = cs; + + skb_queue_head_init(&cs->rq); + skb_queue_head_init(&cs->sq); + init_bcstate(cs, 0); init_bcstate(cs, 1); /* init_card only handles interrupts which are not */ /* used here for the loadable driver */ switch (card->typ) { - case ISDN_CTYPE_DYNAMIC: - ret = 0; - break; - default: - ret = init_card(cs); - break; + case ISDN_CTYPE_DYNAMIC: + ret = 0; + break; + default: + ret = init_card(cs); + break; } if (ret) { closecard(cardnr); ret = 0; goto outf_cs; } - if (do_init(cs)) { + init_tei(cs, cs->protocol); + ret = CallcNewChan(cs); + if (ret) { closecard(cardnr); ret = 0; goto outf_cs; } + /* ISAR needs firmware download first */ + if (!test_bit(HW_ISAR, &cs->HW_Flags)) + ll_run(cs, 0); + ret = 1; goto out; + outf_dlog: + kfree(cs->dlog); outf_cs: - free_IsdnCardState(cs); + kfree(cs); card->cs = NULL; out: return ret; } -void __devinit HiSax_shiftcards(int idx) +void HiSax_shiftcards(int idx) { int i; @@ -1166,7 +1201,7 @@ void __devinit HiSax_shiftcards(int idx) memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); } -int __devinit HiSax_inithardware(int *busy_flag) +int HiSax_inithardware(int *busy_flag) { int foundcards = 0; int i = 0; @@ -1196,13 +1231,16 @@ int __devinit HiSax_inithardware(int *bu else sprintf(ids, "%s%d", id, i); } - if (checkcard(i, ids, busy_flag)) { + if (checkcard(i, ids, busy_flag, THIS_MODULE)) { foundcards++; i++; } else { - printk(KERN_WARNING - "HiSax: Card type %d not installed !\n", - cards[i].typ); + /* make sure we don't oops the module */ + if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) { + printk(KERN_WARNING + "HiSax: Card %s not installed !\n", + CardType[cards[i].typ]); + } HiSax_shiftcards(i); nrcards--; } @@ -1214,7 +1252,7 @@ void HiSax_closecard(int cardnr) { int i, last = nrcards - 1; - if (cardnr > last) + if (cardnr > last || cardnr < 0) return; if (cards[cardnr].cs) { ll_stop(cards[cardnr].cs); @@ -1492,182 +1530,9 @@ static void __exit HiSax_exit(void) printk(KERN_INFO "HiSax module removed\n"); } -#ifdef CONFIG_HISAX_ELSA -int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) -{ -#ifdef MODULE - int i; - - nrcards = 0; - /* Initialize all structs, even though we only accept - two pcmcia cards - */ - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].typ = type[i]; - if (protocol[i]) { - cards[i].protocol = protocol[i]; - } else { - cards[i].protocol = DEFAULT_PROTO; - } - } - cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int) pcm_iob; - cards[0].protocol = prot; - cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA; - - if (!HiSax_id) - HiSax_id = HiSaxID; - if (!HiSaxID[0]) - strcpy(HiSaxID, "HiSax"); - for (i = 0; i < HISAX_MAX_CARDS; i++) - if (cards[i].typ > 0) - nrcards++; - printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - - if (!HiSax_inithardware(busy_flag)) - return -ENODEV; - printk(KERN_NOTICE "HiSax: module installed\n"); -#endif - return 0; -} -#endif - -#ifdef CONFIG_HISAX_HFC_SX -int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) -{ -#ifdef MODULE - int i; - - nrcards = 0; - /* Initialize all structs, even though we only accept - two pcmcia cards - */ - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].typ = type[i]; - if (protocol[i]) { - cards[i].protocol = protocol[i]; - } else { - cards[i].protocol = DEFAULT_PROTO; - } - } - cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int) pcm_iob; - cards[0].protocol = prot; - cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA; - - if (!HiSax_id) - HiSax_id = HiSaxID; - if (!HiSaxID[0]) - strcpy(HiSaxID, "HiSax"); - for (i = 0; i < HISAX_MAX_CARDS; i++) - if (cards[i].typ > 0) - nrcards++; - printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - - if (!HiSax_inithardware(busy_flag)) - return -ENODEV; - printk(KERN_NOTICE "HiSax: module installed\n"); -#endif - return 0; -} -#endif - -#ifdef CONFIG_HISAX_SEDLBAUER -int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) +int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) { -#ifdef MODULE - int i; - - nrcards = 0; - /* Initialize all structs, even though we only accept - two pcmcia cards - */ - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].typ = type[i]; - if (protocol[i]) { - cards[i].protocol = protocol[i]; - } else { - cards[i].protocol = DEFAULT_PROTO; - } - } - cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int) pcm_iob; - cards[0].protocol = prot; - cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; - - if (!HiSax_id) - HiSax_id = HiSaxID; - if (!HiSaxID[0]) - strcpy(HiSaxID, "HiSax"); - for (i = 0; i < HISAX_MAX_CARDS; i++) - if (cards[i].typ > 0) - nrcards++; - printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - - if (!HiSax_inithardware(busy_flag)) - return -ENODEV; - printk(KERN_NOTICE "HiSax: module installed\n"); -#endif - return 0; -} -#endif - -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA -int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) -{ -#ifdef MODULE - int i; - - nrcards = 0; - /* Initialize all structs, even though we only accept - two pcmcia cards - */ - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].typ = type[i]; - if (protocol[i]) { - cards[i].protocol = protocol[i]; - } else { - cards[i].protocol = DEFAULT_PROTO; - } - } - cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int) pcm_iob; - cards[0].protocol = prot; - cards[0].typ = ISDN_CTYPE_A1_PCMCIA; - - if (!HiSax_id) - HiSax_id = HiSaxID; - if (!HiSaxID[0]) - strcpy(HiSaxID, "HiSax"); - for (i = 0; i < HISAX_MAX_CARDS; i++) - if (cards[i].typ > 0) - nrcards++; - printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - - if (!HiSax_inithardware(busy_flag)) - return -ENODEV; - printk(KERN_NOTICE "HiSax: module installed\n"); -#endif - return 0; -} -#endif - -int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, - struct IsdnCard *card) -{ - u8 ids[16]; + u_char ids[16]; int ret = -1; cards[nrcards] = *card; @@ -1675,14 +1540,18 @@ int __devinit hisax_init_pcmcia(void *pc sprintf(ids, "HiSax%d", nrcards); else sprintf(ids, "HiSax"); - if (!checkcard(nrcards, ids, busy_flag)) { - return -1; - } + if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE)) + goto error; + ret = nrcards; nrcards++; +error: return ret; } +EXPORT_SYMBOL(hisax_init_pcmcia); +EXPORT_SYMBOL(HiSax_closecard); + #include "hisax_if.h" EXPORT_SYMBOL(hisax_register); @@ -1692,68 +1561,47 @@ static void hisax_d_l1l2(struct hisax_if static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg); static void hisax_d_l2l1(struct PStack *st, int pr, void *arg); static void hisax_b_l2l1(struct PStack *st, int pr, void *arg); +static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg); static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs); static void hisax_bc_close(struct BCState *bcs); -static void hisax_bh(void *data); +static void hisax_bh(struct IsdnCardState *cs); static void EChannel_proc_rcv(struct hisax_d_if *d_if); -static int -hisax_l1_open(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l2l1 = hisax_d_l2l1; - return 0; -} - -static struct dc_l1_ops hisax_l1_ops = { - .open = hisax_l1_open, - .bh_func = hisax_bh, -}; - -static struct bc_l1_ops hisax_bc_l1_ops = { - .open = hisax_bc_setstack, - .close = hisax_bc_close, -}; - int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], char *name, int protocol) { - int i; + int i, retval; + char id[20]; struct IsdnCardState *cs; - + for (i = 0; i < HISAX_MAX_CARDS; i++) { if (!cards[i].typ) break; } - + if (i >= HISAX_MAX_CARDS) return -EBUSY; - - nrcards++; - - cs = alloc_IsdnCardState(); - if (!cs) - return -ENOMEM; - -#if TEI_PER_CARD - if (protocol == ISDN_PTYPE_NI1) - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#else - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#endif - cs->cardnr = i; - cs->protocol = protocol; - cs->typ = ISDN_CTYPE_DYNAMIC; - - sprintf(cs->iif.id, "%s%d", name, i); - do_register_isdn(cs); + cards[i].typ = ISDN_CTYPE_DYNAMIC; + cards[i].protocol = protocol; + sprintf(id, "%s%d", name, i); + nrcards++; + retval = checkcard(i, id, 0, hisax_d_if->owner); + if (retval == 0) { // yuck + cards[i].typ = 0; + nrcards--; + return retval; + } + cs = cards[i].cs; hisax_d_if->cs = cs; cs->hw.hisax_d_if = hisax_d_if; - cs->iif.owner = hisax_d_if->owner; - dc_l1_init(cs, &hisax_l1_ops); - cs->bc_l1_ops = &hisax_bc_l1_ops; - + cs->cardmsg = hisax_cardmsg; + INIT_WORK(&cs->tqueue, (void *)(void *)hisax_bh, cs); + cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1; for (i = 0; i < 2; i++) { + cs->bcs[i].BC_SetStack = hisax_bc_setstack; + cs->bcs[i].BC_Close = hisax_bc_close; + b_if[i]->ifc.l1l2 = hisax_b_l1l2; hisax_d_if->b_if[i] = b_if[i]; @@ -1762,8 +1610,6 @@ int hisax_register(struct hisax_d_if *hi skb_queue_head_init(&hisax_d_if->erq); clear_bit(0, &hisax_d_if->ph_state); - do_init(cs); - return 0; } @@ -1776,9 +1622,14 @@ void hisax_unregister(struct hisax_d_if #include "isdnl1.h" -static void hisax_bh(void *data) +static void hisax_sched_event(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + schedule_work(&cs->tqueue); +} + +static void hisax_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; struct PStack *st; int pr; @@ -1792,11 +1643,17 @@ static void hisax_bh(void *data) else pr = PH_DEACTIVATE | INDICATION; for (st = cs->stlist; st; st = st->next) - L1L2(st, pr, NULL); + st->l1.l1l2(st, pr, NULL); } } +static void hisax_b_sched_event(struct BCState *bcs, int event) +{ + test_and_set_bit(event, &bcs->event); + schedule_work(&bcs->tqueue); +} + static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg) { struct hisax_if *ifc = (struct hisax_if *) d_if; @@ -1819,15 +1676,15 @@ static void hisax_d_l1l2(struct hisax_if switch (pr) { case PH_ACTIVATE | INDICATION: set_bit(0, &d_if->ph_state); - sched_d_event(cs, D_L1STATECHANGE); + hisax_sched_event(cs, D_L1STATECHANGE); break; case PH_DEACTIVATE | INDICATION: clear_bit(0, &d_if->ph_state); - sched_d_event(cs, D_L1STATECHANGE); + hisax_sched_event(cs, D_L1STATECHANGE); break; case PH_DATA | INDICATION: skb_queue_tail(&cs->rq, arg); - sched_d_event(cs, D_RCVBUFREADY); + hisax_sched_event(cs, D_RCVBUFREADY); break; case PH_DATA | CONFIRM: skb = skb_dequeue(&cs->sq); @@ -1838,14 +1695,14 @@ static void hisax_d_l1l2(struct hisax_if clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); for (st = cs->stlist; st; st = st->next) { if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) { - L1L2(st, PH_PULL | CONFIRM, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); break; } } break; case PH_DATA_E | INDICATION: skb_queue_tail(&d_if->erq, arg); - sched_d_event(cs, E_RCVBUFREADY); + hisax_sched_event(cs, E_RCVBUFREADY); break; default: printk("pr %#x\n", pr); @@ -1863,22 +1720,22 @@ static void hisax_b_l1l2(struct hisax_if // FIXME use isdnl1? switch (pr) { case PH_ACTIVATE | INDICATION: - L1L2(st, pr, NULL); + st->l1.l1l2(st, pr, NULL); break; case PH_DEACTIVATE | INDICATION: - L1L2(st, pr, NULL); + st->l1.l1l2(st, pr, NULL); clear_bit(BC_FLG_BUSY, &bcs->Flag); skb_queue_purge(&bcs->squeue); bcs->hw.b_if = NULL; break; case PH_DATA | INDICATION: skb_queue_tail(&bcs->rqueue, arg); - sched_b_event(bcs, B_RCVBUFREADY); + hisax_b_sched_event(bcs, B_RCVBUFREADY); break; case PH_DATA | CONFIRM: - skb = arg; - bcs->tx_cnt -= skb->truesize; - xmit_complete_b(bcs); + bcs->tx_cnt -= (int) arg; + if (bcs->st->lli.l1writewakeup) + bcs->st->lli.l1writewakeup(bcs->st, (int) arg); skb = skb_dequeue(&bcs->squeue); if (skb) { B_L2L1(b_if, PH_DATA | REQUEST, skb); @@ -1886,7 +1743,7 @@ static void hisax_b_l1l2(struct hisax_if } clear_bit(BC_FLG_BUSY, &bcs->Flag); if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) { - L1L2(st, PH_PULL | CONFIRM, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } break; default: @@ -1917,7 +1774,7 @@ static void hisax_d_l2l1(struct PStack * break; case PH_PULL | REQUEST: if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - L1L2(st, PH_PULL | CONFIRM, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); else set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; @@ -1927,6 +1784,11 @@ static void hisax_d_l2l1(struct PStack * } } +static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg) +{ + return 0; +} + static void hisax_b_l2l1(struct PStack *st, int pr, void *arg) { struct BCState *bcs = st->l1.bcs; @@ -1947,7 +1809,7 @@ static void hisax_b_l2l1(struct PStack * break; case PH_PULL | REQUEST: if (!test_bit(BC_FLG_BUSY, &bcs->Flag)) - L1L2(st, PH_PULL | CONFIRM, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); else set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; @@ -1971,7 +1833,7 @@ static int hisax_bc_setstack(struct PSta hisax_d_if->b_if[st->l1.bc]->bcs = bcs; st->l1.bcs = bcs; - st->l1.l2l1 = hisax_b_l2l1; + st->l2.l2l1 = hisax_b_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -1991,7 +1853,7 @@ static void hisax_bc_close(struct BCStat static void EChannel_proc_rcv(struct hisax_d_if *d_if) { struct IsdnCardState *cs = d_if->cs; - u8 *ptr; + u_char *ptr; struct sk_buff *skb; while ((skb = skb_dequeue(&d_if->erq)) != NULL) { @@ -2017,103 +1879,9 @@ static void EChannel_proc_rcv(struct his } } -void -resources_init(struct resources *rs) -{ - INIT_LIST_HEAD(&rs->res_head); -} - -void -resources_release(struct resources *rs) -{ - struct res *r; - - list_for_each_entry(r, &rs->res_head, node) { - if (r->flags & IORESOURCE_IO) { - release_region(r->start, r->end - r->start + 1); - } - if (r->flags & IORESOURCE_MEM) { - iounmap(r->r_u.ioremap_addr); - release_mem_region(r->start, r->end - r->start + 1); - } - } -} - -unsigned long -request_io(struct resources *rs, unsigned long start, int len, - const char *name) -{ - struct res *r; - - r = kmalloc(sizeof(*r), GFP_KERNEL); - if (!r) { - printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); - goto err; - } - if (!request_region(start, len, name)) { - printk(KERN_WARNING "%s: IO %#lx-%#lx already in use\n", - __FUNCTION__, start, start + len - 1); - goto err_free; - } - r->flags = IORESOURCE_IO; - r->start = start; - r->end = start + len - 1; - r->name = name; - list_add_tail(&r->node, &rs->res_head); - - return r->start; - - err_free: - kfree(r); - err: - return 0; -} - -void * -request_mmio(struct resources *rs, unsigned long start, int len, - const char *name) -{ - struct res *r; - - r = kmalloc(sizeof(*r), GFP_KERNEL); - if (!r) { - printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); - goto err; - } - if (!request_mem_region(start, len, name)) { - printk(KERN_WARNING "%s: MMIO %#lx-%#lx already in use\n", - __FUNCTION__, start, start + len - 1); - goto err_free; - } - r->flags = IORESOURCE_MEM; - r->start = start; - r->end = start + len - 1; - r->name = name; - r->r_u.ioremap_addr = ioremap(start, len); - if (!r->r_u.ioremap_addr) - goto err_release; - - list_add_tail(&r->node, &rs->res_head); - - return r->r_u.ioremap_addr; - - err_release: - release_mem_region(r->start, r->end - r->start + 1); - err_free: - kfree(r); - err: - return 0; -} - -void -hisax_release_resources(struct IsdnCardState *cs) -{ - resources_release(&cs->rs); -} - #include -static struct pci_device_id hisax_pci_tbl[] = { +static struct pci_device_id hisax_pci_tbl[] __initdata = { #ifdef CONFIG_HISAX_FRITZPCI {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID}, #endif @@ -2121,7 +1889,9 @@ static struct pci_device_id hisax_pci_tb {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, PCI_ANY_ID, PCI_ANY_ID}, +//######################################################################################### {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, PCI_ANY_ID, PCI_ANY_ID}, +//######################################################################################### #endif #ifdef CONFIG_HISAX_ELSA {PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, PCI_ANY_ID, PCI_ANY_ID}, diff -puN drivers/isdn/hisax/diva.c~i4l drivers/isdn/hisax/diva.c --- 25/drivers/isdn/hisax/diva.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/diva.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.25.6.5 2001/09/23 22:24:47 kai Exp $ +/* $Id: diva.c,v 1.33.2.5 2004/01/14 00:49:43 keil Exp $ * * low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -28,8 +28,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.25.6.5 $"; -static spinlock_t diva_lock = SPIN_LOCK_UNLOCKED; +const char *Diva_revision = "$Revision: 1.33.2.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -82,376 +81,710 @@ static spinlock_t diva_lock = SPIN_LOCK_ #endif #define PITA_INT0_STATUS 0x02 -static inline u8 -readreg(unsigned int ale, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&diva_lock, flags); byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&diva_lock, flags); - return ret; + return (ret); } static inline void -writereg(unsigned int ale, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&diva_lock, flags); byteout(ale, off); - byteout(adr, data); - spin_unlock_irqrestore(&diva_lock, flags); + insb(adr, data, size); } + static inline void -readfifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { byteout(ale, off); - insb(adr, data, size); + byteout(adr, data); } static inline void -writefifo(unsigned int ale, unsigned int adr, u8 off, u8 *data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) { byteout(ale, off); outsb(adr, data, size); } -static inline u8 -memreadreg(unsigned long adr, u8 off) +static inline u_char +memreadreg(unsigned long adr, u_char off) { - return readb(((unsigned int *)adr) + off); + return(*((unsigned char *) + (((unsigned int *)adr) + off))); } static inline void -memwritereg(unsigned long adr, u8 off, u8 data) +memwritereg(unsigned long adr, u_char off, u_char data) { - writeb(data, ((unsigned int *)adr) + off); + register u_char *p; + + p = (unsigned char *)(((unsigned int *)adr) + off); + *p = data; } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset); + return(readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) { readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) { writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, - offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, - offset + (hscx ? 0x40 : 0), value); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value); } static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, hscx ? 0x40 : 0, data, size); + readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, hscx ? 0x40 : 0, data, size); + writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static inline u8 -ipac_read(struct IsdnCardState *cs, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset); + return(readreg(cs->hw.diva.hscx_adr, + cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0))); } -static inline void -ipac_write(struct IsdnCardState *cs, u8 offset, u8 value) +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value); + writereg(cs->hw.diva.hscx_adr, + cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value); } -static inline void -ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static u_char +MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) { - readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, data, size); + return (memreadreg(cs->hw.diva.cfg_reg, offset+0x80)); } -static inline void -ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static void +MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, data, size); + memwritereg(cs->hw.diva.cfg_reg, offset|0x80, value); } -/* This will generate ipac_dc_ops and ipac_bc_ops using the functions - * above */ - -BUILD_IPAC_OPS(ipac); - -static inline u8 -mem_ipac_read(struct IsdnCardState *cs, u8 offset) +static void +MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - return memreadreg(cs->hw.diva.cfg_reg, offset); + while(size--) + *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80); } -static inline void -mem_ipac_write(struct IsdnCardState *cs, u8 offset, u8 value) +static void +MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - memwritereg(cs->hw.diva.cfg_reg, offset, value); + while(size--) + memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++); } -static inline void -mem_ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static u_char +MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - while(size--) - *data++ = memreadreg(cs->hw.diva.cfg_reg, offset); + return(memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0))); } -static inline void -mem_ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static void +MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - while(size--) - memwritereg(cs->hw.diva.cfg_reg, offset, *data++); + memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value); } -/* This will generate mem_ipac_dc_ops and mem_ipac_bc_ops using the functions - * above */ - -BUILD_IPAC_OPS(mem_ipac); - /* IO-Functions for IPACX type cards */ -static u8 -ipacx_dc_read(struct IsdnCardState *cs, u8 offset) +static u_char +MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset) { - return memreadreg(cs->hw.diva.cfg_reg, offset); + return (memreadreg(cs->hw.diva.cfg_reg, offset)); } static void -ipacx_dc_write(struct IsdnCardState *cs, u8 offset, u8 value) +MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value) { memwritereg(cs->hw.diva.cfg_reg, offset, value); } static void -ipacx_dc_read_fifo(struct IsdnCardState *cs, u8 *data, int size) +MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size) { while(size--) *data++ = memreadreg(cs->hw.diva.cfg_reg, 0); } static void -ipacx_dc_write_fifo(struct IsdnCardState *cs, u8 *data, int size) +MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size) { while(size--) memwritereg(cs->hw.diva.cfg_reg, 0, *data++); } -static struct dc_hw_ops ipacx_dc_ops = { - .read_reg = ipacx_dc_read, - .write_reg = ipacx_dc_write, - .read_fifo = ipacx_dc_read_fifo, - .write_fifo = ipacx_dc_write_fifo, -}; - -static u8 -ipacx_bc_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset) { - return memreadreg(cs->hw.diva.cfg_reg, offset + - (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)); + return(memreadreg(cs->hw.diva.cfg_reg, offset + + (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1))); } static void -ipacx_bc_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value); } -static void -ipacx_bc_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int len) -{ - int i; +/* + * fast interrupt HSCX stuff goes here + */ - for (i = 0; i < len ; i++) - *data++ = ipacx_bc_read(cs, hscx, IPACX_RFIFOB); -} +#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \ + cs->hw.diva.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \ + cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data) -static struct bc_hw_ops ipacx_bc_ops = { - .read_reg = ipacx_bc_read, - .write_reg = ipacx_bc_write, - .read_fifo = ipacx_bc_read_fifo, -}; +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \ + cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \ + cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" static irqreturn_t diva_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 sval; + u_char val, sval; + u_long flags; int cnt=5; + spin_lock_irqsave(&cs->lock, flags); while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) { - hscxisac_irq(intno, dev_id, regs); + val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40); + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA); + if (val) + isac_interrupt(cs, val); + cnt--; } if (!cnt) printk(KERN_WARNING "Diva: IRQ LOOP\n"); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } static irqreturn_t -diva_ipac_pci_irq(int intno, void *dev_id, struct pt_regs *regs) +diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; + u_char ista,val; + u_long flags; + int icnt=5; + + spin_lock_irqsave(&cs->lock, flags); + ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); +Start_IPACISA: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPACISA; + } + if (!icnt) + printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n"); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} - val = readb(cs->hw.diva.pci_cfg); - if (!(val & PITA_INT0_STATUS)) - return IRQ_NONE; /* other shared IRQ */ - writeb(PITA_INT0_STATUS, cs->hw.diva.pci_cfg); /* Reset pending INT0 */ +static inline void +MemwaitforCEC(struct IsdnCardState *cs, int hscx) +{ + int to = 50; - return ipac_irq(intno, dev_id, regs); + while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); } -static irqreturn_t -diva_ipacx_pci_irq(int intno, void *dev_id, struct pt_regs *regs) + +static inline void +MemwaitforXFW(struct IsdnCardState *cs, int hscx) { - struct IsdnCardState *cs = dev_id; - u8 val; + int to = 50; - val = readb(cs->hw.diva.pci_cfg); - if (!(val &PITA_INT0_STATUS)) - return IRQ_NONE; // other shared IRQ - interrupt_ipacx(cs); // handler for chip - writeb(PITA_INT0_STATUS, cs->hw.diva.pci_cfg); // Reset PLX interrupt - return IRQ_HANDLED; + while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); } -static void -diva_release(struct IsdnCardState *cs) +static inline void +MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) { - del_timer_sync(&cs->hw.diva.tl); - if (cs->hw.diva.cfg_reg) - byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ + MemwaitforCEC(cs, hscx); + MemWriteHSCX(cs, hscx, HSCX_CMDR, data); +} - hisax_release_resources(cs); +static void +Memhscx_empty_fifo(struct BCState *bcs, int count) +{ + u_char *ptr; + struct IsdnCardState *cs = bcs->cs; + int cnt; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hscx_empty_fifo"); + + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hscx_empty_fifo: incoming packet too large"); + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); + bcs->hw.hscx.rcvidx = 0; + return; + } + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + cnt = count; + while (cnt--) + *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0); + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static void -diva_ipac_pci_release(struct IsdnCardState *cs) +Memhscx_fill_fifo(struct BCState *bcs) { - writel(0, cs->hw.diva.pci_cfg); /* disable INT0/1 */ - writel(2, cs->hw.diva.pci_cfg); /* reset pending INT0 */ - hisax_release_resources(cs); + struct IsdnCardState *cs = bcs->cs; + int more, count, cnt; + int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; + u_char *ptr,*p; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hscx_fill_fifo"); + + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > fifo_size) { + more = !0; + count = fifo_size; + } else + count = bcs->tx_skb->len; + cnt = count; + MemwaitforXFW(cs, bcs->hw.hscx.hscx); + p = ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + while(cnt--) + memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0, + *p++); + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } -static int -diva_ipac_isa_reset(struct IsdnCardState *cs) +static inline void +Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) { - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); - return 0; + u_char r; + struct BCState *bcs = cs->bcs + hscx; + struct sk_buff *skb; + int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; + int count; + + if (!test_bit(BC_FLG_INIT, &bcs->Flag)) + return; + + if (val & 0x80) { /* RME */ + r = MemReadHSCX(cs, hscx, HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!(r & 0x80)) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX invalid frame"); + if ((r & 0x40) && bcs->mode) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX RDO mode=%d", + bcs->mode); + if (!(r & 0x20)) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX CRC error"); + MemWriteHSCXCMDR(cs, hscx, 0x80); + } else { + count = MemReadHSCX(cs, hscx, HSCX_RBCL) & ( + test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); + if (count == 0) + count = fifo_size; + Memhscx_empty_fifo(bcs, count); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HSCX: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } + } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + Memhscx_empty_fifo(bcs, fifo_size); + if (bcs->mode == L1_MODE_TRANS) { + /* receive audio data */ + if (!(skb = dev_alloc_skb(fifo_size))) + printk(KERN_WARNING "HiSax: receive out of memory\n"); + else { + memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); + } + } + if (val & 0x10) { /* XPR */ + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + Memhscx_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + Memhscx_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } + } } -static int -diva_ipac_pci_reset(struct IsdnCardState *cs) +static inline void +Memhscx_int_main(struct IsdnCardState *cs, u_char val) { - unsigned long misc_reg = cs->hw.diva.pci_cfg + PITA_MISC_REG; - writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, misc_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writel(PITA_PARA_MPX_MODE, misc_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); - return 0; + u_char exval; + struct BCState *bcs; + + if (val & 0x01) { // EXB + bcs = cs->bcs + 1; + exval = MemReadHSCX(cs, 1, HSCX_EXIR); + if (exval & 0x40) { + if (bcs->mode == 1) + Memhscx_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX B EXIR %x Lost TX", exval); + } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B EXIR %x", exval); + } + if (val & 0xf8) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B interrupt %x", val); + Memhscx_interrupt(cs, val, 1); + } + if (val & 0x02) { // EXA + bcs = cs->bcs; + exval = MemReadHSCX(cs, 0, HSCX_EXIR); + if (exval & 0x40) { + if (bcs->mode == L1_MODE_TRANS) + Memhscx_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX A EXIR %x Lost TX", exval); + } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A EXIR %x", exval); + } + if (val & 0x04) { // ICA + exval = MemReadHSCX(cs, 0, HSCX_ISTA); + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A interrupt %x", exval); + Memhscx_interrupt(cs, exval, 0); + } } -static int -diva_ipacx_pci_reset(struct IsdnCardState *cs) +static irqreturn_t +diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs) { - unsigned long misc_reg = cs->hw.diva.pci_cfg + PITA_MISC_REG; + struct IsdnCardState *cs = dev_id; + u_char ista,val; + int icnt=5; + u_char *cfg; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + cfg = (u_char *) cs->hw.diva.pci_cfg; + val = *cfg; + if (!(val & PITA_INT0_STATUS)) { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; /* other shared IRQ */ + } + *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */ + ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); +Start_IPACPCI: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + Memhscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPACPCI; + } + if (!icnt) + printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n"); + memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF); + memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} - writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, misc_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET, misc_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - ipacx_dc_write(cs, IPACX_MASK, 0xff); // Interrupts off - return 0; +static irqreturn_t +diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + u_char *cfg; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + cfg = (u_char *) cs->hw.diva.pci_cfg; + val = *cfg; + if (!(val &PITA_INT0_STATUS)) { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; // other shared IRQ + } + interrupt_ipacx(cs); // handler for chip + *cfg = PITA_INT0_STATUS; // Reset PLX interrupt + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } -static int -diva_reset(struct IsdnCardState *cs) +void +release_io_diva(struct IsdnCardState *cs) { - /* DIVA 2.0 */ - cs->hw.diva.ctrl_reg = 0; /* Reset On */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - if (cs->subtyp == DIVA_ISA) { - cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; - } else { - /* Workaround PCI9060 */ - byteout(cs->hw.diva.pci_cfg + 0x69, 9); - cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; + int bytecnt; + + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) { + u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg; + + *cfg = 0; /* disable INT0/1 */ + *cfg = 2; /* reset pending INT0 */ + iounmap((void *)cs->hw.diva.cfg_reg); + iounmap((void *)cs->hw.diva.pci_cfg); + return; + } else if (cs->subtyp != DIVA_IPAC_ISA) { + del_timer(&cs->hw.diva.tl); + if (cs->hw.diva.cfg_reg) + byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ + } + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) + bytecnt = 8; + else + bytecnt = 32; + if (cs->hw.diva.cfg_reg) { + release_region(cs->hw.diva.cfg_reg, bytecnt); + } +} + +static void +reset_diva(struct IsdnCardState *cs) +{ + if (cs->subtyp == DIVA_IPAC_ISA) { + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); + mdelay(10); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); + mdelay(10); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); + } else if (cs->subtyp == DIVA_IPAC_PCI) { + unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + + PITA_MISC_REG); + *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; + mdelay(10); + *ireg = PITA_PARA_MPX_MODE; + mdelay(10); + memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); + } else if (cs->subtyp == DIVA_IPACX_PCI) { + unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + + PITA_MISC_REG); + *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; + mdelay(10); + *ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET; + mdelay(10); + MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off + } else { /* DIVA 2.0 */ + cs->hw.diva.ctrl_reg = 0; /* Reset On */ + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + mdelay(10); + cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + mdelay(10); + if (cs->subtyp == DIVA_ISA) + cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; + else { + /* Workaround PCI9060 */ + byteout(cs->hw.diva.pci_cfg + 0x69, 9); + cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; + } + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); } - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - return 0; } +#define DIVA_ASSIGN 1 + static void diva_led_handler(struct IsdnCardState *cs) { int blink = 0; - if (cs->status & 0x0001) + if ((cs->subtyp == DIVA_IPAC_ISA) || + (cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) + return; + del_timer(&cs->hw.diva.tl); + if (cs->hw.diva.status & DIVA_ASSIGN) cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_A : DIVA_PCI_LED_A; else { @@ -459,10 +792,10 @@ diva_led_handler(struct IsdnCardState *c DIVA_ISA_LED_A : DIVA_PCI_LED_A; blink = 250; } - if (cs->status & 0xf000) + if (cs->hw.diva.status & 0xf000) cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B; - else if (cs->status & 0x0f00) { + else if (cs->hw.diva.status & 0x0f00) { cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B; blink = 500; @@ -471,212 +804,90 @@ diva_led_handler(struct IsdnCardState *c DIVA_ISA_LED_B : DIVA_PCI_LED_B); byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - if (blink) - mod_timer(&cs->hw.diva.tl, jiffies + (blink * HZ) / 1000); -} - -static void -diva_ipacx_pci_init(struct IsdnCardState *cs) -{ - writel(PITA_INT0_ENABLE, cs->hw.diva.pci_cfg); - init_ipacx(cs, 3); // init chip and enable interrupts -} - -static void -diva_ipac_pci_init(struct IsdnCardState *cs) -{ - writel(PITA_INT0_ENABLE, cs->hw.diva.pci_cfg); - ipac_init(cs); -} - -static struct card_ops diva_ops = { - .init = inithscxisac, - .reset = diva_reset, - .release = diva_release, - .led_handler = diva_led_handler, - .irq_func = diva_interrupt, -}; - -static struct card_ops diva_ipac_isa_ops = { - .init = ipac_init, - .reset = diva_ipac_isa_reset, - .release = hisax_release_resources, - .irq_func = ipac_irq, -}; - -static struct card_ops diva_ipac_pci_ops = { - .init = diva_ipac_pci_init, - .reset = diva_ipac_pci_reset, - .release = diva_ipac_pci_release, - .irq_func = diva_ipac_pci_irq, -}; - -static struct card_ops diva_ipacx_pci_ops = { - .init = diva_ipacx_pci_init, - .reset = diva_ipacx_pci_reset, - .release = diva_ipac_pci_release, - .irq_func = diva_ipacx_pci_irq, -}; - -static int __init -diva_ipac_probe(struct IsdnCardState *cs) -{ - u8 val; - - // request_io - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - return (val == 1 || val == 2); -} - -static int __init -diva_ipac_isa_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = DIVA_IPAC_ISA; - cs->irq = card->para[0]; - cs->hw.diva.cfg_reg = card->para[1]; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", - "IPAC ISA", cs->hw.diva.cfg_reg, cs->irq); - if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 8, "diva isdn")) - goto err; - diva_ipac_isa_reset(cs); - cs->card_ops = &diva_ipac_isa_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -diva_isac_isa_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = DIVA_ISA; - cs->irq = card->para[0]; - cs->hw.diva.cfg_reg = card->para[1]; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", - "ISA", cs->hw.diva.cfg_reg, cs->irq); - if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 8, "diva isdn")) - goto err; - diva_reset(cs); - init_timer(&cs->hw.diva.tl); - cs->hw.diva.tl.function = (void *) diva_led_handler; - cs->hw.diva.tl.data = (long) cs; - cs->card_ops = &diva_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -diva_isa_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - int is_ipac; - cs->hw.diva.cfg_reg = card->para[1]; - if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 8, "diva isdn")) - return -EBUSY; - - is_ipac = diva_ipac_probe(cs); - hisax_release_resources(cs); - - if (is_ipac) - return diva_ipac_isa_probe(cs, card); - else - return diva_isac_isa_probe(cs, card); + if (blink) { + init_timer(&cs->hw.diva.tl); + cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000); + add_timer(&cs->hw.diva.tl); + } } -static int __init -diva_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) +static int +Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - if (pci_enable_device(pdev)) - goto err; + u_int *ireg; + u_long flags; - cs->subtyp = DIVA_PCI; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.diva.cfg_reg = pci_resource_start(pdev, 2); - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", - "PCI", cs->hw.diva.cfg_reg, cs->irq); - printk(KERN_INFO "Diva: %s space at %#lx\n", - "PCI", cs->hw.diva.pci_cfg); - if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 32, "diva isdn")) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -diva_ipac_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.diva.pci_cfg = (unsigned long)request_mmio( - &cs->rs, pci_resource_start(pdev, 0), 4096, "diva"); - cs->hw.diva.cfg_reg = (unsigned long)request_mmio( - &cs->rs, pci_resource_start(pdev, 1), 4096, "diva"); - printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", - "IPAC PCI", cs->hw.diva.cfg_reg, cs->irq); - printk(KERN_INFO "Diva: %s space at %#lx\n", - "IPAC PCI", cs->hw.diva.pci_cfg); - diva_ipac_pci_reset(cs); - cs->card_ops = &diva_ipac_pci_ops; - if (ipac_setup(cs, &mem_ipac_dc_ops, &mem_ipac_bc_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -diva_ipacx_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", - "IPACX PCI", cs->hw.diva.cfg_reg, cs->irq); - printk(KERN_INFO "Diva: %s space at %#lx\n", - "IPACX PCI", cs->hw.diva.pci_cfg); - diva_ipacx_pci_reset(cs); - cs->card_ops = &diva_ipacx_pci_ops; - if (ipacx_setup(cs, &ipacx_dc_ops, &ipacx_bc_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_diva(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_diva(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + reset_diva(cs); + if (cs->subtyp == DIVA_IPACX_PCI) { + ireg = (unsigned int *)cs->hw.diva.pci_cfg; + *ireg = PITA_INT0_ENABLE; + init_ipacx(cs, 3); // init chip and enable interrupts + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + } + if (cs->subtyp == DIVA_IPAC_PCI) { + ireg = (unsigned int *)cs->hw.diva.pci_cfg; + *ireg = PITA_INT0_ENABLE; + } + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + case (MDL_REMOVE | REQUEST): + cs->hw.diva.status = 0; + break; + case (MDL_ASSIGN | REQUEST): + cs->hw.diva.status |= DIVA_ASSIGN; + break; + case MDL_INFO_SETUP: + if ((long)arg) + cs->hw.diva.status |= 0x0200; + else + cs->hw.diva.status |= 0x0100; + break; + case MDL_INFO_CONN: + if ((long)arg) + cs->hw.diva.status |= 0x2000; + else + cs->hw.diva.status |= 0x1000; + break; + case MDL_INFO_REL: + if ((long)arg) { + cs->hw.diva.status &= ~0x2000; + cs->hw.diva.status &= ~0x0200; + } else { + cs->hw.diva.status &= ~0x1000; + cs->hw.diva.status &= ~0x0100; + } + break; + } + if ((cs->subtyp != DIVA_IPAC_ISA) && + (cs->subtyp != DIVA_IPAC_PCI) && + (cs->subtyp != DIVA_IPACX_PCI)) { + spin_lock_irqsave(&cs->lock, flags); + diva_led_handler(cs); + spin_unlock_irqrestore(&cs->lock, flags); + } + return(0); } static struct pci_dev *dev_diva __initdata = NULL; static struct pci_dev *dev_diva_u __initdata = NULL; static struct pci_dev *dev_diva201 __initdata = NULL; +static struct pci_dev *dev_diva202 __initdata = NULL; + #ifdef __ISAPNP__ static struct isapnp_device_id diva_ids[] __initdata = { { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), @@ -700,99 +911,268 @@ static struct isapnp_device_id diva_ids[ { 0, } }; -static struct isapnp_device_id *pdev = &diva_ids[0]; +static struct isapnp_device_id *ipid __initdata = &diva_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif + int __init setup_diva(struct IsdnCard *card) { + int bytecnt = 8; + u_char val; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, Diva_revision); printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_DIEHLDIVA) + return(0); + cs->hw.diva.status = 0; if (card->para[1]) { - if (diva_isa_probe(card->cs, card) < 0) - return 0; - return 1; - - } + cs->hw.diva.ctrl_reg = 0; + cs->hw.diva.cfg_reg = card->para[1]; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if ((val == 1) || (val==2)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } + cs->irq = card->para[0]; + } else { #ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; - - while(pdev->card_vendor) { - if ((pb = pnp_find_card(pdev->card_vendor, - pdev->card_device, pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - pdev->vendor, - pdev->function, - pd))) { - printk(KERN_INFO "HiSax: %s detected\n", - (char *)pdev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "Diva PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "Diva PnP: activate failed\n"); - pnp_device_detach(pd); - return 0; - } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); - return(0); - } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); - if (pdev->function == ISAPNP_FUNCTION(0xA1)) { - if (diva_ipac_isa_probe(card->cs, card)) - return 0; - return 1; + if (isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.diva.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0xA1)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = + card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = + card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_HSCX_ADR; + } + goto ready; } else { - if (diva_isac_isa_probe(card->cs, card)) - return 0; - return 1; + printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); + return(0); } - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return(0); } - pdev++; + ipid++; pnp_c=NULL; } - if (!pdev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "Diva PnP: no ISAPnP card found\n"); } } - } #endif -#ifdef CONFIG_PCI - if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, - dev_diva))) { - if (diva_pci_probe(card->cs, dev_diva)) - return 0; - return 1; - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, - dev_diva_u))) { - if (diva_pci_probe(card->cs, dev_diva_u)) - return 0; - return 1; - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, - dev_diva201))) { - if (diva_ipac_pci_probe(card->cs, dev_diva201)) - return 0; - return 1; - } - printk(KERN_WARNING "Diva: No PCI card found\n"); +#if CONFIG_PCI + cs->subtyp = 0; + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { + if (pci_enable_device(dev_diva)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva_u->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return(0); + cs->subtyp = DIVA_IPAC_PCI; + cs->irq = dev_diva201->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); + } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { + if (pci_enable_device(dev_diva202)) + return(0); + cs->subtyp = DIVA_IPACX_PCI; + cs->irq = dev_diva202->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); + } else { + printk(KERN_WARNING "Diva: No PCI card found\n"); + return(0); + } + + if (!cs->irq) { + printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + return(0); + } + + if (!cs->hw.diva.cfg_reg) { + printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + return(0); + } + cs->irq_flags |= SA_SHIRQ; +#else + printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); + printk(KERN_WARNING "Diva: unable to config DIVA PCI\n"); + return (0); #endif /* CONFIG_PCI */ - return 0; + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) { + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = 0; + cs->hw.diva.hscx = 0; + cs->hw.diva.isac_adr = 0; + cs->hw.diva.hscx_adr = 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + bytecnt = 0; + } else { + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; + bytecnt = 32; + } + } +ready: + printk(KERN_INFO + "Diva: %s card configured at %#lx IRQ %d\n", + (cs->subtyp == DIVA_PCI) ? "PCI" : + (cs->subtyp == DIVA_ISA) ? "ISA" : + (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : + (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI", + cs->hw.diva.cfg_reg, cs->irq); + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) || + (cs->subtyp == DIVA_PCI) ) + printk(KERN_INFO "Diva: %s space at %#lx\n", + (cs->subtyp == DIVA_PCI) ? "PCI" : + (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI", + cs->hw.diva.pci_cfg); + if ((cs->subtyp != DIVA_IPAC_PCI) && + (cs->subtyp != DIVA_IPACX_PCI) ) { + if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.diva.cfg_reg, + cs->hw.diva.cfg_reg + bytecnt); + return (0); + } + } + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Diva_card_msg; + setup_isac(cs); + if (cs->subtyp == DIVA_IPAC_ISA) { + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &diva_irq_ipac_isa; + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + } else if (cs->subtyp == DIVA_IPAC_PCI) { + cs->readisac = &MemReadISAC_IPAC; + cs->writeisac = &MemWriteISAC_IPAC; + cs->readisacfifo = &MemReadISACfifo_IPAC; + cs->writeisacfifo = &MemWriteISACfifo_IPAC; + cs->BC_Read_Reg = &MemReadHSCX; + cs->BC_Write_Reg = &MemWriteHSCX; + cs->BC_Send_Data = &Memhscx_fill_fifo; + cs->irq_func = &diva_irq_ipac_pci; + val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + } else if (cs->subtyp == DIVA_IPACX_PCI) { + cs->readisac = &MemReadISAC_IPACX; + cs->writeisac = &MemWriteISAC_IPACX; + cs->readisacfifo = &MemReadISACfifo_IPACX; + cs->writeisacfifo = &MemWriteISACfifo_IPACX; + cs->BC_Read_Reg = &MemReadHSCX_IPACX; + cs->BC_Write_Reg = &MemWriteHSCX_IPACX; + cs->BC_Send_Data = 0; // function located in ipacx module + cs->irq_func = &diva_irq_ipacx_pci; + printk(KERN_INFO "Diva: IPACX Design Id: %x\n", + MemReadISAC_IPACX(cs, IPACX_ID) &0x3F); + } else { /* DIVA 2.0 */ + cs->hw.diva.tl.function = (void *) diva_led_handler; + cs->hw.diva.tl.data = (long) cs; + init_timer(&cs->hw.diva.tl); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->irq_func = &diva_interrupt; + ISACVersion(cs, "Diva:"); + if (HscxVersion(cs, "Diva:")) { + printk(KERN_WARNING + "Diva: wrong HSCX versions check IO address\n"); + release_io_diva(cs); + return (0); + } + } + return (1); } diff -puN drivers/isdn/hisax/elsa.c~i4l drivers/isdn/hisax/elsa.c --- 25/drivers/isdn/hisax/elsa.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/elsa.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: elsa.c,v 2.26.6.6 2001/09/23 22:24:47 kai Exp $ +/* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $ * * low level stuff for Elsa isdn cards * @@ -32,9 +32,8 @@ #include extern const char *CardType[]; -static spinlock_t elsa_lock = SPIN_LOCK_UNLOCKED; -const char *Elsa_revision = "$Revision: 2.26.6.6 $"; +const char *Elsa_revision = "$Revision: 2.32.2.4 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", @@ -106,6 +105,7 @@ const char *ITACVer[] = /* Status Flags */ #define ELSA_TIMER_AKTIV 1 #define ELSA_BAD_PWR 2 +#define ELSA_ASSIGN 4 #define RS_ISR_PASS_LIMIT 256 #define _INLINE_ inline @@ -141,163 +141,123 @@ static void set_arcofi(struct IsdnCardSt #include "elsa_ser.c" #endif /* ARCOFI_USE */ -static inline u8 -readreg(struct IsdnCardState *cs, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&elsa_lock, flags); - byteout(cs->hw.elsa.ale, off); + byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&elsa_lock, flags); - return ret; + return (ret); } static inline void -writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&elsa_lock, flags); - byteout(cs->hw.elsa.ale, off); - byteout(adr, data); - spin_unlock_irqrestore(&elsa_lock, flags); + byteout(ale, off); + insb(adr, data, size); } + static inline void -readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - byteout(cs->hw.elsa.ale, off); - insb(adr, data, size); + byteout(ale, off); + byteout(adr, data); } static inline void -writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - byteout(cs->hw.elsa.ale, off); + byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.elsa.isac, offset); + return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.elsa.isac, offset, value); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.elsa.isac, 0, data, size); + readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.elsa.isac, 0, data, size); + writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value); } static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.elsa.hscx, hscx ? 0x40 : 0, data, size); + readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - writefifo(cs, cs->hw.elsa.hscx, hscx ? 0x40 : 0, data, size); -} - -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static inline u8 -ipac_read(struct IsdnCardState *cs, u8 offset) -{ - return readreg(cs, cs->hw.elsa.isac, offset); -} - -static inline void -ipac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - writereg(cs, cs->hw.elsa.isac, offset, value); + writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); } -static inline void -ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - readfifo(cs, cs->hw.elsa.isac, offset, data, size); + return (readreg(cs->hw.elsa.ale, + cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0))); } -static inline void -ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writefifo(cs, cs->hw.elsa.isac, offset, data, size); + writereg(cs->hw.elsa.ale, + cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value); } -/* This will generate ipac_dc_ops and ipac_bc_ops using the functions - * above */ - -BUILD_IPAC_OPS(ipac); - -static inline u8 -readitac(struct IsdnCardState *cs, u8 off) +static inline u_char +readitac(struct IsdnCardState *cs, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&elsa_lock, flags); byteout(cs->hw.elsa.ale, off); ret = bytein(cs->hw.elsa.itac); - spin_unlock_irqrestore(&elsa_lock, flags); - return ret; + return (ret); } static inline void -writeitac(struct IsdnCardState *cs, u8 off, u8 data) +writeitac(struct IsdnCardState *cs, u_char off, u_char data) { - unsigned long flags; - - spin_lock_irqsave(&elsa_lock, flags); byteout(cs->hw.elsa.ale, off); byteout(cs->hw.elsa.itac, data); - spin_unlock_irqrestore(&elsa_lock, flags); } static inline int TimerRun(struct IsdnCardState *cs) { - register u8 v; + register u_char v; v = bytein(cs->hw.elsa.cfg); if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000)) @@ -306,12 +266,30 @@ TimerRun(struct IsdnCardState *cs) return (v & ELSA_TIMER_RUN_PCC8); return (v & ELSA_TIMER_RUN); } +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \ + cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \ + cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data) + +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \ + cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \ + cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" static irqreturn_t elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; + u_long flags; + u_char val; + int icnt=5; if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { /* The card tends to generate interrupts while being removed @@ -319,19 +297,45 @@ elsa_interrupt(int intno, void *dev_id, printk(KERN_WARNING "Elsa: card not available!\n"); return IRQ_NONE; } + spin_lock_irqsave(&cs->lock, flags); #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); - spin_lock(&cs->lock); rs_interrupt_elsa(intno, cs); - spin_unlock(&cs->lock); } } #endif - hscxisac_irq(intno, dev_id, regs); - + val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) { + hscx_int_main(cs, val); + } + val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); + Start_ISAC: + if (val) { + isac_interrupt(cs, val); + } + val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); + if (val && icnt) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + icnt--; + goto Start_HSCX; + } + val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); + if (val && icnt) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + icnt--; + goto Start_ISAC; + } + if (!icnt) + printk(KERN_WARNING"ELSA IRQ LOOP\n"); + writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF); if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) { if (!TimerRun(cs)) { /* Timer Restart */ @@ -351,6 +355,10 @@ elsa_interrupt(int intno, void *dev_id, #endif if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); + writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } @@ -358,35 +366,70 @@ static irqreturn_t elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; + u_long flags; + u_char ista,val; + int icnt=5; - if (!cs) { - printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); - return IRQ_NONE; - } + spin_lock_irqsave(&cs->lock, flags); if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ - if (!test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags) && - !(val & ELSA_PCI_IRQ_MASK)) + if (!(val & ELSA_PCI_IRQ_MASK)) { + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; + } } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); - spin_lock(&cs->lock); rs_interrupt_elsa(intno, cs); - spin_unlock(&cs->lock); } } #endif - return ipac_irq(intno, dev_id, regs); + ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "ELSA IRQ LOOP\n"); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } -static void -elsa_release(struct IsdnCardState *cs) +void +release_io_elsa(struct IsdnCardState *cs) { + int bytecnt = 8; + del_timer(&cs->hw.elsa.tl); #if ARCOFI_USE clear_arcofi(cs); @@ -395,28 +438,33 @@ elsa_release(struct IsdnCardState *cs) byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ if (cs->subtyp == ELSA_QS1000PCI) { byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */ - writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); + bytecnt = 2; + release_region(cs->hw.elsa.cfg, 0x80); } if (cs->subtyp == ELSA_QS3000PCI) { byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */ - writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); + release_region(cs->hw.elsa.cfg, 0x80); } if (cs->subtyp == ELSA_PCMCIA_IPAC) { - writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); } -#if ARCOFI_USE if ((cs->subtyp == ELSA_PCFPRO) || (cs->subtyp == ELSA_QS3000) || (cs->subtyp == ELSA_PCF) || (cs->subtyp == ELSA_QS3000PCI)) { + bytecnt = 16; +#if ARCOFI_USE release_modem(cs); - } #endif - hisax_release_resources(cs); + } + if (cs->hw.elsa.base) + release_region(cs->hw.elsa.base, bytecnt); } -static int -elsa_reset(struct IsdnCardState *cs) +static void +reset_elsa(struct IsdnCardState *cs) { if (cs->hw.elsa.timer) { /* Wait 1 Timer */ @@ -437,28 +485,25 @@ elsa_reset(struct IsdnCardState *cs) byteout(cs->hw.elsa.trig, 0xff); } if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { - writereg(cs, cs->hw.elsa.isac, IPAC_POTA2, 0x20); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - writereg(cs, cs->hw.elsa.isac, IPAC_POTA2, 0x00); - set_current_state(TASK_UNINTERRUPTIBLE); - writereg(cs, cs->hw.elsa.isac, IPAC_MASK, 0xc0); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); + mdelay(10); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); + mdelay(10); if (cs->subtyp != ELSA_PCMCIA_IPAC) { - writereg(cs, cs->hw.elsa.isac, IPAC_ACFG, 0x0); - writereg(cs, cs->hw.elsa.isac, IPAC_AOE, 0x3c); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c); } else { - writereg(cs, cs->hw.elsa.isac, IPAC_PCFG, 0x10); - writereg(cs, cs->hw.elsa.isac, IPAC_ACFG, 0x4); - writereg(cs, cs->hw.elsa.isac, IPAC_AOE, 0xf8); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8); } - writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); if (cs->subtyp == ELSA_QS1000PCI) byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ else if (cs->subtyp == ELSA_QS3000PCI) byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */ } - return 0; } #if ARCOFI_USE @@ -476,7 +521,7 @@ check_arcofi(struct IsdnCardState *cs) int arcofi_present = 0; char tmp[40]; char *t; - u8 *p; + u_char *p; if (!cs->dc.isac.mon_tx) if (!(cs->dc.isac.mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { @@ -525,14 +570,28 @@ check_arcofi(struct IsdnCardState *cs) "Elsa: %s detected modem at 0x%lx\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); - request_io(&cs->rs, cs->hw.elsa.base+8, 8, "elsa isdn modem"); + release_region(cs->hw.elsa.base, 8); + if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { + printk(KERN_WARNING + "HiSax: %s config port %lx-%lx already in use\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base + 8, + cs->hw.elsa.base + 16); + } } else if (cs->subtyp==ELSA_PCC16) { cs->subtyp = ELSA_PCF; printk(KERN_INFO "Elsa: %s detected modem at 0x%lx\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); - request_io(&cs->rs, cs->hw.elsa.base+8, 8, "elsa isdn modem"); + release_region(cs->hw.elsa.base, 8); + if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { + printk(KERN_WARNING + "HiSax: %s config port %lx-%lx already in use\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base + 8, + cs->hw.elsa.base + 16); + } } else printk(KERN_INFO "Elsa: %s detected modem at 0x%lx\n", @@ -553,15 +612,8 @@ elsa_led_handler(struct IsdnCardState *c if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC) return; - - if (cs->typ == ISDN_CTYPE_ELSA) { - int pwr = bytein(cs->hw.elsa.ale); - if (pwr & 0x08) - cs->hw.elsa.status |= ELSA_BAD_PWR; - else - cs->hw.elsa.status &= ~ELSA_BAD_PWR; - } - if (cs->status & 0x0001) + del_timer(&cs->hw.elsa.tl); + if (cs->hw.elsa.status & ELSA_ASSIGN) cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED; else if (cs->hw.elsa.status & ELSA_BAD_PWR) cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED; @@ -569,9 +621,9 @@ elsa_led_handler(struct IsdnCardState *c cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED; blink = 250; } - if (cs->status & 0xf000) + if (cs->hw.elsa.status & 0xf000) cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED; - else if (cs->status & 0x0f00) { + else if (cs->hw.elsa.status & 0x0f00) { cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED; blink = 500; } else @@ -579,159 +631,148 @@ elsa_led_handler(struct IsdnCardState *c if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { - u8 led = 0xff; + u_char led = 0xff; if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) led ^= ELSA_IPAC_LINE_LED; if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) led ^= ELSA_IPAC_STAT_LED; - writereg(cs, cs->hw.elsa.isac, IPAC_ATX, led); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); } else byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - - if (blink) - mod_timer(&cs->hw.elsa.tl, jiffies + (blink * HZ) / 1000); -} - -#if ARCOFI_USE -static void -elsa_aux_ind(struct IsdnCardState *cs, void *arg) -{ - if (cs->hw.elsa.MFlag) { - int len; - u8 *msg; - - if (!arg) - return; - msg = arg; - len = *msg; - msg++; - modem_write_cmd(cs, msg, len); - } -} -#else -#define elsa_aux_ind NULL -#endif - -static void -elsa_init(struct IsdnCardState *cs) -{ - if (cs->subtyp == ELSA_QS1000 || cs->subtyp == ELSA_QS3000) - byteout(cs->hw.elsa.timer, 0); - - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - - inithscxisac(cs); + if (blink) { + init_timer(&cs->hw.elsa.tl); + cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); + add_timer(&cs->hw.elsa.tl); + } } -static void -elsa_ipac_init(struct IsdnCardState *cs) +static int +Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - - ipac_init(cs); -} + int ret = 0; + u_long flags; -static void -elsa_test(struct IsdnCardState *cs) -{ - if ((cs->subtyp == ELSA_PCMCIA) || - (cs->subtyp == ELSA_PCMCIA_IPAC) || - (cs->subtyp == ELSA_QS1000PCI)) { - return; - } - if (cs->subtyp != ELSA_QS3000PCI) { - cs->hw.elsa.counter = 0; - cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT; - cs->hw.elsa.status |= ELSA_TIMER_AKTIV; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - byteout(cs->hw.elsa.timer, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((110*HZ)/1000); - cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; - printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", - cs->hw.elsa.counter); - if ((cs->hw.elsa.counter > 10) && - (cs->hw.elsa.counter < 16)) { - printk(KERN_INFO "Elsa: timer and irq OK\n"); - } else { - printk(KERN_WARNING - "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", - cs->hw.elsa.counter, cs->irq); - } - } + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_elsa(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_elsa(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + cs->debug |= L1_DEB_IPAC; + reset_elsa(cs); + inithscxisac(cs, 1); + if ((cs->subtyp == ELSA_QS1000) || + (cs->subtyp == ELSA_QS3000)) + { + byteout(cs->hw.elsa.timer, 0); + } + if (cs->hw.elsa.trig) + byteout(cs->hw.elsa.trig, 0xff); + inithscxisac(cs, 2); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + if ((cs->subtyp == ELSA_PCMCIA) || + (cs->subtyp == ELSA_PCMCIA_IPAC) || + (cs->subtyp == ELSA_QS1000PCI)) { + return(0); + } else if (cs->subtyp == ELSA_QS3000PCI) { + ret = 0; + } else { + spin_lock_irqsave(&cs->lock, flags); + cs->hw.elsa.counter = 0; + cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT; + cs->hw.elsa.status |= ELSA_TIMER_AKTIV; + byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); + byteout(cs->hw.elsa.timer, 0); + spin_unlock_irqrestore(&cs->lock, flags); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((110*HZ)/1000); + spin_lock_irqsave(&cs->lock, flags); + cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; + byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); + cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; + spin_unlock_irqrestore(&cs->lock, flags); + printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", + cs->hw.elsa.counter); + if ((cs->hw.elsa.counter > 10) && + (cs->hw.elsa.counter < 16)) { + printk(KERN_INFO "Elsa: timer and irq OK\n"); + ret = 0; + } else { + printk(KERN_WARNING + "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", + cs->hw.elsa.counter, cs->irq); + ret = 1; + } + } #if ARCOFI_USE - if (check_arcofi(cs)) { - init_modem(cs); - } + if (check_arcofi(cs)) { + init_modem(cs); + } #endif - elsa_led_handler(cs); -} - -static struct card_ops elsa_ops = { - .init = elsa_init, - .test = elsa_test, - .reset = elsa_reset, - .release = elsa_release, - .aux_ind = elsa_aux_ind, - .led_handler = elsa_led_handler, - .irq_func = elsa_interrupt, -}; - -static struct card_ops elsa_ipac_ops = { - .init = elsa_ipac_init, - .test = elsa_test, - .reset = elsa_reset, - .release = elsa_release, - .aux_ind = elsa_aux_ind, - .led_handler = elsa_led_handler, - .irq_func = elsa_interrupt_ipac, -}; - -static void __init -elsa_arcofi_init(struct IsdnCardState *cs) -{ + elsa_led_handler(cs); + return(ret); + case (MDL_REMOVE | REQUEST): + cs->hw.elsa.status &= 0; + break; + case (MDL_ASSIGN | REQUEST): + cs->hw.elsa.status |= ELSA_ASSIGN; + break; + case MDL_INFO_SETUP: + if ((long) arg) + cs->hw.elsa.status |= 0x0200; + else + cs->hw.elsa.status |= 0x0100; + break; + case MDL_INFO_CONN: + if ((long) arg) + cs->hw.elsa.status |= 0x2000; + else + cs->hw.elsa.status |= 0x1000; + break; + case MDL_INFO_REL: + if ((long) arg) { + cs->hw.elsa.status &= ~0x2000; + cs->hw.elsa.status &= ~0x0200; + } else { + cs->hw.elsa.status &= ~0x1000; + cs->hw.elsa.status &= ~0x0100; + } + break; #if ARCOFI_USE - init_arcofi(cs); + case CARD_AUX_IND: + if (cs->hw.elsa.MFlag) { + int len; + u_char *msg; + + if (!arg) + return(0); + msg = arg; + len = *msg; + msg++; + modem_write_cmd(cs, msg, len); + } + break; #endif -} - -static void __init -elsa_timer_init(struct IsdnCardState *cs) -{ - cs->hw.elsa.tl.function = (void *) elsa_led_handler; - cs->hw.elsa.tl.data = (long) cs; - init_timer(&cs->hw.elsa.tl); -} - -static int __init -elsa_timer_test(struct IsdnCardState *cs) -{ - /* test timer */ - byteout(cs->hw.elsa.trig, 0xff); - byteout(cs->hw.elsa.timer, 0); - if (!TimerRun(cs)) { - byteout(cs->hw.elsa.timer, 0); /* second attempt */ - if (!TimerRun(cs)) { - printk(KERN_WARNING "Elsa: timer does not start\n"); - goto err; - } } - HZDELAY(10 * HZ / 1000); /* wait >=10 ms */ - if (TimerRun(cs)) { - printk(KERN_WARNING "Elsa: timer does not run\n"); - goto err; - } - printk(KERN_INFO "Elsa: timer OK; resetting card\n"); - return 0; - err: - return -EBUSY; + if (cs->typ == ISDN_CTYPE_ELSA) { + int pwr = bytein(cs->hw.elsa.ale); + if (pwr & 0x08) + cs->hw.elsa.status |= ELSA_BAD_PWR; + else + cs->hw.elsa.status &= ~ELSA_BAD_PWR; + } + elsa_led_handler(cs); + return(ret); } -static unsigned char __init +static unsigned char probe_elsa_adr(unsigned int adr, int typ) { int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0, @@ -740,13 +781,18 @@ probe_elsa_adr(unsigned int adr, int typ /* In case of the elsa pcmcia card, this region is in use, reserved for us by the card manager. So we do not check it here, it would fail. */ - if (typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(adr, 8, "elsa")) { - printk(KERN_WARNING "Elsa: probing port 0x%x: in use\n", adr); - return 0; + if (typ != ISDN_CTYPE_ELSA_PCMCIA) { + if (request_region(adr, 8, "elsa card")) { + release_region(adr, 8); + } else { + printk(KERN_WARNING + "Elsa: Probing Port 0x%x: already in use\n", adr); + return (0); + } } for (i = 0; i < 16; i++) { - in1 = inb(adr + ELSA_CONFIG); /* 'toggels' at */ - in2 = inb(adr + ELSA_CONFIG); /* each access */ + in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */ + in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */ p16_1 += 0x04 & in1; p16_2 += 0x04 & in2; p8_1 += 0x02 & in1; @@ -756,7 +802,6 @@ probe_elsa_adr(unsigned int adr, int typ pfp_1 += 0x40 & in1; pfp_2 += 0x40 & in2; } - release_region(adr, 8); printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); if (65 == ++p16_1 * ++p16_2) { printk(" PCC-16/PCF found\n"); @@ -776,227 +821,18 @@ probe_elsa_adr(unsigned int adr, int typ } } -static int __init -elsa_probe(struct IsdnCardState *cs, struct IsdnCard *card) +static unsigned int +probe_elsa(struct IsdnCardState *cs) { - u8 val; - int i, bytecnt = 8; - unsigned int CARD_portlist[] = {0x160, 0x170, 0x260, 0x360, 0}; - - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, cs->typ); - if (!cs->subtyp) { - printk(KERN_WARNING "Elsa: no Microlink at %#lx\n", - cs->hw.elsa.base); - goto err; - } - } else { - for (i = 0; CARD_portlist[i]; i++) { - cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ); - if (cs->subtyp) - cs->hw.elsa.base = CARD_portlist[i]; - break; - } - } - if (!cs->hw.elsa.base) - goto err; - - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u8 CARD_IrqTab[8] = {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u8 CARD_IrqTab[8] = {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u8 CARD_IrqTab[8] = {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) - val = 'C'; - printk(KERN_INFO "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], cs->hw.elsa.base, val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - switch (cs->subtyp) { - case ELSA_PCFPRO: bytecnt = 16; break; - } - if (!request_io(&cs->rs, cs->hw.elsa.base, bytecnt, "elsa isdn")) - goto err; - elsa_arcofi_init(cs); - elsa_timer_init(cs); - if (elsa_timer_test(cs)) - goto err; - elsa_reset(cs); - cs->card_ops = &elsa_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - if (cs->subtyp == ELSA_PC) { - val = readitac(cs, ITAC_SYS); - printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); - writeitac(cs, ITAC_ISEN, 0); - writeitac(cs, ITAC_RFIE, 0); - writeitac(cs, ITAC_XFIE, 0); - writeitac(cs, ITAC_SCIE, 0); - writeitac(cs, ITAC_STIE, 0); - } - return 0; - err: - elsa_release(cs); - return -EBUSY; -} - -static int __init -elsa_qs_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - int bytecnt = 8; + int i; + unsigned int CARD_portlist[] = + {0x160, 0x170, 0x260, 0x360, 0}; - cs->irq = card->para[0]; - cs->hw.elsa.base = card->para[1]; - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->irq); - switch (cs->subtyp) { - case ELSA_QS3000: bytecnt = 16; break; - } - if (!request_io(&cs->rs, cs->hw.elsa.base, bytecnt, "elsa isdn")) - goto err; - elsa_arcofi_init(cs); - elsa_timer_init(cs); - if (elsa_timer_test(cs)) - goto err; - elsa_reset(cs); - cs->card_ops = &elsa_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - elsa_release(cs); - return -EBUSY; -} - -static int __init -elsa_qs1000_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = ELSA_QS1000; - return elsa_qs_probe(cs, card); -} - -static int __init -elsa_qs3000_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = ELSA_QS3000; - return elsa_qs_probe(cs, card); -} - -static int __init -elsa_pcmcia_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - u8 val; - - cs->irq = card->para[0]; - cs->hw.elsa.base = card->para[1]; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - val = readreg(cs, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - printk(KERN_INFO "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->irq); - elsa_arcofi_init(cs); - elsa_reset(cs); - if (cs->subtyp == ELSA_PCMCIA_IPAC) { - cs->card_ops = &elsa_ipac_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; - } else { - cs->card_ops = &elsa_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - } - return 0; - err: - elsa_release(cs); - return -EBUSY; -} - -static int __init -elsa_qs_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev, - int subtyp) -{ - int bytecnt = 2; - u8 pci_rev; - - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = subtyp; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.elsa.cfg = pci_resource_start(pdev, 1); - cs->hw.elsa.base = pci_resource_start(pdev, 3); - pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); - if (cs->hw.elsa.cfg & 0x80 && pci_rev == 1) { - printk(KERN_INFO "Elsa: PLX9050 rev1 workaround activated\n"); - __set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base +1; - cs->hw.elsa.hscx = cs->hw.elsa.base +1; - printk(KERN_INFO "Elsa: %s defined at %#lx/%#x IRQ %d\n", - Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->hw.elsa.cfg, - cs->irq); - switch (cs->subtyp) { - case ELSA_QS3000PCI: bytecnt = 16; break; + for (i = 0; CARD_portlist[i]; i++) { + if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ))) + break; } - if (!request_io(&cs->rs, cs->hw.elsa.base, bytecnt, "elsa isdn")) - goto err; - if (!request_io(&cs->rs, cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) - goto err; - elsa_arcofi_init(cs); - elsa_timer_init(cs); - elsa_reset(cs); - cs->card_ops = &elsa_ipac_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; - return 0; - err: - elsa_release(cs); - return -EBUSY; + return (CARD_portlist[i]); } static struct pci_dev *dev_qs1000 __devinitdata = NULL; @@ -1013,109 +849,343 @@ static struct isapnp_device_id elsa_ids[ { 0, } }; -static struct isapnp_device_id *pdev = &elsa_ids[0]; +static struct isapnp_device_id *ipid __initdata = &elsa_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif int __devinit setup_elsa(struct IsdnCard *card) { + int bytecnt; + u_char val; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, Elsa_revision); printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - - if (card->typ == ISDN_CTYPE_ELSA) { - if (elsa_probe(card->cs, card)) - return 0; - return 1; - } else if (card->typ == ISDN_CTYPE_ELSA_PNP) { + cs->hw.elsa.ctrl_reg = 0; + cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; + cs->subtyp = 0; + if (cs->typ == ISDN_CTYPE_ELSA) { + cs->hw.elsa.base = card->para[0]; + printk(KERN_INFO "Elsa: Microlink IO probing\n"); + if (cs->hw.elsa.base) { + if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, + cs->typ))) { + printk(KERN_WARNING + "Elsa: no Elsa Microlink at %#lx\n", + cs->hw.elsa.base); + return (0); + } + } else + cs->hw.elsa.base = probe_elsa(cs); + if (cs->hw.elsa.base) { + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + val = bytein(cs->hw.elsa.cfg); + if (cs->subtyp == ELSA_PC) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; + } else if (cs->subtyp == ELSA_PCC8) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; + } else { + const u_char CARD_IrqTab[8] = + {15, 10, 15, 3, 11, 5, 11, 9}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; + } + val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; + if (val < 3) + val |= 8; + val += 'A' - 3; + if (val == 'B' || val == 'C') + val ^= 1; + if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) + val = 'C'; + printk(KERN_INFO + "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + val, cs->irq); + val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; + if (val) { + printk(KERN_WARNING + "Elsa: Microlink S0 bus power bad\n"); + cs->hw.elsa.status |= ELSA_BAD_PWR; + } + } else { + printk(KERN_WARNING + "No Elsa Microlink found\n"); + return (0); + } + } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; - - while(pdev->card_vendor) { - if ((pb = pnp_find_card(pdev->card_vendor, - pdev->card_device, - pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - pdev->vendor, - pdev->function, - pd))) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + printk(KERN_INFO "HiSax: %s detected\n", - (char *)pdev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "Elsa PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - pnp_device_detach(pd); - printk(KERN_ERR "Elsa PnP: activate failed\n"); - return 0; + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_port_valid(pd, 0) || - !pnp_irq_valid(pd, 0)) { + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); - if (pdev->function == ISAPNP_FUNCTION(0x133)) { - if (elsa_qs1000_probe(card->cs, card)) - return 0; - return 1; - } else { - if (elsa_qs3000_probe(card->cs, card)) - return 0; - return 1; - } + if (ipid->function == ISAPNP_FUNCTION(0x133)) + cs->subtyp = ELSA_QS1000; + else + cs->subtyp = ELSA_QS3000; break; } else { printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); return(0); } } - pdev++; + ipid++; pnp_c=NULL; } - if (!pdev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); return(0); } } #endif - if (elsa_qs1000_probe(card->cs, card)) - return 0; - return 1; - - } else if (card->typ == ISDN_CTYPE_ELSA_PCMCIA) { - if (elsa_pcmcia_probe(card->cs, card)) - return 0; - return 1; - } else if (card->typ == ISDN_CTYPE_ELSA_PCI) { -#ifdef CONFIG_PCI + if (card->para[1] && card->para[0]) { + cs->hw.elsa.base = card->para[1]; + cs->irq = card->para[0]; + if (!cs->subtyp) + cs->subtyp = ELSA_QS1000; + } else { + printk(KERN_ERR "Elsa PnP: no parameter\n"); + } + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); + } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) { + cs->hw.elsa.base = card->para[1]; + cs->irq = card->para[0]; + val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); + if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ + cs->subtyp = ELSA_PCMCIA_IPAC; + cs->hw.elsa.ale = cs->hw.elsa.base + 0; + cs->hw.elsa.isac = cs->hw.elsa.base + 2; + cs->hw.elsa.hscx = cs->hw.elsa.base + 2; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = ELSA_PCMCIA; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + } + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->hw.elsa.ctrl = 0; + cs->irq_flags |= SA_SHIRQ; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); + } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { +#if CONFIG_PCI + cs->subtyp = 0; if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (elsa_qs_pci_probe(card->cs, dev_qs1000, - ELSA_QS1000PCI)) - return 0; - return 1; + if (pci_enable_device(dev_qs1000)) + return(0); + cs->subtyp = ELSA_QS1000PCI; + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (elsa_qs_pci_probe(card->cs, dev_qs3000, - ELSA_QS3000PCI)) - return 0; - return 1; + if (pci_enable_device(dev_qs3000)) + return(0); + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); } else { printk(KERN_WARNING "Elsa: No PCI card found\n"); - return 0; + return(0); + } + if (!cs->irq) { + printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + return(0); + } + + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { + printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); + return(0); + } + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); } + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->irq_flags |= SA_SHIRQ; + printk(KERN_INFO + "Elsa: %s defined at %#lx/0x%x IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->hw.elsa.cfg, + cs->irq); +#else + printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n"); + printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n"); + return (0); #endif /* CONFIG_PCI */ + } else + return (0); + + switch (cs->subtyp) { + case ELSA_PC: + case ELSA_PCC8: + case ELSA_PCC16: + case ELSA_QS1000: + case ELSA_PCMCIA: + case ELSA_PCMCIA_IPAC: + bytecnt = 8; + break; + case ELSA_PCFPRO: + case ELSA_PCF: + case ELSA_QS3000: + case ELSA_QS3000PCI: + bytecnt = 16; + break; + case ELSA_QS1000PCI: + bytecnt = 2; + break; + default: + printk(KERN_WARNING + "Unknown ELSA subtype %d\n", cs->subtyp); + return (0); + } + /* In case of the elsa pcmcia card, this region is in use, + reserved for us by the card manager. So we do not check it + here, it would fail. */ + if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %#lx-%#lx already in use\n", + CardType[card->typ], + cs->hw.elsa.base, + cs->hw.elsa.base + bytecnt); + return (0); + } + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { + if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { + printk(KERN_WARNING + "HiSax: %s pci port %x-%x already in use\n", + CardType[card->typ], + cs->hw.elsa.cfg, + cs->hw.elsa.cfg + 0x80); + release_region(cs->hw.elsa.base, bytecnt); + return (0); + } + } +#if ARCOFI_USE + init_arcofi(cs); +#endif + setup_isac(cs); + cs->hw.elsa.tl.function = (void *) elsa_led_handler; + cs->hw.elsa.tl.data = (long) cs; + init_timer(&cs->hw.elsa.tl); + /* Teste Timer */ + if (cs->hw.elsa.timer) { + byteout(cs->hw.elsa.trig, 0xff); + byteout(cs->hw.elsa.timer, 0); + if (!TimerRun(cs)) { + byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */ + if (!TimerRun(cs)) { + printk(KERN_WARNING + "Elsa: timer do not start\n"); + release_io_elsa(cs); + return (0); + } + } + HZDELAY((HZ/100) + 1); /* wait >=10 ms */ + if (TimerRun(cs)) { + printk(KERN_WARNING "Elsa: timer do not run down\n"); + release_io_elsa(cs); + return (0); + } + printk(KERN_INFO "Elsa: timer OK; resetting card\n"); + } + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Elsa_card_msg; + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &elsa_interrupt_ipac; + val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID); + printk(KERN_INFO "Elsa: IPAC version %x\n", val); + } else { + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->irq_func = &elsa_interrupt; + ISACVersion(cs, "Elsa:"); + if (HscxVersion(cs, "Elsa:")) { + printk(KERN_WARNING + "Elsa: wrong HSCX versions check IO address\n"); + release_io_elsa(cs); + return (0); + } + } + if (cs->subtyp == ELSA_PC) { + val = readitac(cs, ITAC_SYS); + printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); + writeitac(cs, ITAC_ISEN, 0); + writeitac(cs, ITAC_RFIE, 0); + writeitac(cs, ITAC_XFIE, 0); + writeitac(cs, ITAC_SCIE, 0); + writeitac(cs, ITAC_STIE, 0); } - return 0; + return (1); } diff -puN drivers/isdn/hisax/elsa_cs.c~i4l drivers/isdn/hisax/elsa_cs.c --- 25/drivers/isdn/hisax/elsa_cs.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/elsa_cs.c 2004-02-09 22:19:20.000000000 -0800 @@ -53,6 +53,7 @@ #include #include #include +#include "hisax_cfg.h" MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards"); MODULE_AUTHOR("Klaus Lichtenwalder"); @@ -71,7 +72,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); static char *version = -"elsa_cs.c $Revision: 1.1.2.2 $ $Date: 2001/09/23 22:24:47 $ (K.Lichtenwalder)"; +"elsa_cs.c $Revision: 1.2.2.4 $ $Date: 2004/01/25 15:07:06 $ (K.Lichtenwalder)"; #else #define DEBUG(n, args...) #endif @@ -93,8 +94,6 @@ MODULE_PARM(irq_list, "1-4i"); static int protocol = 2; /* EURO-ISDN Default */ MODULE_PARM(protocol, "i"); -extern int elsa_init_pcmcia(int, int, int*, int); - /*====================================================================*/ /* @@ -168,6 +167,7 @@ typedef struct local_info_t { dev_link_t link; dev_node_t node; int busy; + int cardnr; } local_info_t; /*====================================================================== @@ -188,7 +188,6 @@ static dev_link_t *elsa_cs_attach(void) dev_link_t *link; local_info_t *local; int ret, i; - void elsa_interrupt(int, void *, struct pt_regs *); DEBUG(0, "elsa_cs_attach()\n"); @@ -196,6 +195,7 @@ static dev_link_t *elsa_cs_attach(void) local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) return NULL; memset(local, 0, sizeof(local_info_t)); + local->cardnr = -1; link = &local->link; link->priv = local; /* Interrupt setup */ @@ -337,6 +337,7 @@ static void elsa_cs_config(dev_link_t *l int i, j, last_fn; u_short buf[128]; cistpl_cftable_entry_t *cf = &parse.cftable_entry; + IsdnCard_t icard; DEBUG(0, "elsa_config(0x%p)\n", link); handle = link->handle; @@ -430,9 +431,19 @@ static void elsa_cs_config(dev_link_t *l link->state &= ~DEV_CONFIG_PENDING; - elsa_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ, - &(((local_info_t*)link->priv)->busy), - protocol); + icard.para[0] = link->irq.AssignedIRQ; + icard.para[1] = link->io.BasePort1; + icard.protocol = protocol; + icard.typ = ISDN_CTYPE_ELSA_PCMCIA; + + i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard); + if (i < 0) { + printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#x\n", + i, link->io.BasePort1); + elsa_cs_release(link); + } else + ((local_info_t*)link->priv)->cardnr = i; + return; cs_failed: cs_error(link->handle, last_fn, i); @@ -449,9 +460,16 @@ cs_failed: static void elsa_cs_release(dev_link_t *link) { + local_info_t *local = link->priv; DEBUG(0, "elsa_cs_release(0x%p)\n", link); + if (local) { + if (local->cardnr >= 0) { + /* no unregister function with hisax */ + HiSax_closecard(local->cardnr); + } + } /* Unlink the device chain */ link->dev = NULL; diff -puN drivers/isdn/hisax/elsa_ser.c~i4l drivers/isdn/hisax/elsa_ser.c --- 25/drivers/isdn/hisax/elsa_ser.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/elsa_ser.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: elsa_ser.c,v 2.10.6.4 2001/09/23 22:24:47 kai Exp $ +/* $Id: elsa_ser.c,v 2.14.2.2 2004/01/12 22:52:26 keil Exp $ * * stuff for the serial modem on ELSA cards * @@ -26,11 +26,10 @@ //#define SERIAL_DEBUG_REG 1 #ifdef SERIAL_DEBUG_REG -static u8 deb[32]; +static u_char deb[32]; const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"}; const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"}; #endif -static spinlock_t elsa_ser_lock = SPIN_LOCK_UNLOCKED; static char *MInit_1 = "AT&F&C1E0&D2\r\0"; static char *MInit_2 = "ATL2M1S64=13\r\0"; @@ -111,7 +110,6 @@ static void change_speed(struct IsdnCard int quot = 0, baud_base; unsigned cval, fcr = 0; int bits; - unsigned long flags; /* byte size and parity */ @@ -135,23 +133,17 @@ static void change_speed(struct IsdnCard serial_outp(cs, UART_IER, cs->hw.elsa.IER); debugl1(cs,"modem quot=0x%x", quot); - spin_lock_irqsave(&elsa_ser_lock, flags); serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */ serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */ serial_outp(cs, UART_LCR, cval); /* reset DLAB */ serial_inp(cs, UART_RX); - spin_unlock_irqrestore(&elsa_ser_lock, flags); } static int mstartup(struct IsdnCardState *cs) { - unsigned long flags; int retval=0; - - spin_lock_irqsave(&elsa_ser_lock, flags); - /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) @@ -207,7 +199,6 @@ static int mstartup(struct IsdnCardState change_speed(cs, BASE_BAUD); cs->hw.elsa.MFlag = 1; errout: - spin_unlock_irqrestore(&elsa_ser_lock, flags); return retval; } @@ -217,15 +208,11 @@ errout: */ static void mshutdown(struct IsdnCardState *cs) { - unsigned long flags; - #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG"Shutting down serial ...."); #endif - spin_lock_irqsave(&elsa_ser_lock, flags); /* Disable interrupts */ - /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up @@ -245,7 +232,6 @@ static void mshutdown(struct IsdnCardSta serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); serial_inp(cs, UART_RX); /* read data port to reset things */ - spin_unlock_irqrestore(&elsa_ser_lock, flags); #ifdef SERIAL_DEBUG_OPEN printk(" done\n"); #endif @@ -255,14 +241,12 @@ inline int write_modem(struct BCState *bcs) { int ret=0; struct IsdnCardState *cs = bcs->cs; - u_int count, len, fp; - unsigned long flags; + int count, len, fp; if (!bcs->tx_skb) return 0; if (bcs->tx_skb->len <= 0) return 0; - spin_lock_irqsave(&elsa_ser_lock, flags); len = bcs->tx_skb->len; if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt) len = MAX_MODEM_BUF - cs->hw.elsa.transcnt; @@ -288,14 +272,33 @@ write_modem(struct BCState *bcs) { cs->hw.elsa.IER |= UART_IER_THRI; serial_outp(cs, UART_IER, cs->hw.elsa.IER); } - spin_unlock_irqrestore(&elsa_ser_lock, flags); return(ret); } -static void -modem_fill(struct BCState *bcs) -{ - xmit_xpr_b(bcs); +inline void +modem_fill(struct BCState *bcs) { + + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + write_modem(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, + bcs->hw.hscx.count); + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + write_modem(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } } static inline void receive_chars(struct IsdnCardState *cs, @@ -329,7 +332,7 @@ static inline void receive_chars(struct cs->hw.elsa.rcvcnt); skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb); } - sched_b_event(cs->hw.elsa.bcs, B_RCVBUFREADY); + schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY); } else { char tmp[128]; char *t = tmp; @@ -375,6 +378,7 @@ static inline void transmit_chars(struct } } + static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs) { int status, iir, msr; @@ -419,10 +423,10 @@ close_elsastate(struct BCState *bcs) { modehscx(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->rcvbuf) { + if (bcs->hw.hscx.rcvbuf) { if (bcs->mode != L1_MODE_MODEM) - kfree(bcs->rcvbuf); - bcs->rcvbuf = NULL; + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; } skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); @@ -435,16 +439,13 @@ close_elsastate(struct BCState *bcs) } void -modem_write_cmd(struct IsdnCardState *cs, u8 *buf, u_int len) { - u_int count, fp; - u8 *msg = buf; - unsigned long flags; +modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { + int count, fp; + u_char *msg = buf; if (!len) return; - spin_lock_irqsave(&elsa_ser_lock, flags); if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) { - spin_unlock_irqrestore(&elsa_ser_lock, flags); return; } fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; @@ -465,16 +466,13 @@ modem_write_cmd(struct IsdnCardState *cs cs->hw.elsa.IER |= UART_IER_THRI; serial_outp(cs, UART_IER, cs->hw.elsa.IER); } - spin_unlock_irqrestore(&elsa_ser_lock, flags); } void modem_set_init(struct IsdnCardState *cs) { - unsigned long flags; int timeout; #define RCV_DELAY 20000 - spin_lock_irqsave(&elsa_ser_lock, flags); modem_write_cmd(cs, MInit_1, strlen(MInit_1)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) @@ -517,16 +515,13 @@ modem_set_init(struct IsdnCardState *cs) udelay(1000); debugl1(cs, "msi tout=%d", timeout); udelay(RCV_DELAY); - spin_unlock_irqrestore(&elsa_ser_lock, flags); } void modem_set_dial(struct IsdnCardState *cs, int outgoing) { - unsigned long flags; int timeout; #define RCV_DELAY 20000 - spin_lock_irqsave(&elsa_ser_lock, flags); modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) @@ -542,40 +537,39 @@ modem_set_dial(struct IsdnCardState *cs, udelay(1000); debugl1(cs, "msi tout=%d", timeout); udelay(RCV_DELAY); - spin_unlock_irqrestore(&elsa_ser_lock, flags); } void modem_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; - unsigned long flags; + u_long flags; if (pr == (PH_DATA | REQUEST)) { - spin_lock_irqsave(&elsa_ser_lock, flags); - if (st->l1.bcs->tx_skb) { - skb_queue_tail(&st->l1.bcs->squeue, skb); - spin_unlock_irqrestore(&elsa_ser_lock, flags); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); } else { - st->l1.bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - st->l1.bcs->count = 0; - spin_unlock_irqrestore(&elsa_ser_lock, flags); - write_modem(st->l1.bcs); + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->hw.hscx.count = 0; + write_modem(bcs); } + spin_unlock_irqrestore(&bcs->cs->lock, flags); } else if (pr == (PH_ACTIVATE | REQUEST)) { - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - L1L2(st, PH_ACTIVATE | CONFIRM, NULL); - set_arcofi(st->l1.bcs->cs, st->l1.bc); - mstartup(st->l1.bcs->cs); - modem_set_dial(st->l1.bcs->cs, test_bit(FLG_ORIG, &st->l2.flag)); - st->l1.bcs->cs->hw.elsa.MFlag=2; + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); + set_arcofi(bcs->cs, st->l1.bc); + mstartup(bcs->cs); + modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag)); + bcs->cs->hw.elsa.MFlag=2; } else if (pr == (PH_DEACTIVATE | REQUEST)) { - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - st->l1.bcs->cs->dc.isac.arcofi_bc = st->l1.bc; - arcofi_fsm(st->l1.bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); - interruptible_sleep_on(&st->l1.bcs->cs->dc.isac.arcofi_wait); - st->l1.bcs->cs->hw.elsa.MFlag=1; + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + bcs->cs->dc.isac.arcofi_bc = st->l1.bc; + arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); + interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait); + bcs->cs->hw.elsa.MFlag=1; } else { printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr); } @@ -591,24 +585,22 @@ setstack_elsa(struct PStack *st, struct case L1_MODE_TRANS: if (open_hscxstate(st->l1.hardware, bcs)) return (-1); - st->l1.l2l1 = hscx_l2l1; - // bcs->cs->BC_Send_Data = hscx_fill_fifo; FIXME + st->l2.l2l1 = hscx_l2l1; break; case L1_MODE_MODEM: bcs->mode = L1_MODE_MODEM; if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - bcs->rcvbuf = bcs->cs->hw.elsa.rcvbuf; + bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf; skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; - bcs->rcvidx = 0; + bcs->hw.hscx.rcvidx = 0; bcs->tx_cnt = 0; bcs->cs->hw.elsa.bcs = bcs; - st->l1.l2l1 = modem_l2l1; -// bcs->cs->bc_l1_ops = &modem_l1_ops; + st->l2.l2l1 = modem_l2l1; break; } st->l1.bcs = bcs; @@ -618,17 +610,13 @@ setstack_elsa(struct PStack *st, struct return (0); } -static struct bc_l1_ops modem_l1_ops = { - .fill_fifo = modem_fill, - .open = setstack_elsa, - .close = close_elsastate, -}; - void -init_modem(struct IsdnCardState *cs) -{ - cs->bc_l1_ops = &modem_l1_ops; +init_modem(struct IsdnCardState *cs) { + cs->bcs[0].BC_SetStack = setstack_elsa; + cs->bcs[1].BC_SetStack = setstack_elsa; + cs->bcs[0].BC_Close = close_elsastate; + cs->bcs[1].BC_Close = close_elsastate; if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF, GFP_ATOMIC))) { printk(KERN_WARNING diff -puN drivers/isdn/hisax/enternow.h~i4l drivers/isdn/hisax/enternow.h --- 25/drivers/isdn/hisax/enternow.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/enternow.h 2004-02-09 22:19:20.000000000 -0800 @@ -40,3 +40,12 @@ * den TigerJet i/o-Raum gemappt * -> 0x01 des AMD bei hw.njet.base + 0C4 */ #define TJ_AMD_PORT 0xC0 + + + +/* ***************************************************************************************** * + * *************************************** Prototypen ************************************** * + * ***************************************************************************************** */ + +BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset); +void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value); diff -puN drivers/isdn/hisax/enternow_pci.c~i4l drivers/isdn/hisax/enternow_pci.c --- 25/drivers/isdn/hisax/enternow_pci.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/enternow_pci.c 2004-02-09 22:19:20.000000000 -0800 @@ -74,13 +74,14 @@ -const char *enternow_pci_rev = "$Revision: 1.1.2.1 $"; +const char *enternow_pci_rev = "$Revision: 1.1.4.5 $"; + /* *************************** I/O-Interface functions ************************************* */ /* cs->readisac, macro rByteAMD */ -static BYTE +BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset) { /* direktes Register */ @@ -95,7 +96,7 @@ ReadByteAmd7930(struct IsdnCardState *cs } /* cs->writeisac, macro wByteAMD */ -static void +void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value) { /* direktes Register */ @@ -110,14 +111,8 @@ WriteByteAmd7930(struct IsdnCardState *c } -static struct dc_hw_ops amd7930_ops = { - .read_reg = ReadByteAmd7930, - .write_reg = WriteByteAmd7930, -}; - -static void -enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) -{ +void +enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) { if (!val) OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00); else @@ -125,6 +120,17 @@ enpci_setIrqMask(struct IsdnCardState *c } +static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value) +{ + +} + + /* ******************************************************************************** */ @@ -137,15 +143,12 @@ reset_enpci(struct IsdnCardState *cs) /* Reset on, (also for AMD) */ cs->hw.njet.ctrl_reg = 0x07; OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - /* 80 ms delay */ - schedule_timeout((80*HZ)/1000); + mdelay(20); /* Reset off */ - cs->hw.njet.ctrl_reg = 0x70; + cs->hw.njet.ctrl_reg = 0x30; OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - /* 80ms delay */ - schedule_timeout((80*HZ)/1000); + /* 20ms delay */ + mdelay(20); cs->hw.njet.auxd = 0; // LED-status cs->hw.njet.dmactrl = 0; OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); @@ -153,96 +156,124 @@ reset_enpci(struct IsdnCardState *cs) OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off } -static void -enpci_bc_activate(struct IsdnCardState *cs, int chan) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", chan); - - cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (chan + 1)), "MDL_BC_ASSIGN"); - /* at least one b-channel in use, LED 2 on */ - cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; - OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); -} -static void -enpci_bc_deactivate(struct IsdnCardState *cs, int chan) +static int +enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", chan); - - cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(chan + 1)), "MDL_BC_RELEASE"); - /* no b-channel active -> LED2 off */ - if (!(cs->dc.amd7930.lmr1 & 3)) { - cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); - OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); - } -} + u_long flags; + BYTE *chan; -static void -enpci_led_handler(struct IsdnCardState *cs) -{ - if (cs->status & 0x0001) { - /* TEI assigned, LED1 on */ - cs->hw.njet.auxd = TJ_AMD_IRQ << 1; - OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); - } else { - /* TEI removed, LEDs off */ - cs->hw.njet.auxd = 0; - OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00); - } -} + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt); -static void -enpci_init(struct IsdnCardState *cs) -{ - inittiger(cs); - Amd7930_init(cs); -} + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_enpci(cs); + Amd7930_init(cs); + spin_unlock_irqrestore(&cs->lock, flags); + break; + case CARD_RELEASE: + release_io_netjet(cs); + break; + case CARD_INIT: + reset_enpci(cs); + inittiger(cs); + /* irq must be on here */ + Amd7930_init(cs); + break; + case CARD_TEST: + break; + case MDL_ASSIGN: + /* TEI assigned, LED1 on */ + cs->hw.njet.auxd = TJ_AMD_IRQ << 1; + OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); + break; + case MDL_REMOVE: + /* TEI removed, LEDs off */ + cs->hw.njet.auxd = 0; + OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00); + break; + case MDL_BC_ASSIGN: + /* activate B-channel */ + chan = (BYTE *)arg; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan); + + cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN"); + /* at least one b-channel in use, LED 2 on */ + cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; + OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); + break; + case MDL_BC_RELEASE: + /* deactivate B-channel */ + chan = (BYTE *)arg; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan); + + cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE"); + /* no b-channel active -> LED2 off */ + if (!(cs->dc.amd7930.lmr1 & 3)) { + cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); + OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); + } + break; + default: + break; -static int -enpci_reset(struct IsdnCardState *cs) -{ - reset_enpci(cs); - Amd7930_init(cs); - return 0; + } + return(0); } static irqreturn_t enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - BYTE sval, ir; - - spin_lock(&cs->lock); + BYTE s0val, s1val, ir; + u_long flags; - sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1); + spin_lock_irqsave(&cs->lock, flags); + s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1); /* AMD threw an interrupt */ - if (!(sval & TJ_AMD_IRQ)) { + if (!(s1val & TJ_AMD_IRQ)) { /* read and clear interrupt-register */ ir = ReadByteAmd7930(cs, 0x00); Amd7930_interrupt(cs, ir); - } + s1val = 1; + } else + s1val = 0; + s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0); + if ((s0val | s1val)==0) { // shared IRQ + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; + } + if (s0val) + OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); /* DMA-Interrupt: B-channel-stuff */ /* set bits in sval to indicate which page is free */ - - /* set bits in sval to indicate which page is free */ if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) /* the 2nd write page is free */ - sval = 0x08; + s0val = 0x08; else /* the 1st write page is free */ - sval = 0x04; + s0val = 0x04; if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) /* the 2nd read page is free */ - sval = sval | 0x02; + s0val = s0val | 0x02; else /* the 1st read page is free */ - sval = sval | 0x01; - if (sval != cs->hw.njet.last_is0) { /* we have a DMA interrupt */ - cs->hw.njet.irqstat0 = sval; + s0val = s0val | 0x01; + if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ + { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; + } + cs->hw.njet.irqstat0 = s0val; if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) /* we have a read dma int */ @@ -251,71 +282,12 @@ enpci_interrupt(int intno, void *dev_id, (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) /* we have a write dma int */ write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } - spin_unlock(&cs->lock); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static struct card_ops enpci_ops = { - .init = enpci_init, - .reset = enpci_reset, - .release = netjet_release, - .led_handler = enpci_led_handler, - .irq_func = enpci_interrupt, -}; - -static int __init -enpci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.njet.base = pci_resource_start(pdev, 0); - if (!request_io(&cs->rs, cs->hw.njet.base, 0x100, "Fn_ISDN")) - goto err; - - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD - - /* Reset an */ - cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff - OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - - set_current_state(TASK_UNINTERRUPTIBLE); - /* 50 ms Pause */ - schedule_timeout((50*HZ)/1000); - - cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */ - OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - - cs->hw.njet.auxd = 0x00; // war 0xc0 - cs->hw.njet.dmactrl = 0; - - OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); - OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ); - OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); - - printk(KERN_INFO - "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - reset_enpci(cs); - cs->hw.njet.last_is0 = 0; - cs->hw.njet.bc_activate = enpci_bc_activate; - cs->hw.njet.bc_deactivate = enpci_bc_deactivate; - amd7930_setup(cs, &amd7930_ops, &enpci_setIrqMask); - - cs->card_ops = &enpci_ops; - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} static struct pci_dev *dev_netjet __initdata = NULL; @@ -323,30 +295,105 @@ static struct pci_dev *dev_netjet __init int __init setup_enternow_pci(struct IsdnCard *card) { + int bytecnt; + struct IsdnCardState *cs = card->cs; char tmp[64]; +#if CONFIG_PCI #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif strcpy(tmp, enternow_pci_rev); printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp)); - - dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet); - if (dev_netjet) { - if (dev_netjet->subsystem_vendor != 0x55 || - dev_netjet->subsystem_device != 0x02) { - printk(KERN_WARNING "enter:now: You tried to load " - "this driver with an incompatible " - "TigerJet-card\n"); - printk(KERN_WARNING "Use type=20 for Traverse " - "NetJet PCI Card.\n"); - return 0; + if (cs->typ != ISDN_CTYPE_ENTERNOW) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n"); + return(0); + } + /* checks Sub-Vendor ID because system crashes with Traverse-Card */ + if ((dev_netjet->subsystem_vendor != 0x55) || + (dev_netjet->subsystem_device != 0x02)) { + printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n"); + printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n"); + return(0); + } + } else { + printk(KERN_WARNING "enter:now PCI: No PCI card found\n"); + return(0); } - if (enpci_probe(card->cs, dev_netjet)) - return 1; - return 0; + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD + + /* Reset an */ + cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff + OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + /* 20 ms Pause */ + mdelay(20); + + cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */ + OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + mdelay(10); + + cs->hw.njet.auxd = 0x00; // war 0xc0 + cs->hw.njet.dmactrl = 0; + + OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); + OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ); + OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); + + break; + } +#else + + printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n"); + printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) { + printk(KERN_WARNING + "HiSax: %s config port %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); } - printk(KERN_WARNING "enter:now PCI: No PCI card found\n"); - return 0; + setup_Amd7930(cs); + cs->hw.njet.last_is0 = 0; + /* macro rByteAMD */ + cs->readisac = &ReadByteAmd7930; + /* macro wByteAMD */ + cs->writeisac = &WriteByteAmd7930; + cs->dc.amd7930.setIrqMask = &enpci_setIrqMask; + + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &enpci_card_msg; + cs->irq_func = &enpci_interrupt; + cs->irq_flags |= SA_SHIRQ; + + return (1); } diff -puN drivers/isdn/hisax/gazel.c~i4l drivers/isdn/hisax/gazel.c --- 25/drivers/isdn/hisax/gazel.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/gazel.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: gazel.c,v 2.11.6.7 2001/09/23 22:24:47 kai Exp $ +/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $ * * low level stuff for Gazel isdn cards * @@ -21,8 +21,7 @@ #include extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.11.6.7 $"; -static spinlock_t gazel_lock = SPIN_LOCK_UNLOCKED; +const char *gazel_revision = "$Revision: 2.19.2.4 $"; #define R647 1 #define R685 2 @@ -44,492 +43,642 @@ static spinlock_t gazel_lock = SPIN_LOCK #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static inline u8 +static inline u_char readreg(unsigned int adr, u_short off) { return bytein(adr + off); } static inline void -writereg(unsigned int adr, u_short off, u8 data) +writereg(unsigned int adr, u_short off, u_char data) { byteout(adr + off, data); } static inline void -read_fifo(unsigned int adr, u8 * data, int size) +read_fifo(unsigned int adr, u_char * data, int size) { insb(adr, data, size); } static void -write_fifo(unsigned int adr, u8 * data, int size) +write_fifo(unsigned int adr, u_char * data, int size) { outsb(adr, data, size); } -static u8 -r685_isac_read(struct IsdnCardState *cs, u8 off) +static inline u_char +readreg_ipac(unsigned int adr, u_short off) { - return readreg(cs->hw.gazel.isac, off); -} + register u_char ret; -static u8 -r647_isac_read(struct IsdnCardState *cs, u8 off) -{ - return readreg(cs->hw.gazel.isac, (off << 8 & 0xf000) | (off & 0xf)); + byteout(adr, off); + ret = bytein(adr + 4); + return ret; } -static void -r685_isac_write(struct IsdnCardState *cs, u8 off, u8 value) +static inline void +writereg_ipac(unsigned int adr, u_short off, u_char data) { - writereg(cs->hw.gazel.isac, off, value); + byteout(adr, off); + byteout(adr + 4, data); } -static void -r647_isac_write(struct IsdnCardState *cs, u8 off, u8 value) -{ - writereg(cs->hw.gazel.isac, (off << 8 & 0xf000) | (off & 0xf), value); -} -static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +static inline void +read_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size) { - read_fifo(cs->hw.gazel.isacfifo, data, size); + byteout(adr, off); + insb(adr + 4, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +write_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size) { - write_fifo(cs->hw.gazel.isacfifo, data, size); + byteout(adr, off); + outsb(adr + 4, data, size); } -static struct dc_hw_ops r685_isac_ops = { - .read_reg = r685_isac_read, - .write_reg = r685_isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; +/* Interface functions */ -static struct dc_hw_ops r647_isac_ops = { - .read_reg = r647_isac_read, - .write_reg = r647_isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -r685_hscx_read(struct IsdnCardState *cs, int hscx, u8 off) +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs->hw.gazel.hscx[hscx], off); + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + return (readreg(cs->hw.gazel.isac, off2)); + case R753: + case R742: + return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2)); + } + return 0; } -static u8 -r647_hscx_read(struct IsdnCardState *cs, int hscx, u8 off) +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - return readreg(cs->hw.gazel.hscx[hscx], - (off << 8 & 0xf000) | (off & 0xf)); + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + writereg(cs->hw.gazel.isac, off2, value); + break; + case R753: + case R742: + writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value); + break; + } } static void -r685_hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 value) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writereg(cs->hw.gazel.hscx[hscx], off, value); + switch (cs->subtyp) { + case R647: + case R685: + read_fifo(cs->hw.gazel.isacfifo, data, size); + break; + case R753: + case R742: + read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); + break; + } } static void -r647_hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 value) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writereg(cs->hw.gazel.hscx[hscx], - (off << 8 & 0xf000) | (off & 0xf), value); + switch (cs->subtyp) { + case R647: + case R685: + write_fifo(cs->hw.gazel.isacfifo, data, size); + break; + case R753: + case R742: + write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); + break; + } } static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size) +ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) { - read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); + switch (cs->subtyp) { + case R647: + case R685: + read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); + break; + case R753: + case R742: + read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); + break; + } } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size) +WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) { - write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); + switch (cs->subtyp) { + case R647: + case R685: + write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); + break; + case R753: + case R742: + write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); + break; + } } -static struct bc_hw_ops r685_hscx_ops = { - .read_reg = r685_hscx_read, - .write_reg = r685_hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static struct bc_hw_ops r647_hscx_ops = { - .read_reg = r647_hscx_read, - .write_reg = r647_hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static inline u8 -ipac_read(struct IsdnCardState *cs, u_short off) -{ - register u8 ret; - unsigned long flags; - - spin_lock_irqsave(&gazel_lock, flags); - byteout(cs->hw.gazel.ipac, off); - ret = bytein(cs->hw.gazel.ipac + 4); - spin_unlock_irqrestore(&gazel_lock, flags); - return ret; +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + return (readreg(cs->hw.gazel.hscx[hscx], off2)); + case R753: + case R742: + return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2)); + } + return 0; } -static inline void -ipac_write(struct IsdnCardState *cs, u_short off, u8 data) +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - unsigned long flags; + u_short off2 = offset; - spin_lock_irqsave(&gazel_lock, flags); - byteout(cs->hw.gazel.ipac, off); - byteout(cs->hw.gazel.ipac + 4, data); - spin_unlock_irqrestore(&gazel_lock, flags); + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + writereg(cs->hw.gazel.hscx[hscx], off2, value); + break; + case R753: + case R742: + writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value); + break; + } } +/* + * fast interrupt HSCX stuff goes here + */ -static inline void -ipac_readfifo(struct IsdnCardState *cs, u8 off, u8 * data, int size) -{ - byteout(cs->hw.gazel.ipac, off); - insb(cs->hw.gazel.ipac + 4, data, size); +#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ +#define MAXCOUNT 5 + struct IsdnCardState *cs = dev_id; + u_char valisac, valhscx; + int count = 0; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + do { + valhscx = ReadHSCX(cs, 1, HSCX_ISTA); + if (valhscx) + hscx_int_main(cs, valhscx); + valisac = ReadISAC(cs, ISAC_ISTA); + if (valisac) + isac_interrupt(cs, valisac); + count++; + } while ((valhscx || valisac) && (count < MAXCOUNT)); + + WriteHSCX(cs, 0, HSCX_MASK, 0xFF); + WriteHSCX(cs, 1, HSCX_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0x0); + WriteHSCX(cs, 0, HSCX_MASK, 0x0); + WriteHSCX(cs, 1, HSCX_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } -static inline void -ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 * data, int size) -{ - byteout(cs->hw.gazel.ipac, off); - outsb(cs->hw.gazel.ipac + 4, data, size); -} -/* This will generate ipac_dc_ops and ipac_bc_ops using the functions - * above */ +static irqreturn_t +gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val; + int count = 0; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + ista = ReadISAC(cs, IPAC_ISTA - 0x80); + do { + if (ista & 0x0f) { + val = ReadHSCX(cs, 1, HSCX_ISTA); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) { + hscx_int_main(cs, val); + } + } + if (ista & 0x20) { + val = 0xfe & ReadISAC(cs, ISAC_ISTA); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = ReadISAC(cs, IPAC_ISTA - 0x80); + count++; + } + while ((ista & 0x3f) && (count < MAXCOUNT)); -BUILD_IPAC_OPS(ipac); + WriteISAC(cs, IPAC_MASK - 0x80, 0xFF); + WriteISAC(cs, IPAC_MASK - 0x80, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} +void +release_io_gazel(struct IsdnCardState *cs) +{ + unsigned int i; + + switch (cs->subtyp) { + case R647: + for (i = 0x0000; i < 0xC000; i += 0x1000) + release_region(i + cs->hw.gazel.hscx[0], 16); + release_region(0xC000 + cs->hw.gazel.hscx[0], 1); + break; -static int -r647_reset(struct IsdnCardState *cs) -{ - writereg(cs->hw.gazel.cfg_reg, 0, 0); - HZDELAY(10); - writereg(cs->hw.gazel.cfg_reg, 0, 1); - HZDELAY(2); - return 0; + case R685: + release_region(cs->hw.gazel.hscx[0], 0x100); + release_region(cs->hw.gazel.cfg_reg, 0x80); + break; + + case R753: + release_region(cs->hw.gazel.ipac, 0x8); + release_region(cs->hw.gazel.cfg_reg, 0x80); + break; + + case R742: + release_region(cs->hw.gazel.ipac, 8); + break; + } } static int -r685_reset(struct IsdnCardState *cs) +reset_gazel(struct IsdnCardState *cs) { unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; - plxcntrl = inl(addr + PLX_CNTRL); - plxcntrl |= (RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - plxcntrl &= ~(RESET_9050 + RESET_GAZEL); - HZDELAY(4); - outl(plxcntrl, addr + PLX_CNTRL); - HZDELAY(10); - outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR); - return 0; + switch (cs->subtyp) { + case R647: + writereg(addr, 0, 0); + HZDELAY(10); + writereg(addr, 0, 1); + HZDELAY(2); + break; + case R685: + plxcntrl = inl(addr + PLX_CNTRL); + plxcntrl |= (RESET_9050 + RESET_GAZEL); + outl(plxcntrl, addr + PLX_CNTRL); + plxcntrl &= ~(RESET_9050 + RESET_GAZEL); + HZDELAY(4); + outl(plxcntrl, addr + PLX_CNTRL); + HZDELAY(10); + outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR); + break; + case R753: + plxcntrl = inl(addr + PLX_CNTRL); + plxcntrl |= (RESET_9050 + RESET_GAZEL); + outl(plxcntrl, addr + PLX_CNTRL); + plxcntrl &= ~(RESET_9050 + RESET_GAZEL); + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); + HZDELAY(4); + outl(plxcntrl, addr + PLX_CNTRL); + HZDELAY(10); + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); + WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); + WriteISAC(cs, IPAC_AOE - 0x80, 0x0); + WriteISAC(cs, IPAC_MASK - 0x80, 0xff); + WriteISAC(cs, IPAC_CONF - 0x80, 0x1); + outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR); + WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); + break; + case R742: + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); + HZDELAY(4); + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); + WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); + WriteISAC(cs, IPAC_AOE - 0x80, 0x0); + WriteISAC(cs, IPAC_MASK - 0x80, 0xff); + WriteISAC(cs, IPAC_CONF - 0x80, 0x1); + WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); + break; + } + return (0); } static int -r753_reset(struct IsdnCardState *cs) +Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; + u_long flags; - if (test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags)) - /* we can't read, assume the default */ - plxcntrl = 0x18784db6; - else - plxcntrl = inl(addr + PLX_CNTRL); - plxcntrl |= (RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - ipac_write(cs, IPAC_POTA2, 0x20); - HZDELAY(4); - plxcntrl &= ~(RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - HZDELAY(10); - ipac_write(cs, IPAC_POTA2, 0x00); - ipac_write(cs, IPAC_ACFG, 0xff); - ipac_write(cs, IPAC_AOE, 0x0); - ipac_write(cs, IPAC_MASK, 0xff); - ipac_write(cs, IPAC_CONF, 0x1); - outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR); - ipac_write(cs, IPAC_MASK, 0xc0); - return 0; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_gazel(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_RELEASE: + release_io_gazel(cs); + return (0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 1); + if ((cs->subtyp==R647)||(cs->subtyp==R685)) { + int i; + for (i=0;i<(2+MAX_WAITING_CALLS);i++) { + cs->bcs[i].hw.hscx.tsaxr0 = 0x1f; + cs->bcs[i].hw.hscx.tsaxr1 = 0x23; + } + } + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_TEST: + return (0); + } + return (0); } static int -r742_reset(struct IsdnCardState *cs) +reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs) { - ipac_write(cs, IPAC_POTA2, 0x20); - HZDELAY(4); - ipac_write(cs, IPAC_POTA2, 0x00); - ipac_write(cs, IPAC_ACFG, 0xff); - ipac_write(cs, IPAC_AOE, 0x0); - ipac_write(cs, IPAC_MASK, 0xff); - ipac_write(cs, IPAC_CONF, 0x1); - ipac_write(cs, IPAC_MASK, 0xc0); - return 0; -} + unsigned int i, j, base = 0, adr = 0, len = 0; -static void -gazel_init(struct IsdnCardState *cs) -{ - int i; + switch (cs->subtyp) { + case R647: + base = cs->hw.gazel.hscx[0]; + if (!request_region(adr = (0xC000 + base), len = 1, "gazel")) + goto error; + for (i = 0x0000; i < 0xC000; i += 0x1000) { + if (!request_region(adr = (i + base), len = 16, "gazel")) + goto error; + } + if (i != 0xC000) { + for (j = 0; j < i; j+= 0x1000) + release_region(j + base, 16); + release_region(0xC000 + base, 1); + goto error; + } + break; + + case R685: + if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel")) + goto error; + if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { + release_region(cs->hw.gazel.hscx[0],0x100); + goto error; + } + break; - for (i = 0; i < 2; i++) { - cs->bcs[i].hw.hscx.tsaxr0 = 0x1f; - cs->bcs[i].hw.hscx.tsaxr1 = 0x23; - } - inithscxisac(cs); -} - -static struct card_ops r647_ops = { - .init = gazel_init, - .reset = r647_reset, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - -static struct card_ops r685_ops = { - .init = gazel_init, - .reset = r685_reset, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - -static struct card_ops r742_ops = { - .init = ipac_init, - .reset = r742_reset, - .release = hisax_release_resources, - .irq_func = ipac_irq, -}; - -static struct card_ops r753_ops = { - .init = ipac_init, - .reset = r753_reset, - .release = hisax_release_resources, - .irq_func = ipac_irq, -}; + case R753: + if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) + goto error; + if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { + release_region(cs->hw.gazel.ipac, 8); + goto error; + } + break; + + case R742: + if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) + goto error; + break; + } + + return 0; + + error: + printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n", + CardType[cs->typ], adr, adr + len); + return 1; +} static int __init -gazel647_probe(struct IsdnCardState *cs, struct IsdnCard *card) +setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) { - int i, base; + printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n"); + // we got an irq parameter, assume it is an ISA card + // R742 decodes address even in not started... + // R647 returns FF if not present or not started + // eventually needs improvment + if (readreg_ipac(card->para[1], IPAC_ID) == 1) + cs->subtyp = R742; + else + cs->subtyp = R647; - cs->subtyp = R647; - cs->irq = card->para[0]; + setup_isac(cs); cs->hw.gazel.cfg_reg = card->para[1] + 0xC000; - - printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n"); - cs->dc.isac.adf2 = 0x87; - printk(KERN_INFO "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); - printk(KERN_INFO - "Gazel: hscx A:0x%X hscx B:0x%X\n", - cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - + cs->hw.gazel.ipac = card->para[1]; cs->hw.gazel.isac = card->para[1] + 0x8000; cs->hw.gazel.hscx[0] = card->para[1]; cs->hw.gazel.hscx[1] = card->para[1] + 0x4000; + cs->irq = card->para[0]; cs->hw.gazel.isacfifo = cs->hw.gazel.isac; cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; - base = cs->hw.gazel.hscx[0]; - for (i = 0; i < 0xc000; i += 0x1000) { - if (!request_io(&cs->rs, base + i, 16, "gazel")) - goto err; - } - if (!request_io(&cs->rs, 0xc000 + base, 1, "gazel")) - goto err; - - cs->card_ops = &r647_ops; - if (hscxisac_setup(cs, &r647_isac_ops, &r647_hscx_ops)) - goto err; - - cs->card_ops->reset(cs); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -gazel742_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = R742; - cs->irq = card->para[0]; - cs->hw.gazel.cfg_reg = card->para[1] + 0xC000; + switch (cs->subtyp) { + case R647: + printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n"); + cs->dc.isac.adf2 = 0x87; + printk(KERN_INFO + "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", + cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); + printk(KERN_INFO + "Gazel: hscx A:0x%X hscx B:0x%X\n", + cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - printk(KERN_INFO "Gazel: Card ISA R742 found\n"); - printk(KERN_INFO "Gazel: config irq:%d ipac:0x%X\n", - cs->irq, cs->hw.gazel.ipac); - - if (!request_io(&cs->rs, cs->hw.gazel.ipac, 0x8, "gazel")) - goto err; - - cs->card_ops = &r742_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; + break; + case R742: + printk(KERN_INFO "Gazel: Card ISA R742 found\n"); + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + printk(KERN_INFO + "Gazel: config irq:%d ipac:0x%X\n", + cs->irq, cs->hw.gazel.ipac); + break; + } - cs->card_ops->reset(cs); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return (0); } +static struct pci_dev *dev_tel __initdata = NULL; + static int __init -gazel685_probe(struct IsdnCardState *cs, struct pci_dev *pdev) +setup_gazelpci(struct IsdnCardState *cs) { - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = R685; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.gazel.cfg_reg = pci_resource_start(pdev, 1); - cs->hw.gazel.isac = pci_resource_start(pdev, 2) + 0x80; - cs->hw.gazel.hscx[0] = pci_resource_start(pdev, 2); - cs->hw.gazel.hscx[1] = pci_resource_start(pdev, 2) + 0x40; - cs->hw.gazel.isacfifo = cs->hw.gazel.isac; + u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0; + u_char pci_irq = 0, found; + u_int nbseek, seekcard; + + printk(KERN_WARNING "Gazel: PCI card automatic recognition\n"); + + found = 0; + seekcard = PCI_DEVICE_ID_PLX_R685; + for (nbseek = 0; nbseek < 3; nbseek++) { + if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) { + if (pci_enable_device(dev_tel)) + return 1; + pci_irq = dev_tel->irq; + pci_ioaddr0 = pci_resource_start(dev_tel, 1); + pci_ioaddr1 = pci_resource_start(dev_tel, 2); + found = 1; + } + if (found) + break; + else { + switch (seekcard) { + case PCI_DEVICE_ID_PLX_R685: + seekcard = PCI_DEVICE_ID_PLX_R753; + break; + case PCI_DEVICE_ID_PLX_R753: + seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; + break; + } + } + } + if (!found) { + printk(KERN_WARNING "Gazel: No PCI card found\n"); + return (1); + } + if (!pci_irq) { + printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n"); + return 1; + } + cs->hw.gazel.pciaddr[0] = pci_ioaddr0; + cs->hw.gazel.pciaddr[1] = pci_ioaddr1; + setup_isac(cs); + pci_ioaddr1 &= 0xfffe; + cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe; + cs->hw.gazel.ipac = pci_ioaddr1; + cs->hw.gazel.isac = pci_ioaddr1 + 0x80; + cs->hw.gazel.hscx[0] = pci_ioaddr1; + cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40; + cs->hw.gazel.isacfifo = cs->hw.gazel.isac; cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; - cs->dc.isac.adf2 = 0x87; - - if (!request_io(&cs->rs, cs->hw.gazel.hscx[0], 0x100, "gazel")) - goto err; - if (!request_io(&cs->rs, cs->hw.gazel.cfg_reg, 0x80, "gazel")) - goto err; - - printk(KERN_INFO "Gazel: Card PCI R685 found\n"); - printk(KERN_INFO "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); - printk(KERN_INFO "Gazel: hscx A:0x%X hscx B:0x%X\n", - cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - - cs->card_ops = &r685_ops; - if (hscxisac_setup(cs, &r685_isac_ops, &r685_hscx_ops)) - goto err; + cs->irq = pci_irq; + cs->irq_flags |= SA_SHIRQ; - cs->card_ops->reset(cs); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -gazel753_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - u8 pci_rev; - - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = R753; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.gazel.cfg_reg = pci_resource_start(pdev, 1); - cs->hw.gazel.ipac = pci_resource_start(pdev, 2); - - if (!request_io(&cs->rs, cs->hw.gazel.ipac, 0x8, "gazel")) - goto err; - if (!request_io(&cs->rs, cs->hw.gazel.cfg_reg, 0x80, "gazel")) - goto err; - - printk(KERN_INFO "Gazel: Card PCI R753 found\n"); - printk(KERN_INFO "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg); - /* - * Erratum for PLX9050, revision 1: - * If bit 7 of BAR 0/1 is set, local config registers - * can not be read (write is okay) - */ - if (cs->hw.gazel.cfg_reg & 0x80) { - pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); - if (pci_rev == 1) { - printk(KERN_INFO "Gazel: PLX9050 rev1 workaround " - "activated\n"); - __set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags); - } + switch (seekcard) { + case PCI_DEVICE_ID_PLX_R685: + printk(KERN_INFO "Gazel: Card PCI R685 found\n"); + cs->subtyp = R685; + cs->dc.isac.adf2 = 0x87; + printk(KERN_INFO + "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", + cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); + printk(KERN_INFO + "Gazel: hscx A:0x%X hscx B:0x%X\n", + cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); + break; + case PCI_DEVICE_ID_PLX_R753: + case PCI_DEVICE_ID_PLX_DJINN_ITOO: + printk(KERN_INFO "Gazel: Card PCI R753 found\n"); + cs->subtyp = R753; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + printk(KERN_INFO + "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n", + cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg); + break; } - cs->card_ops = &r753_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - goto err; - cs->card_ops->reset(cs); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return (0); } -static struct pci_dev *dev_tel __initdata = NULL; -static u16 __initdata dev_id = PCI_DEVICE_ID_PLX_R685; - int __init setup_gazel(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; + u_char val; strcpy(tmp, gazel_revision); printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_GAZEL) + return (0); + if (card->para[0]) { - printk(KERN_INFO "Gazel: ISA card automatic recognition\n"); - // we got an irq parameter, assume it is an ISA card - // R742 decodes address even in not started... - // R647 returns FF if not present or not started - // eventually needs improvment - card->cs->hw.gazel.ipac = card->para[1]; - if (ipac_read(card->cs, IPAC_ID) == 1) { - if (gazel742_probe(card->cs, card)) - return 0; - } else { - if (gazel647_probe(card->cs, card)) - return 0; - } - return 1; + if (setup_gazelisa(card, cs)) + return (0); + } else { + +#if CONFIG_PCI + if (setup_gazelpci(cs)) + return (0); +#else + printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n"); + return (0); +#endif /* CONFIG_PCI */ } - for (;;) { - dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, dev_id, dev_tel); - if (dev_tel) { - switch (dev_id) { - case PCI_DEVICE_ID_PLX_R685: - if (gazel685_probe(card->cs, dev_tel)) - return 0; - return 1; - case PCI_DEVICE_ID_PLX_R753: - case PCI_DEVICE_ID_PLX_DJINN_ITOO: - if (gazel753_probe(card->cs, dev_tel)) - return 0; - return 1; + if (reserve_regions(card, cs)) { + return (0); + } + if (reset_gazel(cs)) { + printk(KERN_WARNING "Gazel: wrong IRQ\n"); + release_io_gazel(cs); + return (0); + } + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Gazel_card_msg; + + switch (cs->subtyp) { + case R647: + case R685: + cs->irq_func = &gazel_interrupt; + ISACVersion(cs, "Gazel:"); + if (HscxVersion(cs, "Gazel:")) { + printk(KERN_WARNING + "Gazel: wrong HSCX versions check IO address\n"); + release_io_gazel(cs); + return (0); } - } - switch (dev_id) { - case PCI_DEVICE_ID_PLX_R685: - dev_id = PCI_DEVICE_ID_PLX_R753; - case PCI_DEVICE_ID_PLX_R753: - dev_id = PCI_DEVICE_ID_PLX_DJINN_ITOO; - default: break; - } + case R742: + case R753: + cs->irq_func = &gazel_interrupt_ipac; + val = ReadISAC(cs, IPAC_ID - 0x80); + printk(KERN_INFO "Gazel: IPAC version %x\n", val); + break; } - printk(KERN_WARNING "Gazel: No PCI card found\n"); - return 0; -} - + return (1); +} diff -puN drivers/isdn/hisax/hfc_2bds0.c~i4l drivers/isdn/hisax/hfc_2bds0.c --- 25/drivers/isdn/hisax/hfc_2bds0.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_2bds0.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.15.6.3 2001/09/23 22:24:47 kai Exp $ +/* $Id: hfc_2bds0.c,v 1.18.2.5 2004/01/19 15:31:50 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -23,10 +23,16 @@ #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static inline u8 -ReadReg(struct IsdnCardState *cs, int data, u8 reg) +static void +dummyf(struct IsdnCardState *cs, u_char * data, int size) +{ + printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n"); +} + +static inline u_char +ReadReg(struct IsdnCardState *cs, int data, u_char reg) { - register u8 ret; + register u_char ret; if (data) { if (cs->hw.hfcD.cip != reg) { @@ -44,7 +50,7 @@ ReadReg(struct IsdnCardState *cs, int da } static inline void -WriteReg(struct IsdnCardState *cs, int data, u8 reg, u8 value) +WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value) { if (cs->hw.hfcD.cip != reg) { cs->hw.hfcD.cip = reg; @@ -58,31 +64,20 @@ WriteReg(struct IsdnCardState *cs, int d #endif } -static struct bc_hw_ops hfcs_bc_ops = { - .read_reg = ReadReg, - .write_reg = WriteReg, -}; - /* Interface functions */ -static inline u8 -hfcs_read_reg(struct IsdnCardState *cs, u8 offset) +static u_char +readreghfcd(struct IsdnCardState *cs, u_char offset) { - return ReadReg(cs, HFCD_DATA, offset); + return(ReadReg(cs, HFCD_DATA, offset)); } -static inline void -hfcs_write_reg(struct IsdnCardState *cs, u8 offset, u8 value) +static void +writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value) { WriteReg(cs, HFCD_DATA, offset, value); } -void -set_cs_func(struct IsdnCardState *cs) -{ - cs->bc_hw_ops = &hfcs_bc_ops; -} - static inline int WaitForBusy(struct IsdnCardState *cs) { @@ -112,13 +107,12 @@ WaitNoBusy(struct IsdnCardState *cs) } static int -SelFiFo(struct IsdnCardState *cs, u8 FiFo) +SelFiFo(struct IsdnCardState *cs, u_char FiFo) { - u8 cip; + u_char cip; if (cs->hw.hfcD.fifo == FiFo) return(1); - switch(FiFo) { case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1; break; @@ -138,10 +132,11 @@ SelFiFo(struct IsdnCardState *cs, u8 FiF } cs->hw.hfcD.fifo = FiFo; WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA, cip, 0); + cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0); WaitForBusy(cs); return(2); } + static int GetFreeFifoBytes_B(struct BCState *bcs) { @@ -171,7 +166,7 @@ GetFreeFifoBytes_D(struct IsdnCardState } static int -ReadZReg(struct IsdnCardState *cs, u8 reg) +ReadZReg(struct IsdnCardState *cs, u_char reg) { int val; @@ -185,12 +180,12 @@ ReadZReg(struct IsdnCardState *cs, u8 re static struct sk_buff *hfc_empty_fifo(struct BCState *bcs, int count) { - u8 *ptr; + u_char *ptr; struct sk_buff *skb; struct IsdnCardState *cs = bcs->cs; int idx; int chksum; - u8 stat, cip; + u_char stat, cip; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); @@ -264,10 +259,9 @@ static void hfc_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - u_int idx; - int fcnt; - u_int count; - u8 cip; + int idx, fcnt; + int count; + u_char cip; if (!bcs->tx_skb) return; @@ -320,7 +314,11 @@ hfc_fill_fifo(struct BCState *bcs) printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { bcs->tx_cnt -= bcs->tx_skb->len; - xmit_complete_b(bcs); + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; } WaitForBusy(cs); WaitNoBusy(cs); @@ -330,17 +328,33 @@ hfc_fill_fifo(struct BCState *bcs) return; } +static void +hfc_send_data(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs,"send_data %d blocked", bcs->channel); +} + void main_rec_2bds0(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; int z1, z2, rcnt; - u8 f1, f2, cip; + u_char f1, f2, cip; int receive, count = 5; struct sk_buff *skb; Begin: count--; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs,"rec_data %d blocked", bcs->channel); + return; + } SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel)); cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel); WaitNoBusy(cs); @@ -363,7 +377,7 @@ main_rec_2bds0(struct BCState *bcs) bcs->channel, z1, z2, rcnt); if ((skb = hfc_empty_fifo(bcs, rcnt))) { skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); } rcnt = f1 -f2; if (rcnt<0) @@ -374,6 +388,7 @@ main_rec_2bds0(struct BCState *bcs) receive = 0; } else receive = 0; + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && receive) goto Begin; return; @@ -430,31 +445,57 @@ mode_2bs0(struct BCState *bcs, int mode, static void hfc_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; +// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); + } else { +// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + mode_2bs0(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - mode_2bs0(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + mode_2bs0(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -495,7 +536,7 @@ setstack_2b(struct PStack *st, struct BC if (open_hfcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = hfc_l2l1; + st->l2.l2l1 = hfc_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -503,11 +544,8 @@ setstack_2b(struct PStack *st, struct BC } static void -hfcd_bh(void *data) +hfcd_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; -/* struct PStack *stptr; -*/ if (!cs) return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { @@ -543,18 +581,22 @@ int receive_dmsg(struct IsdnCardState *c struct sk_buff *skb; int idx; int rcnt, z1, z2; - u8 stat, cip, f1, f2; + u_char stat, cip, f1, f2; int chksum; int count=5; - u8 *ptr; + u_char *ptr; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_dmsg blocked"); + return(1); + } SelFiFo(cs, 4 | HFCD_REC); cip = HFCD_FIFO | HFCD_F1 | HFCD_REC; WaitNoBusy(cs); - f1 = hfcs_read_reg(cs, cip) & 0xf; + f1 = cs->readisac(cs, cip) & 0xf; cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; WaitNoBusy(cs); - f2 = hfcs_read_reg(cs, cip) & 0xf; + f2 = cs->readisac(cs, cip) & 0xf; while ((f1 != f2) && count--) { z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC); z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC); @@ -617,7 +659,7 @@ int receive_dmsg(struct IsdnCardState *c #endif } else { skb_queue_tail(&cs->rq, skb); - sched_d_event(cs, D_RCVBUFREADY); + schedule_event(cs, D_RCVBUFREADY); } } } else @@ -629,17 +671,18 @@ int receive_dmsg(struct IsdnCardState *c WaitForBusy(cs); cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; WaitNoBusy(cs); - f2 = hfcs_read_reg(cs, cip) & 0xf; + f2 = cs->readisac(cs, cip) & 0xf; } + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); return(1); } static void hfc_fill_dfifo(struct IsdnCardState *cs) { - int fcnt; - u_int idx, count; - u8 cip; + int idx, fcnt; + int count; + u_char cip; if (!cs->tx_skb) return; @@ -711,26 +754,31 @@ struct BCState *Sel_BCS(struct IsdnCardS } void -hfc2bds0_interrupt(struct IsdnCardState *cs, u8 val) +hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) { - u8 exval; + u_char exval; struct BCState *bcs; int count=15; if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCD irq %x", val); - + debugl1(cs, "HFCD irq %x %s", val, + test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? + "locked" : "unlocked"); val &= cs->hw.hfcD.int_m1; if (val & 0x40) { /* TE state machine irq */ - exval = hfcs_read_reg(cs, HFCD_STATES) & 0xf; + exval = cs->readisac(cs, HFCD_STATES) & 0xf; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state, exval); cs->dc.hfcd.ph_state = exval; - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); val &= ~0x40; } while (val) { + if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + cs->hw.hfcD.int_s1 |= val; + return; + } if (cs->hw.hfcD.int_s1 & 0x18) { exval = val; val = cs->hw.hfcD.int_s1; @@ -755,7 +803,23 @@ hfc2bds0_interrupt(struct IsdnCardState if (cs->debug) debugl1(cs, "hfcd spurious 0x01 IRQ"); } else { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); + } else { + schedule_event(bcs, B_XMTBUFREADY); + } + } } } if (val & 0x02) { @@ -763,15 +827,60 @@ hfc2bds0_interrupt(struct IsdnCardState if (cs->debug) debugl1(cs, "hfcd spurious 0x02 IRQ"); } else { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); + } else { + schedule_event(bcs, B_XMTBUFREADY); + } + } } } if (val & 0x20) { /* receive dframe */ receive_dmsg(cs); } if (val & 0x04) { /* dframe transmitted */ - xmit_xpr_d(cs); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfc_fill_dfifo irq blocked"); + } + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfc_fill_dfifo irq blocked"); + } + } else + schedule_event(cs, D_XMTBUFREADY); } + afterXPR: if (cs->hw.hfcD.int_s1 && count--) { val = cs->hw.hfcD.int_s1; cs->hw.hfcD.int_s1 = 0; @@ -787,36 +896,101 @@ HFCD_l1hw(struct PStack *st, int pr, voi { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfc_fill_dfifo blocked"); + + } + spin_unlock_irqrestore(&cs->lock, flags); break; - case (PH_PULL |INDICATION): - xmit_pull_ind_d(cs, skb); + case (PH_PULL | INDICATION): + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfc_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfc_fill_dfifo blocked"); + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): - hfcs_write_reg(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ + spin_lock_irqsave(&cs->lock, flags); + cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); - hfcs_write_reg(cs, HFCD_STATES, 3); /* HFC ST 2 */ + cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */ cs->hw.hfcD.mst_m |= HFCD_MASTER; - hfcs_write_reg(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - hfcs_write_reg(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); + cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); + spin_unlock_irqrestore(&cs->lock, flags); l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (HW_ENABLE | REQUEST): - hfcs_write_reg(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); + spin_lock_irqsave(&cs->lock, flags); + cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_DEACTIVATE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcD.mst_m &= ~HFCD_MASTER; - hfcs_write_reg(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcD.mst_m |= HFCD_MASTER; - hfcs_write_reg(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); break; default: if (cs->debug & L1_DEB_WARN) @@ -825,11 +999,10 @@ HFCD_l1hw(struct PStack *st, int pr, voi } } -static int +void setstack_hfcd(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = HFCD_l1hw; - return 0; } static void @@ -852,30 +1025,21 @@ unsigned int __init return(send); } -static struct bc_l1_ops hfcd_bc_l1_ops = { - .fill_fifo = hfc_fill_fifo, - .open = setstack_2b, - .close = close_2bs0, -}; - -static struct dc_l1_ops hfcd_dc_l1_ops = { - .fill_fifo = hfc_fill_dfifo, - .open = setstack_hfcd, - .bh_func = hfcd_bh, - .dbusy_func = hfc_dbusy_timer, -}; - void __init init2bds0(struct IsdnCardState *cs) { - dc_l1_init(cs, &hfcd_dc_l1_ops); - cs->bc_l1_ops = &hfcd_bc_l1_ops; + cs->setstack_d = setstack_hfcd; if (!cs->hw.hfcD.send) cs->hw.hfcD.send = init_send_hfcd(16); if (!cs->bcs[0].hw.hfc.send) cs->bcs[0].hw.hfc.send = init_send_hfcd(32); if (!cs->bcs[1].hw.hfc.send) cs->bcs[1].hw.hfc.send = init_send_hfcd(32); + cs->BC_Send_Data = &hfc_send_data; + cs->bcs[0].BC_SetStack = setstack_2b; + cs->bcs[1].BC_SetStack = setstack_2b; + cs->bcs[0].BC_Close = close_2bs0; + cs->bcs[1].BC_Close = close_2bs0; mode_2bs0(cs->bcs, 0, 0); mode_2bs0(cs->bcs + 1, 0, 1); } @@ -896,3 +1060,18 @@ release2bds0(struct IsdnCardState *cs) cs->hw.hfcD.send = NULL; } } + +void +set_cs_func(struct IsdnCardState *cs) +{ + cs->readisac = &readreghfcd; + cs->writeisac = &writereghfcd; + cs->readisacfifo = &dummyf; + cs->writeisacfifo = &dummyf; + cs->BC_Read_Reg = &ReadReg; + cs->BC_Write_Reg = &WriteReg; + cs->dbusytimer.function = (void *) hfc_dbusy_timer; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + INIT_WORK(&cs->tqueue, (void *)(void *) hfcd_bh, cs); +} diff -puN drivers/isdn/hisax/hfc_2bds0.h~i4l drivers/isdn/hisax/hfc_2bds0.h --- 25/drivers/isdn/hisax/hfc_2bds0.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_2bds0.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.h,v 1.4.6.2 2001/09/23 22:24:47 kai Exp $ +/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $ * * specific defines for CCD's HFC 2BDS0 * @@ -124,5 +124,5 @@ extern void main_irq_2bds0(struct BCState *bcs); extern void init2bds0(struct IsdnCardState *cs); extern void release2bds0(struct IsdnCardState *cs); -extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u8 val); +extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val); extern void set_cs_func(struct IsdnCardState *cs); diff -puN drivers/isdn/hisax/hfc_2bs0.c~i4l drivers/isdn/hisax/hfc_2bs0.c --- 25/drivers/isdn/hisax/hfc_2bs0.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_2bs0.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.17.6.3 2001/09/23 22:24:47 kai Exp $ +/* $Id: hfc_2bs0.c,v 1.20.2.5 2004/01/19 15:31:50 keil Exp $ * * specific routines for CCD's HFC 2BS0 * @@ -17,26 +17,14 @@ #include "isdnl1.h" #include -static inline u8 -hfc_read_reg(struct IsdnCardState *cs, int data, u8 reg) -{ - return cs->bc_hw_ops->read_reg(cs, data, reg); -} - -static inline void -hfc_write_reg(struct IsdnCardState *cs, int data, u8 reg, u8 val) -{ - cs->bc_hw_ops->write_reg(cs, data, reg, val); -} - static inline int WaitForBusy(struct IsdnCardState *cs) { int to = 130; - u8 val; + u_char val; - while (!(hfc_read_reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { - val = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2 | + while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { + val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 | (cs->hw.hfc.cip & 3)); udelay(1); to--; @@ -53,7 +41,7 @@ WaitNoBusy(struct IsdnCardState *cs) { int to = 125; - while ((hfc_read_reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { + while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { udelay(1); to--; } @@ -79,14 +67,14 @@ GetFreeFifoBytes(struct BCState *bcs) } int -ReadZReg(struct BCState *bcs, u8 reg) +ReadZReg(struct BCState *bcs, u_char reg) { int val; WaitNoBusy(bcs->cs); - val = 256 * hfc_read_reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH); + val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH); WaitNoBusy(bcs->cs); - val += hfc_read_reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW); + val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW); return (val); } @@ -96,21 +84,20 @@ hfc_clear_fifo(struct BCState *bcs) struct IsdnCardState *cs = bcs->cs; int idx, cnt; int rcnt, z1, z2; - u8 cip, f1, f2; + u_char cip, f1, f2; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_clear_fifo"); - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - hfc_write_reg(cs, HFC_STATUS, cip, cip); + cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); WaitForBusy(cs); } WaitNoBusy(cs); - f1 = hfc_read_reg(cs, HFC_DATA, cip); + f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); - f2 = hfc_read_reg(cs, HFC_DATA, cip); + f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); cnt = 32; @@ -129,21 +116,21 @@ hfc_clear_fifo(struct BCState *bcs) cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); idx = 0; while ((idx < rcnt) && WaitNoBusy(cs)) { - hfc_read_reg(cs, HFC_DATA_NODEB, cip); + cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } if (f1 != f2) { WaitNoBusy(cs); - hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); } cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); - f1 = hfc_read_reg(cs, HFC_DATA, cip); + f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); - f2 = hfc_read_reg(cs, HFC_DATA, cip); + f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); } @@ -155,12 +142,12 @@ static struct sk_buff * hfc_empty_fifo(struct BCState *bcs, int count) { - u8 *ptr; + u_char *ptr; struct sk_buff *skb; struct IsdnCardState *cs = bcs->cs; int idx; int chksum; - u8 stat, cip; + u_char stat, cip; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); @@ -170,9 +157,9 @@ hfc_empty_fifo(struct BCState *bcs, int debugl1(cs, "hfc_empty_fifo: incoming packet too large"); cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx++ < count) && WaitNoBusy(cs)) - hfc_read_reg(cs, HFC_DATA_NODEB, cip); + cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); WaitNoBusy(cs); - stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); return (NULL); @@ -182,9 +169,9 @@ hfc_empty_fifo(struct BCState *bcs, int debugl1(cs, "hfc_empty_fifo: incoming packet too small"); cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx++ < count) && WaitNoBusy(cs)) - hfc_read_reg(cs, HFC_DATA_NODEB, cip); + cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); WaitNoBusy(cs); - stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); #ifdef ERROR_STATISTIC @@ -203,7 +190,7 @@ hfc_empty_fifo(struct BCState *bcs, int idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx < count) && WaitNoBusy(cs)) { - *ptr++ = hfc_read_reg(cs, HFC_DATA_NODEB, cip); + *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } if (idx != count) { @@ -212,7 +199,7 @@ hfc_empty_fifo(struct BCState *bcs, int dev_kfree_skb_any(skb); if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); - stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); } @@ -220,11 +207,11 @@ hfc_empty_fifo(struct BCState *bcs, int } if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); - chksum = (hfc_read_reg(cs, HFC_DATA, cip) << 8); + chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8); WaitNoBusy(cs); - chksum += hfc_read_reg(cs, HFC_DATA, cip); + chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); WaitNoBusy(cs); - stat = hfc_read_reg(cs, HFC_DATA, cip); + stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); @@ -237,7 +224,7 @@ hfc_empty_fifo(struct BCState *bcs, int #endif } WaitNoBusy(cs); - stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); } @@ -249,10 +236,10 @@ static void hfc_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - int fcnt; - u_int idx, count; + int idx, fcnt; + int count; int z1, z2; - u8 cip; + u_char cip; if (!bcs->tx_skb) return; @@ -261,15 +248,15 @@ hfc_fill_fifo(struct BCState *bcs) cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel); if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - hfc_write_reg(cs, HFC_STATUS, cip, cip); + cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); WaitForBusy(cs); } WaitNoBusy(cs); if (bcs->mode != L1_MODE_TRANS) { - bcs->hw.hfc.f1 = hfc_read_reg(cs, HFC_DATA, cip); + bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); - bcs->hw.hfc.f2 = hfc_read_reg(cs, HFC_DATA, cip); + bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", @@ -305,7 +292,7 @@ hfc_fill_fifo(struct BCState *bcs) cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel); idx = 0; while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs)) - hfc_write_reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); + cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); if (idx != bcs->tx_skb->len) { debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); @@ -314,13 +301,15 @@ hfc_fill_fifo(struct BCState *bcs) bcs->tx_cnt -= count; if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; - - xmit_complete_b(bcs); + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; if (bcs->mode != L1_MODE_TRANS) { WaitForBusy(cs); WaitNoBusy(cs); - hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); + cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); } + if (bcs->st->lli.l1writewakeup && (count >= 0)) + bcs->st->lli.l1writewakeup(bcs->st, count); test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } return; @@ -331,7 +320,7 @@ main_irq_hfc(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; int z1, z2, rcnt; - u8 f1, f2, cip; + u_char f1, f2, cip; int receive, transmit, count = 5; struct sk_buff *skb; @@ -339,16 +328,16 @@ main_irq_hfc(struct BCState *bcs) count--; cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - hfc_write_reg(cs, HFC_STATUS, cip, cip); + cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); WaitForBusy(cs); } WaitNoBusy(cs); receive = 0; if (bcs->mode == L1_MODE_HDLC) { - f1 = hfc_read_reg(cs, HFC_DATA, cip); + f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); - f2 = hfc_read_reg(cs, HFC_DATA, cip); + f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); if (f1 != f2) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc rec %d f1(%d) f2(%d)", @@ -368,14 +357,14 @@ main_irq_hfc(struct BCState *bcs) if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); + /* sti(); */ if ((skb = hfc_empty_fifo(bcs, rcnt))) { skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); } } receive = 1; } - udelay(1); if (bcs->tx_skb) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); @@ -391,7 +380,7 @@ main_irq_hfc(struct BCState *bcs) transmit = 0; } else { transmit = 0; - sched_b_event(bcs, B_XMTBUFREADY); + schedule_event(bcs, B_XMTBUFREADY); } } if ((receive || transmit) && count) @@ -423,7 +412,7 @@ mode_hfc(struct BCState *bcs, int mode, break; case (L1_MODE_TRANS): cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */ - hfc_write_reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); + cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); hfc_clear_fifo(bcs); /* complete fifo clear */ if (bc) { cs->hw.hfc.ctmt |= 1; @@ -447,8 +436,8 @@ mode_hfc(struct BCState *bcs, int mode, } break; } - hfc_write_reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); - cs->dc_hw_ops->write_reg(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr); + cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); + cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr); if (mode == L1_MODE_HDLC) hfc_clear_fifo(bcs); } @@ -456,31 +445,57 @@ mode_hfc(struct BCState *bcs, int mode, static void hfc_l2l1(struct PStack *st, int pr, void *arg) { - struct sk_buff *skb = arg; + struct BCState *bcs = st->l1.bcs; + struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); + } else { + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + mode_hfc(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - mode_hfc(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + mode_hfc(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -523,7 +538,7 @@ setstack_hfc(struct PStack *st, struct B if (open_hfcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = hfc_l2l1; + st->l2.l2l1 = hfc_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -544,18 +559,16 @@ init_send(struct BCState *bcs) bcs->hw.hfc.send[i] = 0x1fff; } -static struct bc_l1_ops hfc_l1_ops = { - .fill_fifo = hfc_fill_fifo, - .open = setstack_hfc, - .close = close_hfcstate, -}; - void __init inithfc(struct IsdnCardState *cs) { init_send(&cs->bcs[0]); init_send(&cs->bcs[1]); - cs->bc_l1_ops = &hfc_l1_ops; + cs->BC_Send_Data = &hfc_fill_fifo; + cs->bcs[0].BC_SetStack = setstack_hfc; + cs->bcs[1].BC_SetStack = setstack_hfc; + cs->bcs[0].BC_Close = close_hfcstate; + cs->bcs[1].BC_Close = close_hfcstate; mode_hfc(cs->bcs, 0, 0); mode_hfc(cs->bcs + 1, 0, 0); } @@ -572,10 +585,3 @@ releasehfc(struct IsdnCardState *cs) cs->bcs[1].hw.hfc.send = NULL; } } - -int -hfc_setup(struct IsdnCardState *cs, struct bc_hw_ops *hfc_ops) -{ - cs->bc_hw_ops = hfc_ops; - return 0; -} diff -puN drivers/isdn/hisax/hfc_2bs0.h~i4l drivers/isdn/hisax/hfc_2bs0.h --- 25/drivers/isdn/hisax/hfc_2bs0.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_2bs0.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.h,v 1.3.6.2 2001/09/23 22:24:47 kai Exp $ +/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $ * * specific defines for CCD's HFC 2BS0 * @@ -58,4 +58,3 @@ extern void main_irq_hfc(struct BCState *bcs); extern void inithfc(struct IsdnCardState *cs); extern void releasehfc(struct IsdnCardState *cs); -extern int hfc_setup(struct IsdnCardState *cs, struct bc_hw_ops *hfc_ops); diff -puN drivers/isdn/hisax/hfc_pci.c~i4l drivers/isdn/hisax/hfc_pci.c --- 25/drivers/isdn/hisax/hfc_pci.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_pci.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.34.6.8 2001/09/23 22:24:47 kai Exp $ +/* $Id: hfc_pci.c,v 1.48.2.3 2004/01/13 14:31:25 keil Exp $ * * low level driver for CCD´s hfc-pci based cards * @@ -25,7 +25,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.34.6.8 $"; +static const char *hfcpci_revision = "$Revision: 1.48.2.3 $"; /* table entry in the PCI devices list */ typedef struct { @@ -65,45 +65,47 @@ static const PCI_ENTRY id_list[] = }; +#if CONFIG_PCI + /******************************************/ /* free hardware resources used by driver */ /******************************************/ -static void -hfcpci_release(struct IsdnCardState *cs) +void +release_io_hfcpci(struct IsdnCardState *cs) { printk(KERN_INFO "HiSax: release hfcpci at %p\n", cs->hw.hfcpci.pci_io); - cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ + cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ - Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - pci_disable_device(cs->hw.hfcpci.pdev); + Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ + mdelay(10); + Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ + mdelay(10); + Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); + pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ del_timer(&cs->hw.hfcpci.timer); - pci_free_consistent(cs->hw.hfcpci.pdev, 32768, cs->hw.hfcpci.fifos, cs->hw.hfcpci.fifos_dma); - hisax_release_resources(cs); + kfree(cs->hw.hfcpci.share_start); + cs->hw.hfcpci.share_start = NULL; + iounmap((void *)cs->hw.hfcpci.pci_io); } /********************************************************************************/ /* function called to reset the HFC PCI chip. A complete software reset of chip */ /* and fifos is done. */ /********************************************************************************/ -static int -hfcpci_reset(struct IsdnCardState *cs) +static void +reset_hfcpci(struct IsdnCardState *cs) { - pci_disable_device(cs->hw.hfcpci.pdev); + pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); printk(KERN_INFO "HFC_PCI: resetting card\n"); - pci_set_master(cs->hw.hfcpci.pdev); + pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ + mdelay(10); Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + mdelay(10); if (Read_hfc(cs, HFCPCI_STATUS) & 2) printk(KERN_WARNING "HFC-PCI init bit busy\n"); @@ -156,9 +158,7 @@ hfcpci_reset(struct IsdnCardState *cs) /* Finally enable IRQ output */ cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE; Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - if (Read_hfc(cs, HFCPCI_INT_S2)); - - return 0; + if (Read_hfc(cs, HFCPCI_INT_S1)); } /***************************************************/ @@ -174,6 +174,27 @@ hfcpci_Timer(struct IsdnCardState *cs) */ } + +/*********************************/ +/* schedule a new D-channel task */ +/*********************************/ +static void +sched_event_D_pci(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + schedule_work(&cs->tqueue); +} + +/*********************************/ +/* schedule a new b_channel task */ +/*********************************/ +static void +hfcpci_sched_event(struct BCState *bcs, int event) +{ + test_and_set_bit(event, &bcs->event); + schedule_work(&bcs->tqueue); +} + /************************************************/ /* select a b-channel entry matching and active */ /************************************************/ @@ -193,7 +214,7 @@ Sel_BCS(struct IsdnCardState *cs, int ch /* clear the desired B-channel rx fifo */ /***************************************/ static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo) -{ u8 fifo_state; +{ u_char fifo_state; bzfifo_type *bzr; if (fifo) { @@ -207,7 +228,7 @@ static void hfcpci_clear_fifo_rx(struct cs->hw.hfcpci.fifo_en ^= fifo_state; Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0; - bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); + bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; bzr->f1 = MAX_B_FRAMES; bzr->f2 = bzr->f1; /* init F pointers to remain constant */ @@ -220,7 +241,7 @@ static void hfcpci_clear_fifo_rx(struct /* clear the desired B-channel tx fifo */ /***************************************/ static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo) -{ u8 fifo_state; +{ u_char fifo_state; bzfifo_type *bzt; if (fifo) { @@ -233,7 +254,7 @@ static void hfcpci_clear_fifo_tx(struct if (fifo_state) cs->hw.hfcpci.fifo_en ^= fifo_state; Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); + bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; bzt->f1 = MAX_B_FRAMES; bzt->f2 = bzt->f1; /* init F pointers to remain constant */ @@ -247,9 +268,9 @@ static void hfcpci_clear_fifo_tx(struct /*********************************************/ static struct sk_buff * -hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u8 * bdata, int count) +hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int count) { - u8 *ptr, *ptr1, new_f2; + u_char *ptr, *ptr1, new_f2; struct sk_buff *skb; struct IsdnCardState *cs = bcs->cs; int total, maxlen, new_z2; @@ -258,18 +279,18 @@ hfcpci_empty_fifo(struct BCState *bcs, b if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfcpci_empty_fifo"); zp = &bz->za[bz->f2]; /* point to Z-Regs */ - new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */ + new_z2 = zp->z2 + count; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; if ((count > HSCX_BUFMAX + 3) || (count < 4) || - (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { + (*(bdata + (zp->z1 - B_SUB_VAL)))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); #ifdef ERROR_STATISTIC bcs->err_inv++; #endif - bz->za[new_f2].z2 = cpu_to_le16(new_z2); + bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ skb = NULL; } else if (!(skb = dev_alloc_skb(count - 3))) @@ -279,12 +300,12 @@ hfcpci_empty_fifo(struct BCState *bcs, b count -= 3; ptr = skb_put(skb, count); - if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) + if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL) maxlen = count; /* complete transfer */ else - maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2); /* maximum */ + maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ - ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); /* start of data */ + ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ memcpy(ptr, ptr1, maxlen); /* copy data */ count -= maxlen; @@ -293,7 +314,7 @@ hfcpci_empty_fifo(struct BCState *bcs, b ptr1 = bdata; /* start of buffer */ memcpy(ptr, ptr1, count); /* rest */ } - bz->za[new_f2].z2 = cpu_to_le16(new_z2); + bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ } @@ -311,41 +332,45 @@ receive_dmsg(struct IsdnCardState *cs) int maxlen; int rcnt, total; int count = 5; - u8 *ptr, *ptr1; + u_char *ptr, *ptr1; dfifo_type *df; z_type *zp; df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_dmsg blocked"); + return (1); + } while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { zp = &df->za[df->f2 & D_FREG_MASK]; - rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); + rcnt = zp->z1 - zp->z2; if (rcnt < 0) rcnt += D_FIFO_SIZE; rcnt++; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", - df->f1, df->f2, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); + df->f1, df->f2, zp->z1, zp->z2, rcnt); if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || - (df->data[le16_to_cpu(zp->z1)])) { + (df->data[zp->z1])) { if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[le16_to_cpu(zp->z1)]); + debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]); #ifdef ERROR_STATISTIC cs->err_rx++; #endif df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1)); + df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); } else if ((skb = dev_alloc_skb(rcnt - 3))) { total = rcnt; rcnt -= 3; ptr = skb_put(skb, rcnt); - if ((le16_to_cpu(zp->z2) + rcnt) <= D_FIFO_SIZE) + if (zp->z2 + rcnt <= D_FIFO_SIZE) maxlen = rcnt; /* complete transfer */ else - maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2); /* maximum */ + maxlen = D_FIFO_SIZE - zp->z2; /* maximum */ - ptr1 = df->data + le16_to_cpu(zp->z2); /* start of data */ + ptr1 = df->data + zp->z2; /* start of data */ memcpy(ptr, ptr1, maxlen); /* copy data */ rcnt -= maxlen; @@ -355,13 +380,14 @@ receive_dmsg(struct IsdnCardState *cs) memcpy(ptr, ptr1, rcnt); /* rest */ } df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); + df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1); skb_queue_tail(&cs->rq, skb); - sched_d_event(cs, D_RCVBUFREADY); + sched_event_D_pci(cs, D_RCVBUFREADY); } else printk(KERN_WARNING "HFC-PCI: D receive out of memory\n"); } + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); return (1); } @@ -369,17 +395,17 @@ receive_dmsg(struct IsdnCardState *cs) /* check for transparent receive data and read max one threshold size if avail */ /*******************************************************************************/ int -hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u8 * bdata) +hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata) { unsigned short *z1r, *z2r; int new_z2, fcnt, maxlen; struct sk_buff *skb; - u8 *ptr, *ptr1; + u_char *ptr, *ptr1; z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ z2r = z1r + 1; - if (!(fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r))) + if (!(fcnt = *z1r - *z2r)) return (0); /* no data avail */ if (fcnt <= 0) @@ -387,7 +413,7 @@ hfcpci_empty_fifo_trans(struct BCState * if (fcnt > HFCPCI_BTRANS_THRESHOLD) fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ - new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ + new_z2 = *z2r + fcnt; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ @@ -395,12 +421,12 @@ hfcpci_empty_fifo_trans(struct BCState * printk(KERN_WARNING "HFCPCI: receive out of memory\n"); else { ptr = skb_put(skb, fcnt); - if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) + if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL) maxlen = fcnt; /* complete transfer */ else - maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); /* maximum */ + maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */ - ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); /* start of data */ + ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */ memcpy(ptr, ptr1, maxlen); /* copy data */ fcnt -= maxlen; @@ -410,10 +436,10 @@ hfcpci_empty_fifo_trans(struct BCState * memcpy(ptr, ptr1, fcnt); /* rest */ } skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + hfcpci_sched_event(bcs, B_RCVBUFREADY); } - *z2r = cpu_to_le16(new_z2); /* new position */ + *z2r = new_z2; /* new position */ return (1); } /* hfcpci_empty_fifo_trans */ @@ -428,9 +454,10 @@ main_rec_hfcpci(struct BCState *bcs) int receive, count = 5; struct sk_buff *skb; bzfifo_type *bz; - u8 *bdata; + u_char *bdata; z_type *zp; + if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; @@ -442,22 +469,26 @@ main_rec_hfcpci(struct BCState *bcs) } Begin: count--; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_data %d blocked", bcs->channel); + return; + } if (bz->f1 != bz->f2) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)", bcs->channel, bz->f1, bz->f2); zp = &bz->za[bz->f2]; - rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); + rcnt = zp->z1 - zp->z2; if (rcnt < 0) rcnt += B_FIFO_SIZE; rcnt++; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); + bcs->channel, zp->z1, zp->z2, rcnt); if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) { skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + hfcpci_sched_event(bcs, B_RCVBUFREADY); } rcnt = bz->f1 - bz->f2; if (rcnt < 0) @@ -475,7 +506,7 @@ main_rec_hfcpci(struct BCState *bcs) receive = hfcpci_empty_fifo_trans(bcs, bz, bdata); else receive = 0; - + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && receive) goto Begin; return; @@ -487,10 +518,10 @@ main_rec_hfcpci(struct BCState *bcs) static void hfcpci_fill_dfifo(struct IsdnCardState *cs) { - int fcnt, new_z1, maxlen; - u_int count; + int fcnt; + int count, new_z1, maxlen; dfifo_type *df; - u8 *src, *dst, new_f1; + u_char *src, *dst, new_f1; if (!cs->tx_skb) return; @@ -502,7 +533,7 @@ hfcpci_fill_dfifo(struct IsdnCardState * if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)", df->f1, df->f2, - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1)); + df->za[df->f1 & D_FREG_MASK].z1); fcnt = df->f1 - df->f2; /* frame count actually buffered */ if (fcnt < 0) fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ @@ -515,7 +546,7 @@ hfcpci_fill_dfifo(struct IsdnCardState * return; } /* now determine free bytes in FIFO buffer */ - count = le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z2) - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); + count = df->za[df->f2 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1 - 1; if (count <= 0) count += D_FIFO_SIZE; /* count now contains available bytes */ @@ -528,12 +559,12 @@ hfcpci_fill_dfifo(struct IsdnCardState * return; } count = cs->tx_skb->len; /* get frame len */ - new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & (D_FIFO_SIZE - 1); + new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1); new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); src = cs->tx_skb->data; /* source pointer */ - dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); - maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); /* end fifo */ - if (maxlen > (int)count) + dst = df->data + df->za[df->f1 & D_FREG_MASK].z1; + maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */ + if (maxlen > count) maxlen = count; /* limit size */ memcpy(dst, src, maxlen); /* first copy */ @@ -543,8 +574,8 @@ hfcpci_fill_dfifo(struct IsdnCardState * src += maxlen; /* new position */ memcpy(dst, src, count); } - df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); /* for next buffer */ - df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); /* new pos actual buffer */ + df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */ + df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */ df->f1 = new_f1; /* next frame */ dev_kfree_skb_any(cs->tx_skb); @@ -559,11 +590,11 @@ static void hfcpci_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - int maxlen, fcnt, new_z1; - u_int count; + int maxlen, fcnt; + int count, new_z1; bzfifo_type *bz; - u8 *bdata; - u8 new_f1, *src, *dst; + u_char *bdata; + u_char new_f1, *src, *dst; unsigned short *z1t, *z2t; if (!bcs->tx_skb) @@ -584,24 +615,24 @@ hfcpci_fill_fifo(struct BCState *bcs) z2t = z1t + 1; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)", - bcs->channel, le16_to_cpu(*z1t), le16_to_cpu(*z2t)); - fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); + bcs->channel, *z1t, *z2t); + fcnt = *z2t - *z1t; if (fcnt <= 0) fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */ fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */ while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) { - if ((int)bcs->tx_skb->len < (B_FIFO_SIZE - fcnt)) { + if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { /* data is suitable for fifo */ count = bcs->tx_skb->len; - new_z1 = le16_to_cpu(*z1t) + count; /* new buffer Position */ + new_z1 = *z1t + count; /* new buffer Position */ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z1 -= B_FIFO_SIZE; /* buffer wrap */ src = bcs->tx_skb->data; /* source pointer */ - dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); /* end of fifo */ - if (maxlen > (int)count) + dst = bdata + (*z1t - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */ + if (maxlen > count) maxlen = count; /* limit size */ memcpy(dst, src, maxlen); /* first copy */ @@ -613,11 +644,15 @@ hfcpci_fill_fifo(struct BCState *bcs) } bcs->tx_cnt -= bcs->tx_skb->len; fcnt += bcs->tx_skb->len; - *z1t = cpu_to_le16(new_z1); /* now send data */ + *z1t = new_z1; /* now send data */ } else if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", bcs->channel, bcs->tx_skb->len); + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ } @@ -627,7 +662,7 @@ hfcpci_fill_fifo(struct BCState *bcs) if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)", bcs->channel, bz->f1, bz->f2, - le16_to_cpu(bz->za[bz->f1].z1)); + bz->za[bz->f1].z1); fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ if (fcnt < 0) @@ -638,7 +673,7 @@ hfcpci_fill_fifo(struct BCState *bcs) return; } /* now determine free bytes in FIFO buffer */ - count = le16_to_cpu(bz->za[bz->f1].z2) - le16_to_cpu(bz->za[bz->f1].z1); + count = bz->za[bz->f2].z2 - bz->za[bz->f1].z1 - 1; if (count <= 0) count += B_FIFO_SIZE; /* count now contains available bytes */ @@ -653,15 +688,15 @@ hfcpci_fill_fifo(struct BCState *bcs) return; } count = bcs->tx_skb->len; /* get frame len */ - new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count; /* new buffer Position */ + new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z1 -= B_FIFO_SIZE; /* buffer wrap */ new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); src = bcs->tx_skb->data; /* source pointer */ - dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); /* end fifo */ - if (maxlen > (int)count) + dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */ + if (maxlen > count) maxlen = count; /* limit size */ memcpy(dst, src, maxlen); /* first copy */ @@ -672,11 +707,15 @@ hfcpci_fill_fifo(struct BCState *bcs) memcpy(dst, src, count); } bcs->tx_cnt -= bcs->tx_skb->len; - xmit_complete_b(bcs); + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ + bz->za[new_f1].z1 = new_z1; /* for next buffer */ bz->f1 = new_f1; /* next frame */ + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); return; } @@ -696,7 +735,7 @@ dch_nt_l2l1(struct PStack *st, int pr, v st->l1.l1hw(st, pr, arg); break; case (PH_ACTIVATE | REQUEST): - L1L2(st, PH_ACTIVATE | CONFIRM, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); break; case (PH_TESTLOOP | REQUEST): if (1 & (long) arg) @@ -722,10 +761,12 @@ dch_nt_l2l1(struct PStack *st, int pr, v static int hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic) { - int i = *(unsigned int *) ic->parm.num; + u_long flags; + int i = *(unsigned int *) ic->parm.num; if ((ic->arg == 98) && (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); @@ -738,7 +779,8 @@ hfcpci_auxcmd(struct IsdnCardState *cs, cs->dc.hfcpci.ph_state = 1; cs->hw.hfcpci.nt_mode = 1; cs->hw.hfcpci.nt_timer = 0; - cs->stlist->l1.l2l1 = dch_nt_l2l1; + cs->stlist->l2.l2l1 = dch_nt_l2l1; + spin_unlock_irqrestore(&cs->lock, flags); debugl1(cs, "NT mode activated"); return (0); } @@ -746,6 +788,7 @@ hfcpci_auxcmd(struct IsdnCardState *cs, (cs->hw.hfcpci.nt_mode) || (ic->arg != 12)) return (-EINVAL); + spin_lock_irqsave(&cs->lock, flags); if (i) { cs->logecho = 1; cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */ @@ -768,6 +811,7 @@ hfcpci_auxcmd(struct IsdnCardState *cs, Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + spin_unlock_irqrestore(&cs->lock, flags); return (0); } /* hfcpci_auxcmd */ @@ -780,50 +824,54 @@ receive_emsg(struct IsdnCardState *cs) int rcnt; int receive, count = 5; bzfifo_type *bz; - u8 *bdata; + u_char *bdata; z_type *zp; - u8 *ptr, *ptr1, new_f2; + u_char *ptr, *ptr1, new_f2; int total, maxlen, new_z2; - u8 e_buffer[256]; + u_char e_buffer[256]; bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; Begin: count--; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "echo_rec_data blocked"); + return; + } if (bz->f1 != bz->f2) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)", bz->f1, bz->f2); zp = &bz->za[bz->f2]; - rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); + rcnt = zp->z1 - zp->z2; if (rcnt < 0) rcnt += B_FIFO_SIZE; rcnt++; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)", - le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); - new_z2 = le16_to_cpu(zp->z2) + rcnt; /* new position in fifo */ + zp->z1, zp->z2, rcnt); + new_z2 = zp->z2 + rcnt; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; if ((rcnt > 256 + 3) || (count < 4) || - (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { + (*(bdata + (zp->z1 - B_SUB_VAL)))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt); - bz->za[new_f2].z2 = cpu_to_le16(new_z2); + bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ } else { total = rcnt; rcnt -= 3; ptr = e_buffer; - if (le16_to_cpu(zp->z2) <= (B_FIFO_SIZE + B_SUB_VAL)) + if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL) maxlen = rcnt; /* complete transfer */ else - maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2); /* maximum */ + maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ - ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); /* start of data */ + ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ memcpy(ptr, ptr1, maxlen); /* copy data */ rcnt -= maxlen; @@ -832,7 +880,7 @@ receive_emsg(struct IsdnCardState *cs) ptr1 = bdata; /* start of buffer */ memcpy(ptr, ptr1, rcnt); /* rest */ } - bz->za[new_f2].z2 = cpu_to_le16(new_z2); + bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ if (cs->debug & DEB_DLOG_HEX) { ptr = cs->dlog; @@ -861,6 +909,7 @@ receive_emsg(struct IsdnCardState *cs) receive = 0; } else receive = 0; + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && receive) goto Begin; return; @@ -872,28 +921,30 @@ receive_emsg(struct IsdnCardState *cs) static irqreturn_t hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) { + u_long flags; struct IsdnCardState *cs = dev_id; - u8 exval; + u_char exval; struct BCState *bcs; int count = 15; - u8 val, stat; + u_char val, stat; - if (!cs) { - printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n"); - return IRQ_NONE; + if (!(cs->hw.hfcpci.int_m2 & 0x08)) { + debugl1(cs, "HFC-PCI: int_m2 %x not initialised", cs->hw.hfcpci.int_m2); + return IRQ_NONE; /* not initialised */ } - if (!(cs->hw.hfcpci.int_m2 & 0x08)) - return IRQ_NONE; /* not initialised */ - + spin_lock_irqsave(&cs->lock, flags); if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) { val = Read_hfc(cs, HFCPCI_INT_S1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val); - } else + } else { + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; - + } if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI irq %x", val); + debugl1(cs, "HFC-PCI irq %x %s", val, + test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? + "locked" : "unlocked"); val &= cs->hw.hfcpci.int_m1; if (val & 0x40) { /* state machine irq */ exval = Read_hfc(cs, HFCPCI_STATES) & 0xf; @@ -901,18 +952,23 @@ hfcpci_interrupt(int intno, void *dev_id debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state, exval); cs->dc.hfcpci.ph_state = exval; - sched_d_event(cs, D_L1STATECHANGE); + sched_event_D_pci(cs, D_L1STATECHANGE); val &= ~0x40; } if (val & 0x80) { /* timer irq */ if (cs->hw.hfcpci.nt_mode) { if ((--cs->hw.hfcpci.nt_timer) < 0) - sched_d_event(cs, D_L1STATECHANGE); + sched_event_D_pci(cs, D_L1STATECHANGE); } val &= ~0x80; Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); } while (val) { + if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + cs->hw.hfcpci.int_s1 |= val; + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; + } if (cs->hw.hfcpci.int_s1 & 0x18) { exval = val; val = cs->hw.hfcpci.int_s1; @@ -939,7 +995,23 @@ hfcpci_interrupt(int intno, void *dev_id if (cs->debug) debugl1(cs, "hfcpci spurious 0x01 IRQ"); } else { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + hfcpci_sched_event(bcs, B_XMTBUFREADY); + } + } } } if (val & 0x02) { @@ -947,15 +1019,60 @@ hfcpci_interrupt(int intno, void *dev_id if (cs->debug) debugl1(cs, "hfcpci spurious 0x02 IRQ"); } else { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + hfcpci_sched_event(bcs, B_XMTBUFREADY); + } + } } } if (val & 0x20) { /* receive dframe */ receive_dmsg(cs); } if (val & 0x04) { /* dframe transmitted */ - xmit_xpr_d(cs); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + sched_event_D_pci(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcpci_fill_dfifo irq blocked"); + } + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcpci_fill_dfifo irq blocked"); + } + } else + sched_event_D_pci(cs, D_XMTBUFREADY); } + afterXPR: if (cs->hw.hfcpci.int_s1 && count--) { val = cs->hw.hfcpci.int_s1; cs->hw.hfcpci.int_s1 = 0; @@ -964,6 +1081,7 @@ hfcpci_interrupt(int intno, void *dev_id } else val = 0; } + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } @@ -981,40 +1099,106 @@ hfcpci_dbusy_timer(struct IsdnCardState static void HFCPCI_l1hw(struct PStack *st, int pr, void *arg) { + u_long flags; struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcpci_fill_dfifo blocked"); + + } + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_d(cs, skb); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcpci_fill_dfifo blocked"); + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */ cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); + spin_unlock_irqrestore(&cs->lock, flags); l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (HW_ENABLE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_DEACTIVATE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER; Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): + spin_lock_irqsave(&cs->lock, flags); switch ((int) arg) { case (1): Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* tx slot */ @@ -1031,12 +1215,14 @@ HFCPCI_l1hw(struct PStack *st, int pr, v break; default: + spin_unlock_irqrestore(&cs->lock, flags); if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg); return; } cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); + spin_unlock_irqrestore(&cs->lock, flags); break; default: if (cs->debug & L1_DEB_WARN) @@ -1048,11 +1234,25 @@ HFCPCI_l1hw(struct PStack *st, int pr, v /***********************************************/ /* called during init setting l1 stack pointer */ /***********************************************/ -static int +void setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = HFCPCI_l1hw; - return 0; +} + +/**************************************/ +/* send B-channel data if not blocked */ +/**************************************/ +static void +hfcpci_send_data(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "send_data %d blocked", bcs->channel); } /***************************************************************/ @@ -1182,31 +1382,58 @@ mode_hfcpci(struct BCState *bcs, int mod static void hfcpci_l2l1(struct PStack *st, int pr, void *arg) { - struct sk_buff *skb = arg; + struct BCState *bcs = st->l1.bcs; + u_long flags; + struct sk_buff *skb = arg; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; +// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + spin_unlock_irqrestore(&bcs->cs->lock, flags); + printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); + break; + } +// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->cs->BC_Send_Data(bcs); + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_hfcpci(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + mode_hfcpci(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - mode_hfcpci(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + mode_hfcpci(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -1256,7 +1483,7 @@ setstack_2b(struct PStack *st, struct BC if (open_hfcpcistate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = hfcpci_l2l1; + st->l2.l2l1 = hfcpci_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -1267,11 +1494,11 @@ setstack_2b(struct PStack *st, struct BC /* handle L1 state changes */ /***************************/ static void -hfcpci_bh(void *data) +hfcpci_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; -/* struct PStack *stptr; - */ + u_long flags; +// struct PStack *stptr; + if (!cs) return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { @@ -1295,6 +1522,7 @@ hfcpci_bh(void *data) default: break; } else { + spin_lock_irqsave(&cs->lock, flags); switch (cs->dc.hfcpci.ph_state) { case (2): if (cs->hw.hfcpci.nt_timer < 0) { @@ -1303,7 +1531,6 @@ hfcpci_bh(void *data) Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); /* Clear already pending ints */ if (Read_hfc(cs, HFCPCI_INT_S1)); - Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); udelay(10); Write_hfc(cs, HFCPCI_STATES, 4); @@ -1329,6 +1556,7 @@ hfcpci_bh(void *data) default: break; } + spin_unlock_irqrestore(&cs->lock, flags); } } if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) @@ -1337,18 +1565,6 @@ hfcpci_bh(void *data) DChannel_proc_xmt(cs); } -static struct bc_l1_ops hfcpci_bc_l1_ops = { - .fill_fifo = hfcpci_fill_fifo, - .open = setstack_2b, - .close = close_hfcpci, -}; - -static struct dc_l1_ops hfcpci_dc_l1_ops = { - .fill_fifo = hfcpci_fill_dfifo, - .open = setstack_hfcpci, - .bh_func = hfcpci_bh, - .dbusy_func = hfcpci_dbusy_timer, -}; /********************************/ /* called for card init message */ @@ -1356,116 +1572,167 @@ static struct dc_l1_ops hfcpci_dc_l1_ops void __init inithfcpci(struct IsdnCardState *cs) { - dc_l1_init(cs, &hfcpci_dc_l1_ops); - cs->bc_l1_ops = &hfcpci_bc_l1_ops; + cs->bcs[0].BC_SetStack = setstack_2b; + cs->bcs[1].BC_SetStack = setstack_2b; + cs->bcs[0].BC_Close = close_hfcpci; + cs->bcs[1].BC_Close = close_hfcpci; + cs->dbusytimer.function = (void *) hfcpci_dbusy_timer; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); mode_hfcpci(cs->bcs, 0, 0); mode_hfcpci(cs->bcs + 1, 0, 1); } -static void -hfcpci_init(struct IsdnCardState *cs) -{ - inithfcpci(cs); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ - /* now switch timer interrupt off */ - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - /* reinit mode reg */ - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); -} - -static struct card_ops hfcpci_ops = { - .init = hfcpci_init, - .reset = hfcpci_reset, - .release = hfcpci_release, - .irq_func = hfcpci_interrupt, -}; -static int __init -niccy_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev, int i) +/*******************************************/ +/* handle card messages from control layer */ +/*******************************************/ +static int +hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int rc; - - rc = -EBUSY; - if (pci_enable_device(pdev)) - goto err; - - pci_set_master(pdev); - - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.hfcpci.pdev = pdev; - - cs->hw.hfcpci.pci_io = request_mmio(&cs->rs, - pci_resource_start(pdev, 1), 128, - "hfc_pci"); - if (!cs->hw.hfcpci.pci_io) - goto err; - - /* Allocate memory for FIFOS */ - rc = -ENOMEM; - cs->hw.hfcpci.fifos = pci_alloc_consistent(pdev, 32768, - &cs->hw.hfcpci.fifos_dma); - if (!cs->hw.hfcpci.fifos) - goto err; - - pci_write_config_dword(cs->hw.hfcpci.pdev, 0x80, - (u_int)cs->hw.hfcpci.fifos_dma); - printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s name: %s\n", - id_list[i].vendor_name, id_list[i].card_name); - printk(KERN_INFO "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d\n", - (u_int) cs->hw.hfcpci.pci_io, (u_int) cs->hw.hfcpci.fifos, - (u_int) cs->hw.hfcpci.fifos_dma, cs->irq); - printk("ChipID: %x\n", Read_hfc(cs, HFCPCI_CHIP_ID)); - cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */ - cs->hw.hfcpci.int_m1 = 0; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - /* At this point the needed PCI config is done */ - /* fifos are still not enabled */ + u_long flags; - init_timer(&cs->hw.hfcpci.timer); - cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer; - cs->hw.hfcpci.timer.data = (long) cs; - - hfcpci_reset(cs); - cs->auxcmd = &hfcpci_auxcmd; - cs->card_ops = &hfcpci_ops; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCPCI: card_msg %x", mt); + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_hfcpci(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_RELEASE: + release_io_hfcpci(cs); + return (0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithfcpci(cs); + reset_hfcpci(cs); + spin_unlock_irqrestore(&cs->lock, flags); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ + /* now switch timer interrupt off */ + spin_lock_irqsave(&cs->lock, flags); + cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + /* reinit mode reg */ + Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_TEST: + return (0); + } + return (0); } + /* this variable is used as card index when more than one cards are present */ static struct pci_dev *dev_hfcpci __initdata = NULL; +#endif /* CONFIG_PCI */ + int __init setup_hfcpci(struct IsdnCard *card) { + u_long flags; struct IsdnCardState *cs = card->cs; char tmp[64]; int i; struct pci_dev *tmp_hfcpci = NULL; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); +#if CONFIG_PCI cs->hw.hfcpci.int_s1 = 0; cs->dc.hfcpci.ph_state = 0; cs->hw.hfcpci.fifo = 255; + if (cs->typ == ISDN_CTYPE_HFC_PCI) { + i = 0; + while (id_list[i].vendor_id) { + tmp_hfcpci = pci_find_device(id_list[i].vendor_id, + id_list[i].device_id, + dev_hfcpci); + i++; + if (tmp_hfcpci) { + if (pci_enable_device(tmp_hfcpci)) + continue; + pci_set_master(tmp_hfcpci); + if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) + continue; + else + break; + } + } - for (i = 0; id_list[i].vendor_id; i++) { - tmp_hfcpci = pci_find_device(id_list[i].vendor_id, - id_list[i].device_id, - dev_hfcpci); - if (!tmp_hfcpci) - continue; - - if (niccy_pci_probe(card->cs, tmp_hfcpci, i) < 0) + if (tmp_hfcpci) { + i--; + dev_hfcpci = tmp_hfcpci; /* old device */ + cs->hw.hfcpci.dev = dev_hfcpci; + cs->irq = dev_hfcpci->irq; + if (!cs->irq) { + printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); + return (0); + } + cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start; + printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name); + } else { + printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); + return (0); + } + if (!cs->hw.hfcpci.pci_io) { + printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); + return (0); + } + /* Allocate memory for FIFOS */ + /* Because the HFC-PCI needs a 32K physical alignment, we */ + /* need to allocate the double mem and align the address */ + if (!((void *) cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) { + printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); return 0; - return 1; - } - return 0; + } + (ulong) cs->hw.hfcpci.fifos = + (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; + pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos)); + cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256); + printk(KERN_INFO + "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n", + (u_int) cs->hw.hfcpci.pci_io, + (u_int) cs->hw.hfcpci.fifos, + (u_int) virt_to_bus(cs->hw.hfcpci.fifos), + cs->irq, HZ); + spin_lock_irqsave(&cs->lock, flags); + pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ + cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */ + cs->hw.hfcpci.int_m1 = 0; + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); + /* At this point the needed PCI config is done */ + /* fifos are still not enabled */ + INIT_WORK(&cs->tqueue, (void *)(void *) hfcpci_bh, cs); + cs->setstack_d = setstack_hfcpci; + cs->BC_Send_Data = &hfcpci_send_data; + cs->readisac = NULL; + cs->writeisac = NULL; + cs->readisacfifo = NULL; + cs->writeisacfifo = NULL; + cs->BC_Read_Reg = NULL; + cs->BC_Write_Reg = NULL; + cs->irq_func = &hfcpci_interrupt; + cs->irq_flags |= SA_SHIRQ; + cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer; + cs->hw.hfcpci.timer.data = (long) cs; + init_timer(&cs->hw.hfcpci.timer); + cs->cardmsg = &hfcpci_card_msg; + cs->auxcmd = &hfcpci_auxcmd; + spin_unlock_irqrestore(&cs->lock, flags); + return (1); + } else + return (0); /* no valid card type */ +#else + printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n"); + return (0); +#endif /* CONFIG_PCI */ } diff -puN drivers/isdn/hisax/hfc_pci.h~i4l drivers/isdn/hisax/hfc_pci.h --- 25/drivers/isdn/hisax/hfc_pci.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_pci.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.h,v 1.8.6.2 2001/09/23 22:24:48 kai Exp $ +/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $ * * specific defines for CCD's HFC 2BDS0 PCI chips * @@ -185,53 +185,51 @@ typedef struct { unsigned short z1; /* Z1 pointer 16 Bit */ unsigned short z2; /* Z2 pointer 16 Bit */ - } __attribute__((packed)) z_type; + } z_type; typedef struct { - u8 data[D_FIFO_SIZE]; /* FIFO data space */ - u8 fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */ - u8 f1,f2; /* f pointers */ - u8 fill2[0x20C0-0x20A2]; /* reserved, do not use */ + u_char data[D_FIFO_SIZE]; /* FIFO data space */ + u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */ + u_char f1,f2; /* f pointers */ + u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */ z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */ - u8 fill3[0x4000-0x2100]; /* align 16K */ - } __attribute__((packed)) dfifo_type; + u_char fill3[0x4000-0x2100]; /* align 16K */ + } dfifo_type; typedef struct { z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */ - u8 f1,f2; /* f pointers */ - u8 fill[0x2100-0x2082]; /* alignment */ - } __attribute__((packed)) bzfifo_type; + u_char f1,f2; /* f pointers */ + u_char fill[0x2100-0x2082]; /* alignment */ + } bzfifo_type; typedef union { struct { dfifo_type d_tx; /* D-send channel */ dfifo_type d_rx; /* D-receive channel */ - } __attribute__((packed)) d_chan; + } d_chan; struct { - u8 fill1[0x200]; - u8 txdat_b1[B_FIFO_SIZE]; + u_char fill1[0x200]; + u_char txdat_b1[B_FIFO_SIZE]; bzfifo_type txbz_b1; bzfifo_type txbz_b2; - u8 txdat_b2[B_FIFO_SIZE]; + u_char txdat_b2[B_FIFO_SIZE]; - u8 fill2[D_FIFO_SIZE]; + u_char fill2[D_FIFO_SIZE]; - u8 rxdat_b1[B_FIFO_SIZE]; + u_char rxdat_b1[B_FIFO_SIZE]; bzfifo_type rxbz_b1; bzfifo_type rxbz_b2; - u8 rxdat_b2[B_FIFO_SIZE]; - } __attribute__((packed)) b_chans; - u8 fill[32768]; - } __attribute__((packed)) fifo_area; + u_char rxdat_b2[B_FIFO_SIZE]; + } b_chans; + u_char fill[32768]; + } fifo_area; -//#define Write_hfc(a,b,c) (*(((u8 *)a->hw.hfcpci.pci_io)+b) = c) -//#define Read_hfc(a,b) (*(((u8 *)a->hw.hfcpci.pci_io)+b)) -#define Write_hfc(a,b,c) writeb(c, ((u8 *)a->hw.hfcpci.pci_io)+b) -#define Read_hfc(a,b) readb(((u8 *)a->hw.hfcpci.pci_io)+b) +#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c) +#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b)) extern void main_irq_hcpci(struct BCState *bcs); extern void inithfcpci(struct IsdnCardState *cs); diff -puN drivers/isdn/hisax/hfcscard.c~i4l drivers/isdn/hisax/hfcscard.c --- 25/drivers/isdn/hisax/hfcscard.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfcscard.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hfcscard.c,v 1.8.6.2 2001/09/23 22:24:48 kai Exp $ +/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $ * * low level stuff for hfcs based cards (Teles3c, ACER P10) * @@ -18,33 +18,19 @@ extern const char *CardType[]; -static const char *hfcs_revision = "$Revision: 1.8.6.2 $"; - -static inline u8 -hfcs_read_reg(struct IsdnCardState *cs, int data, u8 reg) -{ - return cs->bc_hw_ops->read_reg(cs, data, reg); -} - -static inline void -hfcs_write_reg(struct IsdnCardState *cs, int data, u8 reg, u8 val) -{ - cs->bc_hw_ops->write_reg(cs, data, reg, val); -} +static const char *hfcs_revision = "$Revision: 1.10.2.4 $"; static irqreturn_t hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val, stat; + u_char val, stat; + u_long flags; - if (!cs) { - printk(KERN_WARNING "HFCS: Spurious interrupt!\n"); - return IRQ_NONE; - } + spin_lock_irqsave(&cs->lock, flags); if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & - (stat = hfcs_read_reg(cs, HFCD_DATA, HFCD_STAT))) { - val = hfcs_read_reg(cs, HFCD_DATA, HFCD_INT_S1); + (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { + val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val); hfc2bds0_interrupt(cs, val); @@ -52,6 +38,7 @@ hfcs_interrupt(int intno, void *dev_id, if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat); } + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } @@ -65,117 +52,91 @@ hfcs_Timer(struct IsdnCardState *cs) */ } -static void -hfcs_release(struct IsdnCardState *cs) +void +release_io_hfcs(struct IsdnCardState *cs) { release2bds0(cs); del_timer(&cs->hw.hfcD.timer); - hisax_release_resources(cs); + if (cs->hw.hfcD.addr) + release_region(cs->hw.hfcD.addr, 2); } -static int -hfcs_reset(struct IsdnCardState *cs) +static void +reset_hfcs(struct IsdnCardState *cs) { printk(KERN_INFO "HFCS: resetting card\n"); cs->hw.hfcD.cirm = HFCD_RESET; if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_MEM8K; - hfcs_write_reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30*HZ)/1000); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ + mdelay(10); cs->hw.hfcD.cirm = 0; if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_MEM8K; - hfcs_write_reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ + mdelay(10); if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_INTB; else if (cs->typ == ISDN_CTYPE_ACERP10) cs->hw.hfcD.cirm |= HFCD_INTA; - hfcs_write_reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); - hfcs_write_reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); - hfcs_write_reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; - hfcs_write_reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | HFCD_INTS_DREC | HFCD_INTS_L1STATE; - hfcs_write_reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); - hfcs_write_reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); - hfcs_write_reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ udelay(10); - hfcs_write_reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ cs->hw.hfcD.mst_m = HFCD_MASTER; - hfcs_write_reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */ + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */ cs->hw.hfcD.sctrl = 0; - hfcs_write_reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); - return 0; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); } -static void -hfcs_init(struct IsdnCardState *cs) -{ - cs->hw.hfcD.timer.expires = jiffies + 75; - add_timer(&cs->hw.hfcD.timer); - init2bds0(cs); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((80*HZ)/1000); - cs->hw.hfcD.ctmt |= HFCD_TIM800; - hfcs_write_reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - hfcs_write_reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); -} - -static struct card_ops hfcs_ops = { - .init = hfcs_init, - .reset = hfcs_reset, - .release = hfcs_release, - .irq_func = hfcs_interrupt, -}; - -static int __init -hfcs_probe(struct IsdnCardState *cs, struct IsdnCard *card) +static int +hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - cs->irq = card->para[0]; - cs->hw.hfcD.addr = card->para[1]; + u_long flags; + int delay; - if (!request_io(&cs->rs, cs->hw.hfcD.addr, 2, "HFCS isdn")) - goto err; - - printk(KERN_INFO "HFCS: defined at 0x%x IRQ %d\n", - cs->hw.hfcD.addr, cs->irq); - - cs->hw.hfcD.cip = 0; - cs->hw.hfcD.int_s1 = 0; - cs->hw.hfcD.send = NULL; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; - cs->hw.hfcD.dfifosize = 512; - cs->dc.hfcd.ph_state = 0; - cs->hw.hfcD.fifo = 255; - - if (cs->typ == ISDN_CTYPE_TELES3C) { - cs->hw.hfcD.bfifosize = 1024 + 512; - /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x56, cs->hw.hfcD.addr | 1); - } else if (cs->typ == ISDN_CTYPE_ACERP10) { - cs->hw.hfcD.bfifosize = 7*1024 + 512; - /* Acer P10 IO ADR is 0x300 */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x57, cs->hw.hfcD.addr | 1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCS: card_msg %x", mt); + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_hfcs(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_hfcs(cs); + return(0); + case CARD_INIT: + delay = (75*HZ)/100 +1; + cs->hw.hfcD.timer.expires = jiffies + delay; + add_timer(&cs->hw.hfcD.timer); + spin_lock_irqsave(&cs->lock, flags); + reset_hfcs(cs); + init2bds0(cs); + spin_unlock_irqrestore(&cs->lock, flags); + delay = (80*HZ)/1000 +1; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((80*HZ)/1000); + spin_lock_irqsave(&cs->lock, flags); + cs->hw.hfcD.ctmt |= HFCD_TIM800; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); } - set_cs_func(cs); - init_timer(&cs->hw.hfcD.timer); - cs->hw.hfcD.timer.function = (void *) hfcs_Timer; - cs->hw.hfcD.timer.data = (long) cs; - hfcs_reset(cs); - cs->card_ops = &hfcs_ops; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return(0); } #ifdef __ISAPNP__ @@ -204,13 +165,14 @@ static struct isapnp_device_id hfc_ids[] { 0, } }; -static struct isapnp_device_id *hdev = &hfc_ids[0]; +static struct isapnp_device_id *ipid __initdata = &hfc_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif int __init setup_hfcs(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, hfcs_revision); @@ -218,54 +180,88 @@ setup_hfcs(struct IsdnCard *card) #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; - while(hdev->card_vendor) { - if ((pb = pnp_find_card(hdev->card_vendor, - hdev->card_device, - pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - hdev->vendor, - hdev->function, - pd))) { printk(KERN_INFO "HiSax: %s detected\n", - (char *)hdev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "HFC PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "HFC PnP: activate failed\n"); - pnp_device_detach(pd); - return 0; + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) { + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); break; } else { printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); } } - hdev++; - pnp_c=NULL; + ipid++; + pnp_c = NULL; } - if (!hdev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); return(0); } } #endif - if (hfcs_probe(card->cs, card) < 0) - return 0; - return 1; - + cs->hw.hfcD.addr = card->para[1] & 0xfffe; + cs->irq = card->para[0]; + cs->hw.hfcD.cip = 0; + cs->hw.hfcD.int_s1 = 0; + cs->hw.hfcD.send = NULL; + cs->bcs[0].hw.hfc.send = NULL; + cs->bcs[1].hw.hfc.send = NULL; + cs->hw.hfcD.dfifosize = 512; + cs->dc.hfcd.ph_state = 0; + cs->hw.hfcD.fifo = 255; + if (cs->typ == ISDN_CTYPE_TELES3C) { + cs->hw.hfcD.bfifosize = 1024 + 512; + } else if (cs->typ == ISDN_CTYPE_ACERP10) { + cs->hw.hfcD.bfifosize = 7*1024 + 512; + } else + return (0); + if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.hfcD.addr, + cs->hw.hfcD.addr + 2); + return (0); + } + printk(KERN_INFO + "HFCS: defined at 0x%x IRQ %d HZ %d\n", + cs->hw.hfcD.addr, + cs->irq, HZ); + if (cs->typ == ISDN_CTYPE_TELES3C) { + /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ + outb(0x00, cs->hw.hfcD.addr); + outb(0x56, cs->hw.hfcD.addr | 1); + } else if (cs->typ == ISDN_CTYPE_ACERP10) { + /* Acer P10 IO ADR is 0x300 */ + outb(0x00, cs->hw.hfcD.addr); + outb(0x57, cs->hw.hfcD.addr | 1); + } + set_cs_func(cs); + cs->hw.hfcD.timer.function = (void *) hfcs_Timer; + cs->hw.hfcD.timer.data = (long) cs; + init_timer(&cs->hw.hfcD.timer); + cs->cardmsg = &hfcs_card_msg; + cs->irq_func = &hfcs_interrupt; + return (1); } diff -puN drivers/isdn/hisax/hfc_sx.c~i4l drivers/isdn/hisax/hfc_sx.c --- 25/drivers/isdn/hisax/hfc_sx.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hfc_sx.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,6 +1,6 @@ -/* $Id: hfc_sx.c,v 1.9.6.3 2001/09/23 22:24:48 kai Exp $ +/* $Id: hfc_sx.c,v 1.12.2.4 2004/01/14 16:04:48 keil Exp $ * - * level driver for CCD´s hfc-s+/sp based cards + * level driver for Cologne Chip Designs hfc-s+/sp based cards * * Author Werner Cornelius * based on existing driver for CCD HFC PCI cards @@ -20,7 +20,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.9.6.3 $"; +static const char *hfcsx_revision = "$Revision: 1.12.2.4 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -43,11 +43,11 @@ static const char *hfcsx_revision = "$Re #undef CCD_DEMO_BOARD #ifdef CCD_DEMO_BOARD -static u8 ccd_sp_irqtab[16] = { +static u_char ccd_sp_irqtab[16] = { 0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6 }; #else /* Teles 16.3c */ -static u8 ccd_sp_irqtab[16] = { +static u_char ccd_sp_irqtab[16] = { 0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6 }; #endif @@ -60,17 +60,16 @@ static u8 ccd_sp_irqtab[16] = { /* In/Out access to registers */ /******************************/ static inline void -Write_hfc(struct IsdnCardState *cs, u8 regnum, u8 val) +Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val) { - byteout(cs->hw.hfcsx.base+1, regnum); byteout(cs->hw.hfcsx.base, val); } -static inline u8 -Read_hfc(struct IsdnCardState *cs, u8 regnum) +static inline u_char +Read_hfc(struct IsdnCardState *cs, u_char regnum) { - u8 ret; + u_char ret; byteout(cs->hw.hfcsx.base+1, regnum); ret = bytein(cs->hw.hfcsx.base); @@ -82,7 +81,7 @@ Read_hfc(struct IsdnCardState *cs, u8 re /* select a fifo and remember which one for reuse */ /**************************************************/ static void -fifo_select(struct IsdnCardState *cs, u8 fifo) +fifo_select(struct IsdnCardState *cs, u_char fifo) { if (fifo == cs->hw.hfcsx.last_fifo) return; /* still valid */ @@ -97,10 +96,10 @@ fifo_select(struct IsdnCardState *cs, u8 /******************************************/ /* reset the specified fifo to defaults. */ -/* If it's a send fifo init needed markers */ +/* If its a send fifo init needed markers */ /******************************************/ static void -reset_fifo(struct IsdnCardState *cs, u8 fifo) +reset_fifo(struct IsdnCardState *cs, u_char fifo) { fifo_select(cs, fifo); /* first select the fifo */ byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM); @@ -116,10 +115,11 @@ reset_fifo(struct IsdnCardState *cs, u8 /* the skb is not released in any way. */ /*************************************************************/ static int -write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u8 fifo, int trans_max) -{ unsigned short *msp; +write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max) +{ + unsigned short *msp; int fifo_size, count, z1, z2; - u8 f_msk, f1, f2, *src; + u_char f_msk, f1, f2, *src; if (skb->len <= 0) return(0); if (fifo & 1) return(0); /* no write fifo */ @@ -145,9 +145,9 @@ write_fifo(struct IsdnCardState *cs, str count = z2 - z1; if (count <= 0) count += fifo_size; /* free bytes */ - if (count < (int)(skb->len+1)) return(0); /* no room */ + if (count < skb->len+1) return(0); /* no room */ count = fifo_size - count; /* bytes still not send */ - if (count > 2 * trans_max) return(0); /* delay too long */ + if (count > 2 * trans_max) return(0); /* delay to long */ count = skb->len; src = skb->data; while (count--) @@ -182,7 +182,7 @@ write_fifo(struct IsdnCardState *cs, str if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)", fifo, skb->len, count); - if (count < (int)skb->len) { + if (count < skb->len) { if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo); return(0); @@ -205,9 +205,9 @@ write_fifo(struct IsdnCardState *cs, str /* the skb is not released in any way. */ /***************************************************************/ static struct sk_buff * -read_fifo(struct IsdnCardState *cs, u8 fifo, int trans_max) +read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) { int fifo_size, count, z1, z2; - u8 f_msk, f1, f2, *dst; + u_char f_msk, f1, f2, *dst; struct sk_buff *skb; if (!(fifo & 1)) return(NULL); /* no read fifo */ @@ -308,8 +308,8 @@ read_fifo(struct IsdnCardState *cs, u8 f /******************************************/ /* free hardware resources used by driver */ /******************************************/ -static void -hfcsx_release(struct IsdnCardState *cs) +void +release_io_hfcsx(struct IsdnCardState *cs) { cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); @@ -318,7 +318,7 @@ hfcsx_release(struct IsdnCardState *cs) schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ del_timer(&cs->hw.hfcsx.timer); - hisax_release_resources(cs); + release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */ kfree(cs->hw.hfcsx.extra); cs->hw.hfcsx.extra = NULL; } @@ -347,8 +347,8 @@ static int set_fifo_size(struct IsdnCard /* function called to reset the HFC SX chip. A complete software reset of chip */ /* and fifos is done. */ /********************************************************************************/ -static int -hfcsx_reset(struct IsdnCardState *cs) +static void +reset_hfcsx(struct IsdnCardState *cs) { cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); @@ -356,11 +356,9 @@ hfcsx_reset(struct IsdnCardState *cs) printk(KERN_INFO "HFC_SX: resetting card\n"); while (1) { Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ + mdelay(30); Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + mdelay(20); if (Read_hfc(cs, HFCSX_STATUS) & 2) printk(KERN_WARNING "HFC-SX init bit busy\n"); cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */ @@ -415,7 +413,6 @@ hfcsx_reset(struct IsdnCardState *cs) cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE; Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); if (Read_hfc(cs, HFCSX_INT_S2)); - return 0; } /***************************************************/ @@ -431,7 +428,6 @@ hfcsx_Timer(struct IsdnCardState *cs) */ } - /************************************************/ /* select a b-channel entry matching and active */ /************************************************/ @@ -450,20 +446,27 @@ Sel_BCS(struct IsdnCardState *cs, int ch /*******************************/ /* D-channel receive procedure */ /*******************************/ -static int +static +int receive_dmsg(struct IsdnCardState *cs) { struct sk_buff *skb; int count = 5; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_dmsg blocked"); + return (1); + } + do { skb = read_fifo(cs, HFCSX_SEL_D_RX, 0); if (skb) { skb_queue_tail(&cs->rq, skb); - sched_d_event(cs, D_RCVBUFREADY); + schedule_event(cs, D_RCVBUFREADY); } } while (--count && skb); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); return (1); } @@ -479,6 +482,10 @@ main_rec_hfcsx(struct BCState *bcs) Begin: count--; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_data %d blocked", bcs->channel); + return; + } skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX, (bcs->mode == L1_MODE_TRANS) ? @@ -486,9 +493,10 @@ main_rec_hfcsx(struct BCState *bcs) if (skb) { skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); } + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && skb) goto Begin; return; @@ -509,6 +517,7 @@ hfcsx_fill_dfifo(struct IsdnCardState *c dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } + return; } /**************************/ @@ -530,9 +539,13 @@ hfcsx_fill_fifo(struct BCState *bcs) (bcs->mode == L1_MODE_TRANS) ? HFCSX_BTRANS_THRESHOLD : 0)) { - bcs->tx_cnt -= bcs->tx_skb->len; - xmit_complete_b(bcs); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_cnt -= bcs->tx_skb->len; + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } @@ -551,7 +564,7 @@ dch_nt_l2l1(struct PStack *st, int pr, v st->l1.l1hw(st, pr, arg); break; case (PH_ACTIVATE | REQUEST): - L1L2(st, PH_ACTIVATE | CONFIRM, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); break; case (PH_TESTLOOP | REQUEST): if (1 & (long) arg) @@ -577,10 +590,12 @@ dch_nt_l2l1(struct PStack *st, int pr, v static int hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic) { + unsigned long flags; int i = *(unsigned int *) ic->parm.num; if ((ic->arg == 98) && (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) { + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT; @@ -592,7 +607,8 @@ hfcsx_auxcmd(struct IsdnCardState *cs, i cs->dc.hfcsx.ph_state = 1; cs->hw.hfcsx.nt_mode = 1; cs->hw.hfcsx.nt_timer = 0; - cs->stlist->l1.l2l1 = dch_nt_l2l1; + spin_unlock_irqrestore(&cs->lock, flags); + cs->stlist->l2.l2l1 = dch_nt_l2l1; debugl1(cs, "NT mode activated"); return (0); } @@ -614,12 +630,14 @@ hfcsx_auxcmd(struct IsdnCardState *cs, i cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */ cs->hw.hfcsx.ctmt &= ~2; + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + spin_unlock_irqrestore(&cs->lock, flags); return (0); } /* hfcsx_auxcmd */ @@ -630,9 +648,13 @@ static void receive_emsg(struct IsdnCardState *cs) { int count = 5; - u8 *ptr; + u_char *ptr; struct sk_buff *skb; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "echo_rec_data blocked"); + return; + } do { skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0); if (skb) { @@ -655,6 +677,9 @@ receive_emsg(struct IsdnCardState *cs) dev_kfree_skb_any(skb); } } while (--count && skb); + + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + return; } /* receive_emsg */ @@ -665,27 +690,28 @@ static irqreturn_t hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 exval; + u_char exval; struct BCState *bcs; int count = 15; - u8 val, stat; + u_long flags; + u_char val, stat; - if (!cs) { - printk(KERN_WARNING "HFC-SX: Spurious interrupt!\n"); - return IRQ_NONE; - } if (!(cs->hw.hfcsx.int_m2 & 0x08)) return IRQ_NONE; /* not initialised */ + spin_lock_irqsave(&cs->lock, flags); if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) { val = Read_hfc(cs, HFCSX_INT_S1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val); - } else + } else { + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; - + } if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX irq %x", val); + debugl1(cs, "HFC-SX irq %x %s", val, + test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? + "locked" : "unlocked"); val &= cs->hw.hfcsx.int_m1; if (val & 0x40) { /* state machine irq */ exval = Read_hfc(cs, HFCSX_STATES) & 0xf; @@ -693,18 +719,23 @@ hfcsx_interrupt(int intno, void *dev_id, debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state, exval); cs->dc.hfcsx.ph_state = exval; - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); val &= ~0x40; } if (val & 0x80) { /* timer irq */ if (cs->hw.hfcsx.nt_mode) { if ((--cs->hw.hfcsx.nt_timer) < 0) - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); } val &= ~0x80; Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); } while (val) { + if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + cs->hw.hfcsx.int_s1 |= val; + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; + } if (cs->hw.hfcsx.int_s1 & 0x18) { exval = val; val = cs->hw.hfcsx.int_s1; @@ -731,7 +762,23 @@ hfcsx_interrupt(int intno, void *dev_id, if (cs->debug) debugl1(cs, "hfcsx spurious 0x01 IRQ"); } else { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + schedule_event(bcs, B_XMTBUFREADY); + } + } } } if (val & 0x02) { @@ -739,15 +786,60 @@ hfcsx_interrupt(int intno, void *dev_id, if (cs->debug) debugl1(cs, "hfcsx spurious 0x02 IRQ"); } else { - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + schedule_event(bcs, B_XMTBUFREADY); + } + } } } if (val & 0x20) { /* receive dframe */ receive_dmsg(cs); } if (val & 0x04) { /* dframe transmitted */ - xmit_xpr_d(cs); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcsx_fill_dfifo irq blocked"); + } + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcsx_fill_dfifo irq blocked"); + } + } else + schedule_event(cs, D_XMTBUFREADY); } + afterXPR: if (cs->hw.hfcsx.int_s1 && count--) { val = cs->hw.hfcsx.int_s1; cs->hw.hfcsx.int_s1 = 0; @@ -756,6 +848,7 @@ hfcsx_interrupt(int intno, void *dev_id, } else val = 0; } + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } @@ -775,38 +868,104 @@ HFCSX_l1hw(struct PStack *st, int pr, vo { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcsx_fill_dfifo blocked"); + + } + spin_unlock_irqrestore(&cs->lock, flags); break; - case (PH_PULL |INDICATION): - xmit_pull_ind_d(cs, skb); + case (PH_PULL | INDICATION): + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcsx_fill_dfifo blocked"); + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */ cs->hw.hfcsx.mst_m |= HFCSX_MASTER; Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); + spin_unlock_irqrestore(&cs->lock, flags); l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (HW_ENABLE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_DEACTIVATE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER; Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcsx.mst_m |= HFCSX_MASTER; Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): + spin_lock_irqsave(&cs->lock, flags); switch ((int) arg) { case (1): Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */ @@ -814,21 +973,21 @@ HFCSX_l1hw(struct PStack *st, int pr, vo cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1; Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); break; - case (2): Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08; Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); break; - default: + spin_unlock_irqrestore(&cs->lock, flags); if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg); return; } cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); + spin_unlock_irqrestore(&cs->lock, flags); break; default: if (cs->debug & L1_DEB_WARN) @@ -840,11 +999,25 @@ HFCSX_l1hw(struct PStack *st, int pr, vo /***********************************************/ /* called during init setting l1 stack pointer */ /***********************************************/ -static int +void setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = HFCSX_l1hw; - return 0; +} + +/**************************************/ +/* send B-channel data if not blocked */ +/**************************************/ +static void +hfcsx_send_data(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "send_data %d blocked", bcs->channel); } /***************************************************************/ @@ -963,31 +1136,57 @@ mode_hfcsx(struct BCState *bcs, int mode static void hfcsx_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; +// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); + } else { +// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_hfcsx(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + mode_hfcsx(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - mode_hfcsx(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + mode_hfcsx(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -1037,7 +1236,7 @@ setstack_2b(struct PStack *st, struct BC if (open_hfcsxstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = hfcsx_l2l1; + st->l2.l2l1 = hfcsx_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -1048,10 +1247,12 @@ setstack_2b(struct PStack *st, struct BC /* handle L1 state changes */ /***************************/ static void -hfcsx_bh(void *data) +hfcsx_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; + u_long flags; + if (!cs) + return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { if (!cs->hw.hfcsx.nt_mode) switch (cs->dc.hfcsx.ph_state) { @@ -1075,6 +1276,7 @@ hfcsx_bh(void *data) } else { switch (cs->dc.hfcsx.ph_state) { case (2): + spin_lock_irqsave(&cs->lock, flags); if (cs->hw.hfcsx.nt_timer < 0) { cs->hw.hfcsx.nt_timer = 0; cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; @@ -1096,13 +1298,16 @@ hfcsx_bh(void *data) cs->hw.hfcsx.nt_timer = NT_T1_COUNT; Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */ } + spin_unlock_irqrestore(&cs->lock, flags); break; case (1): case (3): case (4): + spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcsx.nt_timer = 0; cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + spin_unlock_irqrestore(&cs->lock, flags); break; default: break; @@ -1115,18 +1320,6 @@ hfcsx_bh(void *data) DChannel_proc_xmt(cs); } -static struct bc_l1_ops hfcsx_bc_l1_ops = { - .fill_fifo = hfcsx_fill_fifo, - .open = setstack_2b, - .close = close_hfcsx, -}; - -static struct dc_l1_ops hfcsx_dc_l1_ops = { - .fill_fifo = hfcsx_fill_dfifo, - .open = setstack_hfcsx, - .bh_func = hfcsx_bh, - .dbusy_func = hfcsx_dbusy_timer, -}; /********************************/ /* called for card init message */ @@ -1134,98 +1327,55 @@ static struct dc_l1_ops hfcsx_dc_l1_ops void __devinit inithfcsx(struct IsdnCardState *cs) { - dc_l1_init(cs, &hfcsx_dc_l1_ops); - cs->bc_l1_ops = &hfcsx_bc_l1_ops; + cs->setstack_d = setstack_hfcsx; + cs->BC_Send_Data = &hfcsx_send_data; + cs->bcs[0].BC_SetStack = setstack_2b; + cs->bcs[1].BC_SetStack = setstack_2b; + cs->bcs[0].BC_Close = close_hfcsx; + cs->bcs[1].BC_Close = close_hfcsx; mode_hfcsx(cs->bcs, 0, 0); mode_hfcsx(cs->bcs + 1, 0, 1); } -static void -hfcsx_init(struct IsdnCardState *cs) -{ - inithfcsx(cs); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ - /* now switch timer interrupt off */ - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - /* reinit mode reg */ - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); -} -static struct card_ops hfcsx_ops = { - .init = hfcsx_init, - .reset = hfcsx_reset, - .release = hfcsx_release, - .irq_func = hfcsx_interrupt, -}; -static int __init -hfcsx_probe(struct IsdnCardState *cs, struct IsdnCard *card) +/*******************************************/ +/* handle card messages from control layer */ +/*******************************************/ +static int +hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int rc; - char c; + u_long flags; - cs->irq = card->para[0]; - cs->hw.hfcsx.base = card->para[1] & 0xfffe; - - cs->hw.hfcsx.fifo = 255; - cs->hw.hfcsx.int_s1 = 0; - cs->dc.hfcsx.ph_state = 0; - - rc = -EBUSY; - if (!request_io(&cs->rs, cs->hw.hfcsx.base, 2, "HFCSX isdn")) - goto err; - - rc = -ENODEV; - byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF); - byteout(cs->hw.hfcsx.base + 1, ((cs->hw.hfcsx.base >> 8) & 3) | 0x54); - udelay(10); - cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID); - switch (cs->hw.hfcsx.chip >> 4) { - case 1: - c ='+'; - break; - case 9: - c ='P'; - break; - default: - printk(KERN_WARNING "HFC-SX: invalid chip id 0x%x\n", - cs->hw.hfcsx.chip >> 4); - goto err; - } - if (!ccd_sp_irqtab[cs->irq & 0xF]) { - printk(KERN_WARNING "HFC_SX: invalid irq %d specified\n", - cs->irq & 0xF); - goto err; - } - rc = -ENOMEM; - cs->hw.hfcsx.extra = kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC); - if (!cs->hw.hfcsx.extra) { - printk(KERN_WARNING "HFC-SX: unable to allocate memory\n"); - goto err; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCSX: card_msg %x", mt); + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_hfcsx(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_RELEASE: + release_io_hfcsx(cs); + return (0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithfcsx(cs); + spin_unlock_irqrestore(&cs->lock, flags); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ + /* now switch timer interrupt off */ + spin_lock_irqsave(&cs->lock, flags); + cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + /* reinit mode reg */ + Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + spin_unlock_irqrestore(&cs->lock, flags); + return (0); + case CARD_TEST: + return (0); } - printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d\n", - c, (u_int) cs->hw.hfcsx.base, cs->irq); - - cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */ - cs->hw.hfcsx.int_m1 = 0; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - - init_timer(&cs->hw.hfcsx.timer); - cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer; - cs->hw.hfcsx.timer.data = (long) cs; - cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */ - cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not eval. */ - - hfcsx_reset(cs); - cs->auxcmd = &hfcsx_auxcmd; - cs->card_ops = &hfcsx_ops; - return 0; - err: - hisax_release_resources(cs); - return rc; + return (0); } #ifdef __ISAPNP__ @@ -1236,66 +1386,133 @@ static struct isapnp_device_id hfc_ids[] { 0, } }; -static struct isapnp_device_id *hdev = &hfc_ids[0]; +static struct isapnp_device_id *ipid __initdata = &hfc_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif int __devinit setup_hfcsx(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, hfcsx_revision); printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp)); #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; - while(hdev->card_vendor) { - if ((pb = pnp_find_card(hdev->card_vendor, - hdev->card_device, - pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - hdev->vendor, - hdev->function, - pd))) { printk(KERN_INFO "HiSax: %s detected\n", - (char *)hdev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "HFC PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "HFC PnP: activate failed\n"); - pnp_device_detach(pd); - return 0; + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) { + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); break; } else { printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); } } - hdev++; - pnp_c=NULL; + ipid++; + pnp_c = NULL; } - if (!hdev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); return(0); } } #endif - if (hfcsx_probe(card->cs, card) < 0) - return 0; - return 1; + cs->hw.hfcsx.base = card->para[1] & 0xfffe; + cs->irq = card->para[0]; + cs->hw.hfcsx.int_s1 = 0; + cs->dc.hfcsx.ph_state = 0; + cs->hw.hfcsx.fifo = 255; + if ((cs->typ == ISDN_CTYPE_HFC_SX) || + (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) { + if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) { + printk(KERN_WARNING + "HiSax: HFC-SX io-base %#lx already in use\n", + cs->hw.hfcsx.base); + return(0); + } + byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF); + byteout(cs->hw.hfcsx.base + 1, + ((cs->hw.hfcsx.base >> 8) & 3) | 0x54); + udelay(10); + cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID); + switch (cs->hw.hfcsx.chip >> 4) { + case 1: + tmp[0] ='+'; + break; + case 9: + tmp[0] ='P'; + break; + default: + printk(KERN_WARNING + "HFC-SX: invalid chip id 0x%x\n", + cs->hw.hfcsx.chip >> 4); + release_region(cs->hw.hfcsx.base, 2); + return(0); + } + if (!ccd_sp_irqtab[cs->irq & 0xF]) { + printk(KERN_WARNING + "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF); + release_region(cs->hw.hfcsx.base, 2); + return(0); + } + if (!(cs->hw.hfcsx.extra = (void *) + kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) { + release_region(cs->hw.hfcsx.base, 2); + printk(KERN_WARNING "HFC-SX: unable to allocate memory\n"); + return(0); + } + printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n", + tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ); + cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */ + cs->hw.hfcsx.int_m1 = 0; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); + } else + return (0); /* no valid card type */ + + cs->dbusytimer.function = (void *) hfcsx_dbusy_timer; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + INIT_WORK(&cs->tqueue, (void *)(void *) hfcsx_bh, cs); + cs->readisac = NULL; + cs->writeisac = NULL; + cs->readisacfifo = NULL; + cs->writeisacfifo = NULL; + cs->BC_Read_Reg = NULL; + cs->BC_Write_Reg = NULL; + cs->irq_func = &hfcsx_interrupt; + + cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer; + cs->hw.hfcsx.timer.data = (long) cs; + cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */ + cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */ + init_timer(&cs->hw.hfcsx.timer); + + reset_hfcsx(cs); + cs->cardmsg = &hfcsx_card_msg; + cs->auxcmd = &hfcsx_auxcmd; + return (1); } diff -puN /dev/null drivers/isdn/hisax/hfc_usb.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/isdn/hisax/hfc_usb.c 2004-02-09 22:19:20.000000000 -0800 @@ -0,0 +1,1667 @@ +/* + * hfc_usb.c + * + * modular HiSax ISDN driver for Colognechip HFC-USB chip + * + * Authors : Peter Sprenger (sprenger@moving-byters.de) + * Martin Bachem (info@colognechip.com) + * based on the first hfc_usb driver of Werner Cornelius (werner@isdn-development.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. + * +*/ + + +#include +#include +#include +#include +#include +#include "hisax.h" +#include +#include +#include +#include +#include +#include +#include "hisax_if.h" + +static const char *hfcusb_revision = "4.0"; + +/* + to enable much mire debug messages in this driver, define + VERBOSE_USB_DEBUG and VERBOSE_ISDN_DEBUG + below +*/ + +#define VERBOSE_USB_DEBUG +#define VERBOSE_ISDN_DEBUG + +#define INCLUDE_INLINE_FUNCS + +#define TRUE 1 +#define FALSE 0 + + +/***********/ +/* defines */ +/***********/ +#define HFC_CTRL_TIMEOUT 20 //(HZ * USB_CTRL_GET_TIMEOUT) +/* 5ms timeout writing/reading regs */ +#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */ +#define HFC_TIMER_T4 500 /* time for state change interval */ + +#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */ +#define HFCUSB_L1_DRX 1 /* D-frame received */ +#define HFCUSB_L1_ERX 2 /* E-frame received */ +#define HFCUSB_L1_DTX 4 /* D-frames completed */ + +#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */ + +#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */ +#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */ + +#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */ +#define HFCUSB_CIRM 0x00 /* cirm register index */ +#define HFCUSB_USB_SIZE 0x07 /* int length register */ +#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */ +#define HFCUSB_F_CROSS 0x0b /* bit order register */ +#define HFCUSB_CLKDEL 0x37 /* bit delay register */ +#define HFCUSB_CON_HDLC 0xfa /* channel connect register */ +#define HFCUSB_HDLC_PAR 0xfb +#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */ +#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */ +#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */ +#define HFCUSB_F_THRES 0x0c /* threshold register */ +#define HFCUSB_FIFO 0x0f /* fifo select register */ +#define HFCUSB_F_USAGE 0x1a /* fifo usage register */ +#define HFCUSB_MST_MODE0 0x14 +#define HFCUSB_MST_MODE1 0x15 +#define HFCUSB_P_DATA 0x1f +#define HFCUSB_INC_RES_F 0x0e +#define HFCUSB_STATES 0x30 + +#define HFCUSB_CHIPID 0x40 /* ID value of HFC-USB */ + +/******************/ +/* fifo registers */ +/******************/ +#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */ +#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */ +#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */ +#define HFCUSB_B2_TX 2 +#define HFCUSB_B2_RX 3 +#define HFCUSB_D_TX 4 +#define HFCUSB_D_RX 5 +#define HFCUSB_PCM_TX 6 +#define HFCUSB_PCM_RX 7 + +/* +* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just +* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out +*/ +#define USB_INT 0 +#define USB_BULK 1 +#define USB_ISOC 2 + +#define ISOC_PACKETS_D 8 +#define ISOC_PACKETS_B 8 +#define ISO_BUFFER_SIZE 128 + +// ISO send definitions +#define SINK_MAX 68 +#define SINK_MIN 48 +#define SINK_DMIN 12 +#define SINK_DMAX 18 +#define BITLINE_INF (-64*8) + + + + +/**********/ +/* macros */ +/**********/ +#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT) +#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT) + +/*************************************************/ +/* entry and size of output/input control buffer */ +/*************************************************/ +#define HFC_CTRL_BUFSIZE 32 +typedef struct +{ + __u8 hfc_reg; /* register number */ + __u8 reg_val; /* value to be written (or read) */ + int action; /* data for action handler */ + +} ctrl_buft; + +typedef struct +{ + int vendor; // vendor id + int prod_id; // product id + char *vend_name; // vendor string + __u8 led_scheme; // led display scheme + __u8 led_invert; // invert led aux port settings + __u8 led_bits[8]; // array of 8 possible LED bitmask settings + +} vendor_data; + +/***************************************************************/ +/* structure defining input+output fifos (interrupt/bulk mode) */ +/***************************************************************/ + +struct usb_fifo; /* forward definition */ +typedef struct iso_urb_struct +{ + struct urb *purb; + __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */ + struct usb_fifo *owner_fifo; // pointer to owner fifo +} iso_urb_struct; + + +struct hfcusb_data; /* forward definition */ +typedef struct usb_fifo +{ + int fifonum; /* fifo index attached to this structure */ + int active; /* fifo is currently active */ + struct hfcusb_data *hfc; /* pointer to main structure */ + int pipe; /* address of endpoint */ + __u8 usb_packet_maxlen; /* maximum length for usb transfer */ + unsigned int max_size; /* maximum size of receive/send packet */ + __u8 intervall; /* interrupt interval */ + struct sk_buff *skbuff; /* actual used buffer */ + struct urb *urb; /* transfer structure for usb routines */ + __u8 buffer[128]; /* buffer incoming/outgoing data */ + int bit_line; /* how much bits are in the fifo? */ + + volatile __u8 usb_transfer_mode;/* switched between ISO and INT */ + iso_urb_struct iso[2]; /* need two urbs to have one always for pending */ + struct hisax_if *hif; /* hisax interface */ + int delete_flg; /* only delete skbuff once */ + int last_urblen; /* remember length of last packet */ + +} usb_fifo; + + +/*********************************************/ +/* structure holding all data for one device */ +/*********************************************/ +typedef struct hfcusb_data +{ + // HiSax Interface for loadable Layer1 drivers + struct hisax_d_if d_if; /* see hisax_if.h */ + struct hisax_b_if b_if[2]; /* see hisax_if.h */ + int protocol; + + struct usb_device *dev; /* our device */ + int if_used; /* used interface number */ + int alt_used; /* used alternate config */ + int ctrl_paksize; /* control pipe packet size */ + int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */ + int cfg_used; /* configuration index used */ + int vend_idx; // vendor found + + int b_mode[2]; // B-channel mode + + int l1_activated; // layer 1 activated + + int packet_size,iso_packet_size; + + /* control pipe background handling */ + ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */ + volatile int ctrl_in_idx, ctrl_out_idx, + ctrl_cnt; /* input/output pointer + count */ + struct urb *ctrl_urb; /* transfer structure for control channel */ + + struct usb_ctrlrequest ctrl_write; /* buffer for control write request */ + struct usb_ctrlrequest ctrl_read; /* same for read request */ + + __u8 led_state,led_new_data,led_b_active; + + volatile __u8 threshold_mask; /* threshold actually reported */ + volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */ + + usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */ + + volatile __u8 l1_state; /* actual l1 state */ + struct timer_list t3_timer; /* timer 3 for activation/deactivation */ + struct timer_list t4_timer; /* timer 4 for activation/deactivation */ + struct timer_list led_timer; /* timer flashing leds */ + +} hfcusb_data; + + +static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish); + + + +/******************************************************/ +/* start next background transfer for control channel */ +/******************************************************/ +static void ctrl_start_transfer(hfcusb_data * hfc) +{ + int err; + if(hfc->ctrl_cnt) + { + hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe; + hfc->ctrl_urb->setup_packet = (u_char *) & hfc->ctrl_write; + hfc->ctrl_urb->transfer_buffer = NULL; + hfc->ctrl_urb->transfer_buffer_length = 0; + hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg; + hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val; + err = usb_submit_urb(hfc->ctrl_urb, GFP_KERNEL); /* start transfer */ + printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err); + } +} /* ctrl_start_transfer */ + +/************************************/ +/* queue a control transfer request */ +/* return 0 on success. */ +/************************************/ +static int queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val,int action) +{ + ctrl_buft *buf; + +#ifdef VERBOSE_USB_DEBUG + printk ("HFC_USB: queue_control_request reg: %x, val: %x\n", reg, val); +#endif + + if(hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE) return(1); /* no space left */ + buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */ + buf->hfc_reg = reg; + buf->reg_val = val; + buf->action=action; + if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE) + hfc->ctrl_in_idx = 0; /* pointer wrap */ + if (++hfc->ctrl_cnt == 1) + ctrl_start_transfer(hfc); + return(0); +} /* queue_control_request */ + + +static int control_action_handler(hfcusb_data *hfc,int reg,int val,int action) +{ + if(!action) return(1); // no action defined + + return(0); +} + + +/***************************************************************/ +/* control completion routine handling background control cmds */ +/***************************************************************/ +static void ctrl_complete(struct urb *urb, struct pt_regs *regs) +{ + hfcusb_data *hfc = (hfcusb_data *) urb->context; + ctrl_buft *buf; + + printk(KERN_DEBUG "ctrl_complete cnt %d\n", hfc->ctrl_cnt); + urb->dev = hfc->dev; + if(hfc->ctrl_cnt) + { + buf=&hfc->ctrl_buff[hfc->ctrl_out_idx]; + control_action_handler(hfc,buf->hfc_reg,buf->reg_val,buf->action); + + hfc->ctrl_cnt--; /* decrement actual count */ + if(++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0; /* pointer wrap */ + + ctrl_start_transfer(hfc); /* start next transfer */ + } +} /* ctrl_complete */ + + + +#define LED_OFF 0 // no LED support +#define LED_SCHEME1 1 // LED standard scheme +#define LED_SCHEME2 2 // not used yet... + +#define LED_POWER_ON 1 +#define LED_POWER_OFF 2 +#define LED_S0_ON 3 +#define LED_S0_OFF 4 +#define LED_B1_ON 5 +#define LED_B1_OFF 6 +#define LED_B1_DATA 7 +#define LED_B2_ON 8 +#define LED_B2_OFF 9 +#define LED_B2_DATA 10 + +#define LED_NORMAL 0 // LEDs are normal +#define LED_INVERTED 1 // LEDs are inverted + +// time for LED flashing +#define LED_TIME 250 + +vendor_data vdata[]= +{ + {0x959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", LED_OFF,LED_NORMAL,{4,0,2,1}}, /* CologneChip Eval TA */ + {0x7b0, 0x0007, "Billion tiny USB ISDN TA 128", LED_SCHEME1, LED_INVERTED, {8,0x40,0x20,0x10}}, /* Billion TA */ + {0x742, 0x2008, "Stollmann USB TA", LED_SCHEME1, LED_NORMAL, {4,0,2,1}}, /* Stollmann TA */ + {0x8e3, 0x0301, "Olitec USB RNIS", LED_SCHEME1, LED_NORMAL, {2,0,1,4}}, /* Olitec TA */ + {0x675, 0x1688, "DrayTec USB ISDN TA", LED_SCHEME1, LED_NORMAL, {4,0,2,1}}, /* Draytec TA */ + {0x7fa, 0x0846, "Bewan Modem RNIS USB", LED_SCHEME1, LED_INVERTED, {8,0x40,0x20,0x10}}, /* Bewan TA */ + {0,0,0} // EOL element +}; + +/***************************************************/ +/* write led data to auxport & invert if necessary */ +/***************************************************/ +static void write_led(hfcusb_data * hfc,__u8 led_state) +{ + if(led_state!=hfc->led_state) + { + hfc->led_state=led_state; + queue_control_request(hfc, HFCUSB_P_DATA,(vdata[hfc->vend_idx].led_invert) ? ~led_state : led_state,1); + } +} + +/******************************************/ +/* invert B-channel LEDs if data is sent */ +/******************************************/ +static void led_timer(hfcusb_data * hfc) +{ + static int cnt=0; + __u8 led_state=hfc->led_state; + + if(cnt) + { + if(hfc->led_b_active&1) led_state|=vdata[hfc->vend_idx].led_bits[2]; + if(hfc->led_b_active&2) led_state|=vdata[hfc->vend_idx].led_bits[3]; + } + else + { + if(!(hfc->led_b_active&1) || hfc->led_new_data&1) led_state&=~vdata[hfc->vend_idx].led_bits[2]; + if(!(hfc->led_b_active&2) || hfc->led_new_data&2) led_state&=~vdata[hfc->vend_idx].led_bits[3]; + } + + write_led(hfc,led_state); + hfc->led_new_data=0; + + cnt=!cnt; + // restart 4 hz timer + hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000; + if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer); +} + +/**************************/ +/* handle LED requests */ +/**************************/ +static void handle_led(hfcusb_data * hfc,int event) +{ + __u8 led_state=hfc->led_state; + + // if no scheme -> no LED action + if(vdata[hfc->vend_idx].led_scheme==LED_OFF) return; + + switch(event) + { + case LED_POWER_ON: + led_state|=vdata[hfc->vend_idx].led_bits[0]; + break; + case LED_POWER_OFF: // no Power off handling + break; + case LED_S0_ON: + led_state|=vdata[hfc->vend_idx].led_bits[1]; + break; + case LED_S0_OFF: + led_state&=~vdata[hfc->vend_idx].led_bits[1]; + break; + case LED_B1_ON: + hfc->led_b_active|=1; + break; + case LED_B1_OFF: + hfc->led_b_active&=~1; + break; + case LED_B1_DATA: + hfc->led_new_data|=1; + break; + case LED_B2_ON: + hfc->led_b_active|=2; + break; + case LED_B2_OFF: + hfc->led_b_active&=~2; + break; + case LED_B2_DATA: + hfc->led_new_data|=2; + break; + } + + write_led(hfc,led_state); +} + +/********************************/ +/* called when timer t3 expires */ +/********************************/ +static void l1_timer_expire_t3(hfcusb_data * hfc) +{ + //printk (KERN_INFO "HFC-USB: l1_timer_expire_t3\n"); + + hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL); +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n"); +#endif + hfc->l1_activated=FALSE; + handle_led(hfc,LED_S0_OFF); +} + +/********************************/ +/* called when timer t4 expires */ +/********************************/ +static void l1_timer_expire_t4(hfcusb_data * hfc) +{ + //printk (KERN_INFO "HFC-USB: l1_timer_expire_t4\n"); + + hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL); +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n"); +#endif + hfc->l1_activated=FALSE; + handle_led(hfc,LED_S0_OFF); +} + +/*****************************/ +/* handle S0 state changes */ +/*****************************/ +static void state_handler(hfcusb_data * hfc,__u8 state) +{ + __u8 old_state; + + old_state=hfc->l1_state; + + // range check + if(state==old_state || state<1 || state>8) return; + +#ifdef VERBOSE_ISDN_DEBUG + printk(KERN_INFO "HFC-USB: new S0 state:%d old_state:%d\n",state,old_state); +#endif + + if(state<4 || state==7 || state==8) + { + if(timer_pending(&hfc->t3_timer)) del_timer(&hfc->t3_timer); + //printk(KERN_INFO "HFC-USB: T3 deactivated\n"); + } + + if(state>=7) + { + if(timer_pending(&hfc->t4_timer)) del_timer(&hfc->t4_timer); + //printk(KERN_INFO "HFC-USB: T4 deactivated\n"); + } + + if(state==7 && !hfc->l1_activated) + { + hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_ACTIVATE | INDICATION,NULL); + //printk(KERN_INFO "HFC-USB: PH_ACTIVATE | INDICATION sent\n"); + hfc->l1_activated=TRUE; + handle_led(hfc,LED_S0_ON); + } + else + if(state<=3 /* && activated*/) + { + if(old_state==7 || old_state==8) + { + //printk(KERN_INFO "HFC-USB: T4 activated\n"); + hfc->t4_timer.expires = jiffies + (HFC_TIMER_T4 * HZ) / 1000; + if(!timer_pending(&hfc->t4_timer)) add_timer(&hfc->t4_timer); + } + else + { + hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL); + //printk(KERN_INFO "HFC-USB: PH_DEACTIVATE | INDICATION sent\n"); + hfc->l1_activated=FALSE; + handle_led(hfc,LED_S0_OFF); + } + } + + hfc->l1_state=state; +} + + +/* prepare iso urb */ +static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf, + int num_packets, int packet_size, int interval, usb_complete_t complete, void *context) +{ + int k; + + spin_lock_init(&urb->lock); // do we really need spin_lock_init ? + urb->dev = dev; + urb->pipe = pipe; + urb->complete = complete; + urb->number_of_packets = num_packets; + urb->transfer_buffer_length = packet_size * num_packets; + urb->context = context; + urb->transfer_buffer = buf; + urb->transfer_flags = 0; + urb->transfer_flags = URB_ISO_ASAP; + urb->actual_length = 0; + urb->interval = interval; + for (k = 0; k < num_packets; k++) { + urb->iso_frame_desc[k].offset = packet_size * k; + urb->iso_frame_desc[k].length = packet_size; + urb->iso_frame_desc[k].actual_length = 0; + } +} + +/* allocs urbs and start isoc transfer with two pending urbs to avoid gaps in the transfer chain */ +static int start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,usb_complete_t complete,int packet_size) +{ + int i, k, errcode; + +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: starting ISO-chain for Fifo %i\n", fifo->fifonum); +#endif + + + // allocate Memory for Iso out Urbs + for (i = 0; i < 2; i++) { + if (!(fifo->iso[i].purb)) { + fifo->iso[i].purb = usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); + fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; + + // Init the first iso + if (ISO_BUFFER_SIZE >= (fifo->usb_packet_maxlen * num_packets_per_urb)) + { + + fill_isoc_urb(fifo->iso[i].purb, fifo->hfc->dev, fifo->pipe, fifo->iso[i].buffer, + num_packets_per_urb, fifo->usb_packet_maxlen, fifo->intervall, + complete, &fifo->iso[i]); + + memset(fifo->iso[i].buffer, 0, sizeof(fifo->iso[i].buffer)); + + // defining packet delimeters in fifo->buffer + for(k = 0; k < num_packets_per_urb; k++) + { + fifo->iso[i].purb->iso_frame_desc[k].offset = k*packet_size; + fifo->iso[i].purb->iso_frame_desc[k].length = packet_size; + } + } + } + + fifo->bit_line = BITLINE_INF; + + errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL); + fifo->active = (errcode >= 0) ? 1 : 0; + if(errcode < 0) + { + printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i.%i \n", errcode, i); + }; + + } + + // errcode = (usb_submit_urb(fifo->iso[0].purb, GFP_KERNEL)); + return(fifo->active); +} + +/* stops running iso chain and frees their pending urbs */ +static void stop_isoc_chain(usb_fifo * fifo) +{ + int i; + + for(i = 0; i < 2; i++) + { + if(fifo->iso[i].purb) + { +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: Stopping iso chain for fifo %i.%i\n", fifo->fifonum, i); +#endif + usb_unlink_urb(fifo->iso[i].purb); + usb_free_urb(fifo->iso[i].purb); + fifo->iso[i].purb = NULL; + } + } + if (fifo->urb) { + usb_unlink_urb(fifo->urb); + usb_free_urb(fifo->urb); + fifo->urb = NULL; + } + fifo->active = 0; +} + +// defines how much ISO packets are handled in one URB +static int iso_packets[8]={ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B, + ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D}; + +/*****************************************************/ +/* transmit completion routine for all ISO tx fifos */ +/*****************************************************/ +static void tx_iso_complete(struct urb *urb, struct pt_regs *regs) +{ + iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; + usb_fifo *fifo = context_iso_urb->owner_fifo; + hfcusb_data *hfc = fifo->hfc; + int k, tx_offset, num_isoc_packets, sink, len, current_len,errcode,frame_complete,transp_mode,fifon; + __u8 threshbit; + __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + + fifon=fifo->fifonum; + tx_offset=0; + // very weird error code when using ohci drivers, for now : ignore this error ... (MB) + if(urb->status == -EOVERFLOW) + { + urb->status = 0; +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",fifon); +#endif + } + + if(fifo->active && !urb->status) + { + transp_mode=0; + if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE; + + threshbit = threshtable[fifon] & hfc->threshold_mask; // is threshold set for our channel? + num_isoc_packets=iso_packets[fifon]; + + if(fifon >= HFCUSB_D_TX) + { + sink = (threshbit) ? SINK_DMIN : SINK_DMAX; // how much bit go to the sink for D-channel? + } + else + { + sink = (threshbit) ? SINK_MIN : SINK_MAX; // how much bit go to the sink for B-channel? + } + + // prepare ISO Urb + fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets, + fifo->usb_packet_maxlen, fifo->intervall, tx_iso_complete, urb->context); + memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer)); + + frame_complete=FALSE; + + // Generate Iso Packets + for(k = 0; k < num_isoc_packets; ++k) + { + if(fifo->skbuff) + { + len = fifo->skbuff->len; // remaining length + + fifo->bit_line -= sink; // we lower data margin every msec + current_len = (0 - fifo->bit_line) / 8; + if(current_len > 14) current_len = 14; // maximum 15 byte for every ISO packet makes our life easier + current_len = (len <= current_len) ? len : current_len; + fifo->bit_line += current_len * 8; // how much bit do we put on the line? + + context_iso_urb->buffer[tx_offset] = 0; + if(current_len == len) + { + if(!transp_mode) + { + context_iso_urb->buffer[tx_offset] = 1; // here frame completion + fifo->bit_line += 32; // add 2 byte flags and 16bit CRC at end of ISDN frame + } + frame_complete = TRUE; + } + + // copy bytes from buffer into ISO_URB + memcpy(context_iso_urb->buffer+tx_offset+1,fifo->skbuff->data,current_len); + skb_pull(fifo->skbuff,current_len); + + // define packet delimeters within the URB buffer + urb->iso_frame_desc[k].offset = tx_offset; + urb->iso_frame_desc[k].length = current_len + 1; + + tx_offset += (current_len + 1); + // printk(KERN_INFO "HFC-USB: fifonum:%d,%d bytes to send, %d bytes ISO packet,bitline:%d,sink:%d,threshbit:%d,threshmask:%x\n",fifon,len,current_len,fifo->bit_line,sink,threshbit,hfc->threshold_mask); + if(!transp_mode) + { + if(fifon==HFCUSB_B1_TX) handle_led(hfc,LED_B1_DATA); + if(fifon==HFCUSB_B2_TX) handle_led(hfc,LED_B2_DATA); + } + } + else + { + // we have no more data - generate 1 byte ISO packets + urb->iso_frame_desc[k].offset = tx_offset++; + + urb->iso_frame_desc[k].length = 1; + fifo->bit_line -= sink; // we lower data margin every msec + + if(fifo->bit_line < BITLINE_INF) + { + fifo->bit_line = BITLINE_INF; + //printk (KERN_INFO "HFC-USB: BITLINE_INF underrun\n"); + } + } + + if(frame_complete) + { + // delete the buffer only once, here or in hfc_usb_l2l1() in a PH_DATA|REQUEST + fifo->delete_flg=TRUE; + + fifo->hif->l1l2(fifo->hif,PH_DATA|CONFIRM,(void*)fifo->skbuff->truesize); + + if(fifo->skbuff && fifo->delete_flg) + { + dev_kfree_skb_any(fifo->skbuff); + //printk(KERN_INFO "HFC-USB: skbuff=NULL on fifo:%d\n",fifo->fifonum); + fifo->skbuff = NULL; + fifo->delete_flg=FALSE; + } + + frame_complete=FALSE; + } + } + + errcode = usb_submit_urb(urb, GFP_KERNEL); + if(errcode < 0) + { + printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); + } + } + else + { + if(urb->status) + { + printk(KERN_INFO "HFC-USB: tx_iso_complete : urb->status %i, fifonum %i\n", urb->status,fifon); + } + } + +} /* tx_iso_complete */ + +/*****************************************************/ +/* receive completion routine for all ISO tx fifos */ +/*****************************************************/ +static void rx_iso_complete(struct urb *urb, struct pt_regs *regs) +{ + iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; + usb_fifo *fifo = context_iso_urb->owner_fifo; + hfcusb_data *hfc = fifo->hfc; + int k, len, errcode, offset, num_isoc_packets,fifon; + __u8 *buf; + + fifon=fifo->fifonum; + // very weird error code when using ohci drivers, for now : ignore this error ... (MB) + if(urb->status == -EOVERFLOW) + { + urb->status = 0; +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",fifon); +#endif + } + + if(fifo->active && !urb->status) + { + num_isoc_packets=iso_packets[fifon]; + + // Generate D-Channel Iso Packets + for(k = 0; k < num_isoc_packets; ++k) + { + len=urb->iso_frame_desc[k].actual_length; + offset=urb->iso_frame_desc[k].offset; + buf=context_iso_urb->buffer+offset; + + if(fifo->last_urblen!=fifo->usb_packet_maxlen) + { + // the threshold mask is in the 2nd status byte + hfc->threshold_mask=buf[1]; + // the S0 state is in the upper half of the 1st status byte + state_handler(hfc,buf[0] >> 4); + // if we have more than the 2 status bytes -> collect data + if(len>2) collect_rx_frame(fifo,buf+2,len-2,buf[0]&1); + } + else collect_rx_frame(fifo,buf,len,0); + + fifo->last_urblen=len; + + } + + // prepare ISO Urb + fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets, + fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context); + + errcode = usb_submit_urb(urb, GFP_KERNEL); + if(errcode < 0) + { + printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); + } + } + else + { + if(urb->status) + { + printk(KERN_INFO "HFC-USB: rx_iso_complete : urb->status %i, fifonum %i\n", urb->status,fifon); + } + } +} /* rx_iso_complete */ + + +/*****************************************************/ +/* collect data from interrupt or isochron in */ +/*****************************************************/ +static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish) +{ + hfcusb_data *hfc = fifo->hfc; + int transp_mode,fifon; + + fifon=fifo->fifonum; + transp_mode=0; + if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE; + + //printk(KERN_INFO "HFC-USB: got %d bytes finish:%d max_size:%d fifo:%d\n",len,finish,fifo->max_size,fifon); + if(!fifo->skbuff) + { + // allocate sk buffer + fifo->skbuff=dev_alloc_skb(fifo->max_size + 3); + if(!fifo->skbuff) + { + printk(KERN_INFO "HFC-USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",fifon); + return; + } + + } + + if(len && fifo->skbuff->len+lenmax_size) + { + memcpy(skb_put(fifo->skbuff,len),data,len); + } + else printk(KERN_INFO "HCF-USB: got frame exceeded fifo->max_size:%d\n",fifo->max_size); + + // give transparent data up, when 128 byte are available + if(transp_mode && fifo->skbuff->len>=128) + { + fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff); + fifo->skbuff = NULL; // buffer was freed from upper layer + return; + } + + // we have a complete hdlc packet + if(finish) + { + if(!fifo->skbuff->data[fifo->skbuff->len-1]) + { + skb_trim(fifo->skbuff,fifo->skbuff->len-3); // remove CRC & status + + //printk(KERN_INFO "HFC-USB: got frame %d bytes on fifo:%d\n",fifo->skbuff->len,fifon); + + if(fifon==HFCUSB_PCM_RX) fifo->hif->l1l2(fifo->hif,PH_DATA_E | INDICATION,fifo->skbuff); + else fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff); + + fifo->skbuff = NULL; // buffer was freed from upper layer + } + else + { + printk(KERN_INFO "HFC-USB: got frame %d bytes but CRC ERROR!!!\n",fifo->skbuff->len); + + skb_trim(fifo->skbuff,0); // clear whole buffer + } + } + + // LED flashing only in HDLC mode + if(!transp_mode) + { + if(fifon==HFCUSB_B1_RX) handle_led(hfc,LED_B1_DATA); + if(fifon==HFCUSB_B2_RX) handle_led(hfc,LED_B2_DATA); + } +} + +/***********************************************/ +/* receive completion routine for all rx fifos */ +/***********************************************/ +static void rx_complete(struct urb *urb, struct pt_regs *regs) +{ + int len; + __u8 *buf; + usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */ + hfcusb_data *hfc = fifo->hfc; + + urb->dev = hfc->dev; /* security init */ + + if((!fifo->active) || (urb->status)) { +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: RX-Fifo %i is going down (%i)\n", fifo->fifonum, urb->status); +#endif + fifo->urb->interval = 0; /* cancel automatic rescheduling */ + if(fifo->skbuff) { + dev_kfree_skb_any(fifo->skbuff); + fifo->skbuff = NULL; + } + return; + } + + len=urb->actual_length; + buf=fifo->buffer; + + if(fifo->last_urblen!=fifo->usb_packet_maxlen) { + // the threshold mask is in the 2nd status byte + hfc->threshold_mask=buf[1]; + // the S0 state is in the upper half of the 1st status byte + state_handler(hfc,buf[0] >> 4); + // if we have more than the 2 status bytes -> collect data + if(len>2) collect_rx_frame(fifo,buf+2,urb->actual_length-2,buf[0]&1); + } else + collect_rx_frame(fifo,buf,urb->actual_length,0); + + fifo->last_urblen=urb->actual_length; + + +} /* rx_complete */ + + + +/***************************************************/ +/* start the interrupt transfer for the given fifo */ +/***************************************************/ +static void start_int_fifo(usb_fifo * fifo) +{ + int errcode; + +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: starting intr IN fifo:%d\n", fifo->fifonum); +#endif + if (!fifo->urb) { + fifo->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!fifo->urb) + return; + } + usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer, + fifo->usb_packet_maxlen, rx_complete, fifo, fifo->intervall); + fifo->active = 1; /* must be marked active */ + errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); + + if(errcode) + { + printk(KERN_INFO "HFC-USB: submit URB error(start_int_info): status:%i\n", errcode); + fifo->active = 0; + fifo->skbuff = NULL; + } +} /* start_int_fifo */ + +/*****************************/ +/* set the B-channel mode */ +/*****************************/ +static void set_hfcmode(hfcusb_data *hfc,int channel,int mode) +{ + __u8 val,idx_table[2]={0,2}; + +#ifdef VERBOSE_ISDN_DEBUG + printk (KERN_INFO "HFC-USB: setting channel %d to mode %d\n",channel,mode); +#endif + + hfc->b_mode[channel]=mode; + + // setup CON_HDLC + val=0; + if(mode!=L1_MODE_NULL) val=8; // enable fifo? + if(mode==L1_MODE_TRANS) val|=2; // set transparent bit + + queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel],1); // set FIFO to transmit register + queue_control_request(hfc,HFCUSB_CON_HDLC,val,1); + queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo + + queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel]+1,1); // set FIFO to receive register + queue_control_request(hfc,HFCUSB_CON_HDLC,val,1); + queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo + + val=0x40; + if(hfc->b_mode[0]) val|=1; + if(hfc->b_mode[1]) val|=2; + queue_control_request(hfc,HFCUSB_SCTRL,val,1); + + val=0; + if(hfc->b_mode[0]) val|=1; + if(hfc->b_mode[1]) val|=2; + queue_control_request(hfc,HFCUSB_SCTRL_R,val,1); + + if(mode==L1_MODE_NULL) + { + if(channel) handle_led(hfc,LED_B2_OFF); + else handle_led(hfc,LED_B1_OFF); + } + else + { + if(channel) handle_led(hfc,LED_B2_ON); + else handle_led(hfc,LED_B1_ON); + } +} + +/* + -------------------------------------------------------------------------------------- + from here : hisax_if callback routines : + - void hfc_usb_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) { + + l1 to l2 routines : + - static void hfc_usb_l1l2(hfcusb_data * hfc) + +*/ + +void hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg) +{ + usb_fifo *fifo = my_hisax_if->priv; + hfcusb_data *hfc = fifo->hfc; + + switch (pr) { + case PH_ACTIVATE | REQUEST: + if(fifo->fifonum==HFCUSB_D_TX) + { +#ifdef VERBOSE_ISDN_DEBUG + printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST\n"); +#endif + queue_control_request(hfc, HFCUSB_STATES,0x60,1); /* make activation */ + hfc->t3_timer.expires = jiffies + (HFC_TIMER_T3 * HZ) / 1000; + if(!timer_pending(&hfc->t3_timer)) add_timer(&hfc->t3_timer); + } + else + { +#ifdef VERBOSE_ISDN_DEBUG + printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST\n"); +#endif + set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)arg); + fifo->hif->l1l2(fifo->hif,PH_ACTIVATE | INDICATION, NULL); + } + break; + case PH_DEACTIVATE | REQUEST: + if(fifo->fifonum==HFCUSB_D_TX) + { +#ifdef VERBOSE_ISDN_DEBUG + printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST\n"); +#endif + printk (KERN_INFO "HFC-USB: ISDN TE device should not deativate...\n"); + } + else + { +#ifdef VERBOSE_ISDN_DEBUG + printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST\n"); +#endif + set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)L1_MODE_NULL); + fifo->hif->l1l2(fifo->hif,PH_DEACTIVATE | INDICATION, NULL); + } + break; + case PH_DATA | REQUEST: + if(fifo->skbuff && fifo->delete_flg) + { + dev_kfree_skb_any(fifo->skbuff); + //printk(KERN_INFO "skbuff=NULL on fifo:%d\n",fifo->fifonum); + fifo->skbuff = NULL; + fifo->delete_flg=FALSE; + } + + fifo->skbuff=arg; // we have a new buffer + + //if(fifo->fifonum==HFCUSB_D_TX) printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DATA | REQUEST\n"); + //else printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DATA | REQUEST\n"); + break; + default: + printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n", pr); + break; + } +} + +// valid configurations +#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT +#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT +#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT +#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT + + +/* + -------------------------------------------------------------------------------------- + From here on USB initialization and deactivation related routines are implemented : + + - hfc_usb_init : + is the main Entry Point for the USB Subsystem when the device get plugged + in. This function calls usb_register with usb_driver as parameter. + Here, further entry points for probing (hfc_usb_probe) and disconnecting + the device (hfc_usb_disconnect) are published, as the id_table + + - hfc_usb_probe + this function is called by the usb subsystem, and steps through the alternate + settings of the currently plugged in device to detect all Endpoints needed to + run an ISDN TA. + Needed EndPoints are + 3 (+1) IntIn EndPoints (D-in, E-in, B1-in, B2-in, (E-in)) or + 3 (+1) Isochron In Endpoints (D-out, B1-out, B2-out) and 3 IsoOut Endpoints + The currently used transfer mode of on the Out-Endpoints will be stored in + hfc->usb_transfer_mode and is either USB_INT or USB_ISO + When a valid alternate setting could be found, the usb_init (see blow) + function is called + + - usb_init + Here, the HFC_USB Chip itself gets initialized and the USB framework to send/receive + Data to/from the several EndPoints are initialized: + The E- and D-Channel Int-In chain gets started + The IsoChain for the Iso-Out traffic get started + + - hfc_usb_disconnect + this function is called by the usb subsystem and has to free all resources + and stop all usb traffic to allow a proper hotplugging disconnect. + +*/ + +/***************************************************************************/ +/* usb_init is called once when a new matching device is detected to setup */ +/* main parameters. It registers the driver at the main hisax module. */ +/* on success 0 is returned. */ +/***************************************************************************/ +static int usb_init(hfcusb_data * hfc) +{ + usb_fifo *fifo; + int i, err; + u_char b; + struct hisax_b_if *p_b_if[2]; + + /* check the chip id */ + printk(KERN_INFO "HFCUSB_CHIP_ID begin\n"); + if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) { + printk(KERN_INFO "HFC-USB: cannot read chip id\n"); + return(1); + } + printk(KERN_INFO "HFCUSB_CHIP_ID %x\n", b); + if (b != HFCUSB_CHIPID) { + printk(KERN_INFO "HFC-USB: Invalid chip id 0x%02x\n", b); + return(1); + } + + /* first set the needed config, interface and alternate */ + printk(KERN_INFO "usb_init 1\n"); +// usb_set_configuration(hfc->dev, 1); + printk(KERN_INFO "usb_init 2\n"); + err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); + printk(KERN_INFO "usb_init usb_set_interface return %d\n", err); + /* now we initialize the chip */ + write_usb(hfc, HFCUSB_CIRM, 8); // do reset + write_usb(hfc, HFCUSB_CIRM, 0x10); // aux = output, reset off + + // set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers + write_usb(hfc, HFCUSB_USB_SIZE,(hfc->packet_size/8) | ((hfc->packet_size/8) << 4)); + + // set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers + write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size); + + /* enable PCM/GCI master mode */ + write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */ + write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */ + + /* init the fifos */ + write_usb(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD/8) |((HFCUSB_RX_THRESHOLD/8) << 4)); + + fifo = hfc->fifos; + for(i = 0; i < HFCUSB_NUM_FIFOS; i++) + { + write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */ + fifo[i].skbuff = NULL; /* init buffer pointer */ + fifo[i].max_size = (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; + fifo[i].last_urblen=0; + write_usb(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); // set 2 bit for D- & E-channel + write_usb(hfc, HFCUSB_CON_HDLC, ((i==HFCUSB_D_TX) ? 0x09 : 0x08)); // rx hdlc, enable IFF for D-channel + write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */ + } + + write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */ + write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */ + write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */ + + write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ + write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */ + + // set both B-channel to not connected + hfc->b_mode[0]=L1_MODE_NULL; + hfc->b_mode[1]=L1_MODE_NULL; + + hfc->l1_activated=FALSE; + hfc->led_state=0; + hfc->led_new_data=0; + + /* init the t3 timer */ + init_timer(&hfc->t3_timer); + hfc->t3_timer.data = (long) hfc; + hfc->t3_timer.function = (void *) l1_timer_expire_t3; + /* init the t4 timer */ + init_timer(&hfc->t4_timer); + hfc->t4_timer.data = (long) hfc; + hfc->t4_timer.function = (void *) l1_timer_expire_t4; + /* init the led timer */ + init_timer(&hfc->led_timer); + hfc->led_timer.data = (long) hfc; + hfc->led_timer.function = (void *) led_timer; + // trigger 4 hz led timer + hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000; + if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer); + + // init the background machinery for control requests + hfc->ctrl_read.bRequestType = 0xc0; + hfc->ctrl_read.bRequest = 1; + hfc->ctrl_read.wLength = 1; + hfc->ctrl_write.bRequestType = 0x40; + hfc->ctrl_write.bRequest = 0; + hfc->ctrl_write.wLength = 0; + usb_fill_control_urb(hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe,(u_char *) & hfc->ctrl_write, NULL, 0, ctrl_complete, hfc); + + /* Init All Fifos */ + for(i = 0; i < HFCUSB_NUM_FIFOS; i++) + { + hfc->fifos[i].iso[0].purb = NULL; + hfc->fifos[i].iso[1].purb = NULL; + hfc->fifos[i].active = 0; + } + + // register like Germaschewski : + hfc->d_if.owner = THIS_MODULE; + hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX]; + hfc->d_if.ifc.l2l1 = hfc_usb_l2l1; + + for (i=0; i<2; i++) + { + hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX+i*2]; + hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1; + p_b_if[i] = &hfc->b_if[i]; + } + + hfc->protocol = 2; /* default EURO ISDN, should be a module_param */ + hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol); + + for (i=0; i<4; i++) + hfc->fifos[i].hif=&p_b_if[i/2]->ifc; + for (i=4; i<8; i++) + hfc->fifos[i].hif=&hfc->d_if.ifc; + + // 3 (+1) INT IN + 3 ISO OUT + if(hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) + { + start_int_fifo(hfc->fifos + HFCUSB_D_RX); // Int IN D-fifo + if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(hfc->fifos + HFCUSB_PCM_RX); // E-fifo + start_int_fifo(hfc->fifos + HFCUSB_B1_RX); // Int IN B1-fifo + start_int_fifo(hfc->fifos + HFCUSB_B2_RX); // Int IN B2-fifo + } + + // 3 (+1) ISO IN + 3 ISO OUT + if(hfc->cfg_used==CNF_3ISO3ISO || hfc->cfg_used==CNF_4ISO3ISO) + { + start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D, rx_iso_complete,16); + if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX, ISOC_PACKETS_D, rx_iso_complete,16); + start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B, rx_iso_complete,16); + start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B, rx_iso_complete,16); + } + + start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, tx_iso_complete,1); + start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, tx_iso_complete,1); + start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B, tx_iso_complete,1); + + handle_led(hfc,LED_POWER_ON); + + return(0); +} /* usb_init */ + + +/****************************************/ +/* data defining the devices to be used */ +/****************************************/ +// static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = { +static struct usb_device_id hfc_usb_idtab[] = { + {USB_DEVICE(0x7b0, 0x0007)}, /* Billion USB TA 2 */ + {USB_DEVICE(0x742, 0x2008)}, /* Stollmann USB TA */ + {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip USB eval TA */ + {USB_DEVICE(0x8e3, 0x0301)}, /* OliTec ISDN USB */ + {USB_DEVICE(0x675, 0x1688)}, /* DrayTec ISDN USB */ + {USB_DEVICE(0x7fa, 0x0846)}, /* Bewan ISDN USB TA */ + {} /* end with an all-zeroes entry */ +}; + +MODULE_AUTHOR("Peter Sprenger (sprenger@moving-byters.de)/Martin Bachem (info@colognechip.com)"); +MODULE_DESCRIPTION("HFC I4L USB driver"); +MODULE_DEVICE_TABLE(usb, hfc_usb_idtab); +MODULE_LICENSE("GPL"); + +#define EP_NUL 1 // Endpoint at this position not allowed +#define EP_NOP 2 // all type of endpoints allowed at this position +#define EP_ISO 3 // Isochron endpoint mandatory at this position +#define EP_BLK 4 // Bulk endpoint mandatory at this position +#define EP_INT 5 // Interrupt endpoint mandatory at this position + +// this array represents all endpoints possible in the HCF-USB +// the last 2 entries are the configuration number and the minimum interval for Interrupt endpoints +int validconf[][18]= +{ + // INT in, ISO out config + {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NOP,EP_INT,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_4INT3ISO,2}, + {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_3INT3ISO,2}, + // ISO in, ISO out config + {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NOP,EP_ISO,CNF_4ISO3ISO,2}, + {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NUL,EP_NUL,CNF_3ISO3ISO,2}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // EOL element +}; + +// string description of chosen config +char *conf_str[]= +{ + "4 Interrupt IN + 3 Isochron OUT", + "3 Interrupt IN + 3 Isochron OUT", + "4 Isochron IN + 3 Isochron OUT", + "3 Isochron IN + 3 Isochron OUT" +}; + + +/*************************************************/ +/* function called to probe a new plugged device */ +/*************************************************/ +static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev= interface_to_usbdev(intf); + hfcusb_data *context; + struct usb_host_interface *iface = intf->altsetting + intf->act_altsetting; + struct usb_host_endpoint *ep; + int i, idx, probe_alt_setting,vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr; + int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0; + +// usb_show_device(dev); +// usb_show_device_descriptor(&dev->descriptor); +// usb_show_interface_descriptor(&iface->desc); + vend_idx=0xffff; + for(i=0;vdata[i].vendor;i++) + { + if(dev->descriptor.idVendor==vdata[i].vendor && dev->descriptor.idProduct==vdata[i].prod_id) vend_idx=i; + } + + +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", + intf->altsetting->desc.bInterfaceNumber, intf->act_altsetting, intf->minor); +#endif + + if (vend_idx != 0xffff) { +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name); +#endif + /* if vendor and product ID is OK, start probing a matching alternate setting ... */ + probe_alt_setting = 0; + small_match=0xffff; + // default settings + iso_packet_size=16; + packet_size=64; + + while(probe_alt_setting < intf->num_altsetting) { + iface = intf->altsetting + probe_alt_setting; + cfg_used=0; + +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: test alt_setting %d\n", probe_alt_setting); +#endif + // check for config EOL element + while (validconf[cfg_used][0]) { + cfg_found=TRUE; + vcf=validconf[cfg_used]; + ep = iface->endpoint; /* first endpoint descriptor */ + +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n", + probe_alt_setting, intf->act_altsetting,cfg_used); +#endif + // copy table + memcpy(cmptbl,vcf,16*sizeof(int)); + + // check for all endpoints in this alternate setting + for (i=0; i < iface->desc.bNumEndpoints; i++) { + ep_addr = ep->desc.bEndpointAddress; + idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */ + if (ep_addr & 0x80) + idx++; + attr = ep->desc.bmAttributes; + + if (cmptbl[idx] == EP_NUL) { + printk(KERN_INFO "HFC-USB: cfg_found=FALSE in idx:%d attr:%d cmptbl[%d]:%d\n", + idx, attr, idx, cmptbl[idx]); + cfg_found = FALSE; + } + + if (attr == USB_ENDPOINT_XFER_INT && cmptbl[idx] == EP_INT) + cmptbl[idx] = EP_NUL; + if (attr == USB_ENDPOINT_XFER_BULK && cmptbl[idx] == EP_BLK) + cmptbl[idx] = EP_NUL; + if (attr == USB_ENDPOINT_XFER_ISOC && cmptbl[idx] == EP_ISO) + cmptbl[idx] = EP_NUL; + + // check if all INT endpoints match minimum interval + if (attr == USB_ENDPOINT_XFER_INT && ep->desc.bInterval < vcf[17]) { +#ifdef VERBOSE_USB_DEBUG + if (cfg_found) + printk(KERN_INFO "HFC-USB: Interrupt Endpoint interval < %d found - skipping config\n", + vcf[17]); +#endif + cfg_found = FALSE; + } + + ep++; + } + + for (i = 0; i < 16; i++) { + // printk(KERN_INFO "HFC-USB: cmptbl[%d]:%d\n", i, cmptbl[i]); + + // all entries must be EP_NOP or EP_NUL for a valid config + if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL) + cfg_found = FALSE; + } + + // we check for smallest match, to provide configuration priority + // configurations with smaller index have higher priority + if (cfg_found) { + if (cfg_used < small_match) { + small_match = cfg_used; + alt_used = probe_alt_setting; + } +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used); +#endif + } + + cfg_used++; + } + + probe_alt_setting++; + } /* (probe_alt_setting < intf->num_altsetting) */ +#ifdef VERBOSE_USB_DEBUG + printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used); +#endif + // yiipiee, we found a valid config + if (small_match != 0xffff) { + intf->act_altsetting = alt_used; + iface = intf->altsetting + intf->act_altsetting; + + if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) + return(-ENOMEM); /* got no mem */ + memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */ + + ep = iface->endpoint; /* first endpoint descriptor */ + vcf = validconf[small_match]; + + for (i = 0; i < iface->desc.bNumEndpoints; i++) { + ep_addr = ep->desc.bEndpointAddress; + idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */ + if (ep_addr & 0x80) + idx++; + cidx = idx & 7; + attr = ep->desc.bmAttributes; + + // only initialize used endpoints + if (vcf[idx] != EP_NOP && vcf[idx] != EP_NUL) { + switch (attr) { + case USB_ENDPOINT_XFER_INT: + context->fifos[cidx].pipe = usb_rcvintpipe(dev, ep->desc.bEndpointAddress); + context->fifos[cidx].usb_transfer_mode = USB_INT; + packet_size = ep->desc.wMaxPacketSize; // remember max packet size +#ifdef VERBOSE_USB_DEBUG + printk (KERN_INFO "HFC-USB: Interrupt-In Endpoint found %d ms(idx:%d cidx:%d)!\n", + ep->desc.bInterval, idx, cidx); +#endif + break; + case USB_ENDPOINT_XFER_BULK: + if (ep_addr & 0x80) + context->fifos[cidx].pipe = usb_rcvbulkpipe(dev, ep->desc.bEndpointAddress); + else + context->fifos[cidx].pipe = usb_sndbulkpipe(dev, ep->desc.bEndpointAddress); + context->fifos[cidx].usb_transfer_mode = USB_BULK; + packet_size = ep->desc.wMaxPacketSize; // remember max packet size +#ifdef VERBOSE_USB_DEBUG + printk (KERN_INFO "HFC-USB: Bulk Endpoint found (idx:%d cidx:%d)!\n", + idx, cidx); +#endif + break; + case USB_ENDPOINT_XFER_ISOC: + if (ep_addr & 0x80) + context->fifos[cidx].pipe = usb_rcvisocpipe(dev, ep->desc.bEndpointAddress); + else + context->fifos[cidx].pipe = usb_sndisocpipe(dev, ep->desc.bEndpointAddress); + context->fifos[cidx].usb_transfer_mode = USB_ISOC; + iso_packet_size = ep->desc.wMaxPacketSize; // remember max packet size +#ifdef VERBOSE_USB_DEBUG + printk (KERN_INFO "HFC-USB: ISO Endpoint found (idx:%d cidx:%d)!\n", + idx, cidx); +#endif + break; + default: + context->fifos[cidx].pipe = 0; /* reset data */ + } /* switch attribute */ + + if (context->fifos[cidx].pipe) { + context->fifos[cidx].fifonum = cidx; + context->fifos[cidx].hfc = context; + context->fifos[cidx].usb_packet_maxlen = ep->desc.wMaxPacketSize; + context->fifos[cidx].intervall = ep->desc.bInterval; + context->fifos[cidx].skbuff = NULL; +#ifdef VERBOSE_USB_DEBUG + printk (KERN_INFO "HFC-USB: fifo%d pktlen %d interval %d\n", + context->fifos[cidx].fifonum, + context->fifos[cidx].usb_packet_maxlen, + context->fifos[cidx].intervall); +#endif + } + } + + ep++; + } + + // now share our luck + context->dev = dev; /* save device */ + context->if_used = intf->altsetting->desc.bInterfaceNumber; /* save used interface */ + context->alt_used = intf->act_altsetting; /* and alternate config */ + context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ + context->cfg_used=vcf[16]; // store used config + context->vend_idx=vend_idx; // store found vendor + context->packet_size=packet_size; + context->iso_packet_size=iso_packet_size; + + /* create the control pipes needed for register access */ + context->ctrl_in_pipe = usb_rcvctrlpipe(context->dev, 0); + context->ctrl_out_pipe = usb_sndctrlpipe(context->dev, 0); + context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); + + printk(KERN_INFO "HFC-USB: detected \"%s\" configuration: %s (if=%d alt=%d)\n", + vdata[vend_idx].vend_name, conf_str[small_match], context->if_used, context->alt_used); + + /* init the chip and register the driver */ + if (usb_init(context)) + { + if (context->ctrl_urb) { + usb_unlink_urb(context->ctrl_urb); + usb_free_urb(context->ctrl_urb); + context->ctrl_urb = NULL; + } + kfree(context); + return(-EIO); + } + usb_set_intfdata(intf, context); + return(0); + } + } + return(-EIO); +} + +/****************************************************/ +/* function called when an active device is removed */ +/****************************************************/ +static void hfc_usb_disconnect(struct usb_interface *intf) +{ + hfcusb_data *context = usb_get_intfdata(intf); + int i; + + printk(KERN_INFO "HFC-USB: device disconnect\n"); + + usb_set_intfdata(intf, NULL); + if (!context) + return; + if (timer_pending(&context->t3_timer)) + del_timer(&context->t3_timer); + if (timer_pending(&context->t4_timer)) + del_timer(&context->t4_timer); + if (timer_pending(&context->led_timer)) + del_timer(&context->led_timer); + + hisax_unregister(&context->d_if); + + /* tell all fifos to terminate */ + for(i = 0; i < HFCUSB_NUM_FIFOS; i++) { + if(context->fifos[i].usb_transfer_mode == USB_ISOC) { + if(context->fifos[i].active > 0) { + stop_isoc_chain(&context->fifos[i]); +#ifdef VERBOSE_USB_DEBUG + printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i\n", i); +#endif + } + } else { + if(context->fifos[i].active > 0) { + context->fifos[i].active = 0; +#ifdef VERBOSE_USB_DEBUG + printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: unlinking URB for Fifo no %i\n", i); +#endif + } + if (context->fifos[i].urb) { + usb_unlink_urb(context->fifos[i].urb); + usb_free_urb(context->fifos[i].urb); + context->fifos[i].urb = NULL; + } + } + context->fifos[i].active = 0; + } + if (context->ctrl_urb) { + usb_unlink_urb(context->ctrl_urb); + usb_free_urb(context->ctrl_urb); + context->ctrl_urb = NULL; + } + kfree(context); /* free our structure again */ +} /* hfc_usb_disconnect */ + + +/************************************/ +/* our driver information structure */ +/************************************/ +static struct usb_driver hfc_drv = { + .owner = THIS_MODULE, + .name = "hfc_usb", + .id_table = hfc_usb_idtab, + .probe = hfc_usb_probe, + .disconnect = hfc_usb_disconnect, +}; + +static void __exit hfc_usb_exit(void) +{ +#ifdef VERBOSE_USB_DEBUG + printk ("HFC-USB: calling \"hfc_usb_exit\" ...\n"); +#endif + usb_deregister(&hfc_drv); /* release our driver */ + printk(KERN_INFO "HFC-USB module removed\n"); +} + +static int __init hfc_usb_init(void) +{ + printk ("HFC-USB: driver module revision %s loaded\n", hfcusb_revision); + + if(usb_register(&hfc_drv)) + { + printk(KERN_INFO "HFC-USB: Unable to register HFC-USB module at usb stack\n"); + return(-1); /* unable to register */ + } + return(0); +} + +module_init(hfc_usb_init); +module_exit(hfc_usb_exit); diff -puN /dev/null drivers/isdn/hisax/hisax_cfg.h --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/isdn/hisax/hisax_cfg.h 2004-02-09 22:19:20.000000000 -0800 @@ -0,0 +1,64 @@ +/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $ + * define of the basic HiSax configuration structures + * and pcmcia interface + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#define ISDN_CTYPE_16_0 1 +#define ISDN_CTYPE_8_0 2 +#define ISDN_CTYPE_16_3 3 +#define ISDN_CTYPE_PNP 4 +#define ISDN_CTYPE_A1 5 +#define ISDN_CTYPE_ELSA 6 +#define ISDN_CTYPE_ELSA_PNP 7 +#define ISDN_CTYPE_TELESPCMCIA 8 +#define ISDN_CTYPE_IX1MICROR2 9 +#define ISDN_CTYPE_ELSA_PCMCIA 10 +#define ISDN_CTYPE_DIEHLDIVA 11 +#define ISDN_CTYPE_ASUSCOM 12 +#define ISDN_CTYPE_TELEINT 13 +#define ISDN_CTYPE_TELES3C 14 +#define ISDN_CTYPE_SEDLBAUER 15 +#define ISDN_CTYPE_SPORTSTER 16 +#define ISDN_CTYPE_MIC 17 +#define ISDN_CTYPE_ELSA_PCI 18 +#define ISDN_CTYPE_COMPAQ_ISA 19 +#define ISDN_CTYPE_NETJET_S 20 +#define ISDN_CTYPE_TELESPCI 21 +#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 +#define ISDN_CTYPE_AMD7930 23 +#define ISDN_CTYPE_NICCY 24 +#define ISDN_CTYPE_S0BOX 25 +#define ISDN_CTYPE_A1_PCMCIA 26 +#define ISDN_CTYPE_FRITZPCI 27 +#define ISDN_CTYPE_SEDLBAUER_FAX 28 +#define ISDN_CTYPE_ISURF 29 +#define ISDN_CTYPE_ACERP10 30 +#define ISDN_CTYPE_HSTSAPHIR 31 +#define ISDN_CTYPE_BKM_A4T 32 +#define ISDN_CTYPE_SCT_QUADRO 33 +#define ISDN_CTYPE_GAZEL 34 +#define ISDN_CTYPE_HFC_PCI 35 +#define ISDN_CTYPE_W6692 36 +#define ISDN_CTYPE_HFC_SX 37 +#define ISDN_CTYPE_NETJET_U 38 +#define ISDN_CTYPE_HFC_SP_PCMCIA 39 +#define ISDN_CTYPE_DYNAMIC 40 +#define ISDN_CTYPE_ENTERNOW 41 +#define ISDN_CTYPE_COUNT 41 + +typedef struct IsdnCardState IsdnCardState_t; +typedef struct IsdnCard IsdnCard_t; + +struct IsdnCard { + int typ; + int protocol; /* EDSS1, 1TR6 or NI1 */ + unsigned long para[4]; + IsdnCardState_t *cs; +}; + +extern void HiSax_closecard(int); +extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *); diff -puN drivers/isdn/hisax/hisax_debug.h~i4l drivers/isdn/hisax/hisax_debug.h --- 25/drivers/isdn/hisax/hisax_debug.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hisax_debug.h 2004-02-09 22:19:20.000000000 -0800 @@ -39,7 +39,7 @@ printk(KERN_DEBUG "%s: " format "\n" , _ static void __attribute__((unused)) -dump_packet(const char *name,const u8 *data,int pkt_len) +dump_packet(const char *name,const u_char *data,int pkt_len) { #define DUMP_HDR_SIZE 20 #define DUMP_TLR_SIZE 8 diff -puN -L drivers/isdn/hisax/hisax_fcclassic.c drivers/isdn/hisax/hisax_fcclassic.c~i4l /dev/null --- 25/drivers/isdn/hisax/hisax_fcclassic.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,385 +0,0 @@ -/* - * Driver for AVM Fritz!classic (ISA) ISDN card - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski - * 2001 by Karsten Keil - * - * based upon Karsten Keil's original avm_a1.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hisax_fcclassic.h" - -// debugging cruft -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); -MODULE_DESCRIPTION("AVM Fritz!Card classic ISDN driver"); - -static int protocol = 2; /* EURO-ISDN Default */ -MODULE_PARM(protocol, "i"); - -// ---------------------------------------------------------------------- - -#define AVM_A1_STAT_ISAC 0x01 -#define AVM_A1_STAT_HSCX 0x02 -#define AVM_A1_STAT_TIMER 0x04 - -// ---------------------------------------------------------------------- - -static unsigned char -fcclassic_read_isac(struct isac *isac, unsigned char offset) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char val; - - val = inb(adapter->isac_base + offset); - DBG(0x1000, " port %#x, value %#x", - offset, val); - return val; -} - -static void -fcclassic_write_isac(struct isac *isac, unsigned char offset, - unsigned char value) -{ - struct fritz_adapter *adapter = isac->priv; - - DBG(0x1000, " port %#x, value %#x", - offset, value); - outb(value, adapter->isac_base + offset); -} - -static void -fcclassic_read_isac_fifo(struct isac *isac, unsigned char * data, int size) -{ - struct fritz_adapter *adapter = isac->priv; - - insb(adapter->isac_fifo, data, size); -} - -static void -fcclassic_write_isac_fifo(struct isac *isac, unsigned char * data, int size) -{ - struct fritz_adapter *adapter = isac->priv; - - outsb(adapter->isac_fifo, data, size); -} - -static u8 -fcclassic_read_hscx(struct hscx *hscx, u8 offset) -{ - struct fritz_adapter *adapter = hscx->priv; - - return inb(adapter->hscx_base[hscx->channel] + offset); -} - -static void -fcclassic_write_hscx(struct hscx *hscx, u8 offset, u8 value) -{ - struct fritz_adapter *adapter = hscx->priv; - - outb(value, adapter->hscx_base[hscx->channel] + offset); -} - -static void -fcclassic_read_hscx_fifo(struct hscx *hscx, unsigned char * data, int size) -{ - struct fritz_adapter *adapter = hscx->priv; - - insb(adapter->hscx_fifo[hscx->channel], data, size); -} - -static void -fcclassic_write_hscx_fifo(struct hscx *hscx, unsigned char * data, int size) -{ - struct fritz_adapter *adapter = hscx->priv; - - outsb(adapter->hscx_fifo[hscx->channel], data, size); -} - -// ---------------------------------------------------------------------- - -static irqreturn_t -fcclassic_irq(int intno, void *dev, struct pt_regs *regs) -{ - struct fritz_adapter *adapter = dev; - unsigned char sval; - - DBG(2, ""); - while ((sval = inb(adapter->cfg_reg) & 0xf) != 0x7) { - DBG(2, "sval %#x", sval); - if (!(sval & AVM_A1_STAT_TIMER)) { - outb(0x1e, adapter->cfg_reg); - } - if (!(sval & AVM_A1_STAT_HSCX)) { - hscx_irq(adapter->hscx); - } - if (!(sval & AVM_A1_STAT_ISAC)) { - isac_irq(&adapter->isac); - } - } - return IRQ_HANDLED; -} - -// ---------------------------------------------------------------------- - -static int __init -fcclassic_setup(struct fritz_adapter *adapter) -{ - u32 val = 0; - int i; - int retval; - - DBG(1,""); - - isac_init(&adapter->isac); // FIXME is this okay now - - adapter->cfg_reg = adapter->io + 0x1800; - adapter->isac_base = adapter->io + 0x1400 - 0x20; - adapter->isac_fifo = adapter->io + 0x1000; - adapter->hscx_base[0] = adapter->io + 0x0400 - 0x20; - adapter->hscx_fifo[0] = adapter->io; - adapter->hscx_base[1] = adapter->io + 0x0c00 - 0x20; - adapter->hscx_fifo[1] = adapter->io + 0x0800; - - retval = -EBUSY; - if (!request_region(adapter->cfg_reg , 8, - "fcclassic cfg")) - goto err; - if (!request_region(adapter->isac_base + 0x20 , 32, - "fcclassic isac")) - goto err_cfg_reg; - if (!request_region(adapter->isac_fifo , 1, - "fcclassic isac fifo")) - goto err_isac_base; - if (!request_region(adapter->hscx_base[0] + 0x20, 32, - "fcclassic hscx")) - goto err_isac_fifo; - if (!request_region(adapter->hscx_fifo[0] , 1, - "fcclassic hscx fifo")) - goto err_hscx_base_0; - if (!request_region(adapter->hscx_base[1] + 0x20, 32, - "fcclassic hscx")) - goto err_hscx_fifo_0; - if (!request_region(adapter->hscx_fifo[1] , 1, - "fcclassic hscx fifo")) - goto err_hscx_base_1; - retval = request_irq(adapter->irq, fcclassic_irq, 0, - "fcclassic", adapter); - if (retval) - goto err_hscx_fifo_1; - - // Reset - outb(0x00, adapter->cfg_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(200 * HZ / 1000); // 200 msec - outb(0x01, adapter->cfg_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(200 * HZ / 1000); // 200 msec - outb(0x00, adapter->cfg_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(200 * HZ / 1000); // 200 msec - - val = adapter->irq; - if (val == 9) - val = 2; - outb(val, adapter->cfg_reg + 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(200 * HZ / 1000); // 200 msec - outb(0x00, adapter->cfg_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(200 * HZ / 1000); // 200 msec - - val = inb(adapter->cfg_reg); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - adapter->cfg_reg, val); - val = inb(adapter->cfg_reg + 3); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - adapter->cfg_reg + 3, val); - val = inb(adapter->cfg_reg + 2); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - adapter->cfg_reg + 2, val); - val = inb(adapter->cfg_reg); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - adapter->cfg_reg, val); - - outb(0x16, adapter->cfg_reg); - outb(0x1e, adapter->cfg_reg); - - adapter->isac.priv = adapter; - adapter->isac.read_isac = &fcclassic_read_isac; - adapter->isac.write_isac = &fcclassic_write_isac; - adapter->isac.read_isac_fifo = &fcclassic_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcclassic_write_isac_fifo; - hisax_isac_setup(&adapter->isac); - for (i = 0; i < 2; i++) { - hscx_init(&adapter->hscx[i]); - adapter->hscx[i].priv = adapter; - adapter->hscx[i].read_hscx = &fcclassic_read_hscx; - adapter->hscx[i].write_hscx = &fcclassic_write_hscx; - adapter->hscx[i].read_hscx_fifo = &fcclassic_read_hscx_fifo; - adapter->hscx[i].write_hscx_fifo = &fcclassic_write_hscx_fifo; - hscx_setup(&adapter->hscx[i]); - } - - return 0; - - err_hscx_fifo_1: - release_region(adapter->hscx_fifo[1] , 1); - err_hscx_base_1: - release_region(adapter->hscx_base[1] + 0x20, 32); - err_hscx_fifo_0: - release_region(adapter->hscx_fifo[0] , 1); - err_hscx_base_0: - release_region(adapter->hscx_base[0] + 0x20, 32); - err_isac_fifo: - release_region(adapter->isac_fifo , 1); - err_isac_base: - release_region(adapter->isac_base + 0x20, 32); - err_cfg_reg: - release_region(adapter->cfg_reg , 8); - err: - return retval; -} - -static void __exit fcclassic_release(struct fritz_adapter *adapter) -{ - DBG(1,""); - -// outb(0, adapter->io + AVM_STATUS0); - free_irq(adapter->irq, adapter); - release_region(adapter->hscx_fifo[1] , 1); - release_region(adapter->hscx_base[1] + 0x20, 32); - release_region(adapter->hscx_fifo[0] , 1); - release_region(adapter->hscx_base[0] + 0x20, 32); - release_region(adapter->isac_fifo , 1); - release_region(adapter->isac_base + 0x20, 32); - release_region(adapter->cfg_reg , 8); -} - -// ---------------------------------------------------------------------- - -static struct fritz_adapter * __init -new_adapter(struct pci_dev *pdev) -{ - struct fritz_adapter *adapter; - struct hisax_b_if *b_if[2]; - int i; - - adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL); - if (!adapter) - return NULL; - - memset(adapter, 0, sizeof(struct fritz_adapter)); - - adapter->isac.hisax_d_if.owner = THIS_MODULE; - adapter->isac.hisax_d_if.ifc.priv = &adapter->isac; - adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1; - - for (i = 0; i < 2; i++) { - // adapter->hscx[i].adapter = adapter; - adapter->hscx[i].channel = i; - adapter->hscx[i].b_if.ifc.priv = &adapter->hscx[i]; - adapter->hscx[i].b_if.ifc.l2l1 = hscx_b_l2l1; - } - pci_set_drvdata(pdev, adapter); - - for (i = 0; i < 2; i++) - b_if[i] = &adapter->hscx[i].b_if; - - hisax_register(&adapter->isac.hisax_d_if, b_if, "fcclassic", protocol); - - return adapter; -} - -static void -delete_adapter(struct fritz_adapter *adapter) -{ - hisax_unregister(&adapter->isac.hisax_d_if); - kfree(adapter); -} - -static int __init -fcclassic_probe(struct pci_dev *pdev, const struct isapnp_device_id *ent) -{ - struct fritz_adapter *adapter; - int retval; - - retval = -ENOMEM; - adapter = new_adapter(pdev); - if (!adapter) - goto err; - - adapter->io = pdev->resource[0].start; - adapter->irq = pdev->irq_resource[0].start; - - printk(KERN_INFO "hisax_fcclassic: found Fritz!Card classic at IO %#x irq %d\n", - adapter->io, adapter->irq); - - retval = fcclassic_setup(adapter); - if (retval) - goto err_free; - - return 0; - - err_free: - delete_adapter(adapter); - err: - return retval; -} - -static int __exit -fcclassic_remove(struct pci_dev *pdev) -{ - struct fritz_adapter *adapter = pci_get_drvdata(pdev); - - fcclassic_release(adapter); - delete_adapter(adapter); - - return 0; -} - -static struct pci_dev isa_dev[4]; - -static int __init -hisax_fcclassic_init(void) -{ - printk(KERN_INFO "hisax_fcclassic: Fritz!Card classic ISDN driver v0.0.1\n"); - - isa_dev[0].resource[0].start = 0x300; - isa_dev[0].irq_resource[0].start = 7; - - fcclassic_probe(isa_dev, NULL); - - return 0; -} - -static void __exit -hisax_fcclassic_exit(void) -{ - fcclassic_remove(isa_dev); -} - -module_init(hisax_fcclassic_init); -module_exit(hisax_fcclassic_exit); diff -puN -L drivers/isdn/hisax/hisax_fcclassic.h drivers/isdn/hisax/hisax_fcclassic.h~i4l /dev/null --- 25/drivers/isdn/hisax/hisax_fcclassic.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,18 +0,0 @@ -#include "hisax_if.h" -#include "hisax_isac.h" -#include "hisax_hscx.h" - -#include - -struct fritz_adapter { - unsigned int io; - unsigned int irq; - unsigned int cfg_reg; - unsigned int isac_base; - unsigned int isac_fifo; - unsigned int hscx_base[2]; - unsigned int hscx_fifo[2]; - struct isac isac; - - struct hscx hscx[2]; -}; diff -puN drivers/isdn/hisax/hisax_fcpcipnp.c~i4l drivers/isdn/hisax/hisax_fcpcipnp.c --- 25/drivers/isdn/hisax/hisax_fcpcipnp.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hisax_fcpcipnp.c 2004-02-09 22:19:20.000000000 -0800 @@ -27,22 +27,26 @@ #include #include #include -#include +#include #include #include #include #include +#include + +#include + #include "hisax_fcpcipnp.h" // debugging cruft #define __debug_variable debug #include "hisax_debug.h" -// #define CONFIG_PNP_CARD 1 - #ifdef CONFIG_HISAX_DEBUG static int debug = 0; +/* static int hdlcfifosize = 32; */ MODULE_PARM(debug, "i"); +/* MODULE_PARM(hdlcfifosize, "i"); */ #endif MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); @@ -65,6 +69,17 @@ static struct pci_device_id fcpci_ids[] MODULE_DEVICE_TABLE(pci, fcpci_ids); +#ifdef __ISAPNP__ +static struct pnp_device_id fcpnp_ids[] __devinitdata = { + { + .id = "AVM0900", + .driver_data = (unsigned long) "Fritz!Card PnP", + }, +}; + +MODULE_DEVICE_TABLE(isapnp, fcpnp_ids); +#endif + static int protocol = 2; /* EURO-ISDN Default */ MODULE_PARM(protocol, "i"); MODULE_LICENSE("GPL"); @@ -115,12 +130,12 @@ MODULE_LICENSE("GPL"); #define HDLC_STAT_RDO 0x10 #define HDLC_STAT_CRCVFRRAB 0x0E #define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK 0x3f00 +#define HDLC_STAT_RML_MASK 0xff00 #define HDLC_CMD_XRS 0x80 #define HDLC_CMD_XME 0x01 #define HDLC_CMD_RRS 0x20 -#define HDLC_CMD_XML_MASK 0x3f00 +#define HDLC_CMD_XML_MASK 0xff00 #define AVM_HDLC_FIFO_1 0x10 #define AVM_HDLC_FIFO_2 0x18 @@ -367,8 +382,7 @@ static void hdlc_fill_fifo(struct fritz_ { struct fritz_adapter *adapter = bcs->adapter; struct sk_buff *skb = bcs->tx_skb; - u_int count; - u_int fifo_size = 32; + int count; unsigned long flags; unsigned char *p; @@ -378,8 +392,8 @@ static void hdlc_fill_fifo(struct fritz_ BUG(); bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (bcs->tx_skb->len > fifo_size) { - count = fifo_size; + if (bcs->tx_skb->len > bcs->fifo_size) { + count = bcs->fifo_size; } else { count = bcs->tx_skb->len; if (bcs->mode != L1_MODE_TRANS) @@ -389,7 +403,7 @@ static void hdlc_fill_fifo(struct fritz_ p = bcs->tx_skb->data; skb_pull(bcs->tx_skb, count); bcs->tx_cnt += count; - bcs->ctrl.sr.xml = ((count == fifo_size) ? 0 : count); + bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count); switch (adapter->type) { case AVM_FRITZ_PCI: @@ -470,7 +484,7 @@ static inline void hdlc_rpr_irq(struct f len = (stat & HDLC_STAT_RML_MASK) >> 8; if (len == 0) - len = 32; + len = bcs->fifo_size; hdlc_empty_fifo(bcs, len); @@ -498,6 +512,7 @@ static inline void hdlc_rpr_irq(struct f static inline void hdlc_xdu_irq(struct fritz_bcs *bcs) { struct fritz_adapter *adapter = bcs->adapter; + /* Here we lost an TX interrupt, so * restart transmitting the whole frame. @@ -506,14 +521,17 @@ static inline void hdlc_xdu_irq(struct f bcs->ctrl.sr.cmd |= HDLC_CMD_XRS; adapter->write_ctrl(bcs, 1); bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS; - adapter->write_ctrl(bcs, 1); if (!bcs->tx_skb) { DBG(0x10, "XDU without skb"); + adapter->write_ctrl(bcs, 1); return; } - skb_push(bcs->tx_skb, bcs->tx_cnt); - bcs->tx_cnt = 0; + /* only hdlc restarts the frame, transparent mode must continue */ + if (bcs->mode == L1_MODE_HDLC) { + skb_push(bcs->tx_skb, bcs->tx_cnt); + bcs->tx_cnt = 0; + } } static inline void hdlc_xpr_irq(struct fritz_bcs *bcs) @@ -530,7 +548,8 @@ static inline void hdlc_xpr_irq(struct f } bcs->tx_cnt = 0; bcs->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, skb); + B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); + dev_kfree_skb_irq(skb); } static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat) @@ -543,6 +562,8 @@ static void hdlc_irq_one(struct fritz_bc if (stat & HDLC_INT_XDU) { DBG(0x10, "XDU"); hdlc_xdu_irq(bcs); + hdlc_xpr_irq(bcs); + return; } if (stat & HDLC_INT_XPR) { DBG(0x10, "XPR"); @@ -573,6 +594,7 @@ static void modehdlc(struct fritz_bcs *b if (bcs->mode == mode) return; + bcs->fifo_size = 32; bcs->ctrl.ctrl = 0; bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; switch (mode) { @@ -585,10 +607,11 @@ static void modehdlc(struct fritz_bcs *b bcs->rcvidx = 0; bcs->tx_cnt = 0; bcs->tx_skb = NULL; - if (mode == L1_MODE_TRANS) + if (mode == L1_MODE_TRANS) { bcs->ctrl.sr.mode = HDLC_MODE_TRANS; - else + } else { bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG; + } adapter->write_ctrl(bcs, 5); bcs->ctrl.sr.cmd = HDLC_CMD_XRS; adapter->write_ctrl(bcs, 1); @@ -631,7 +654,8 @@ static void fritz_b_l2l1(struct hisax_if // ---------------------------------------------------------------------- -static irqreturn_t fcpci2_irq(int intno, void *dev, struct pt_regs *regs) +static irqreturn_t +fcpci2_irq(int intno, void *dev, struct pt_regs *regs) { struct fritz_adapter *adapter = dev; unsigned char val; @@ -643,13 +667,15 @@ static irqreturn_t fcpci2_irq(int intno, DBG(2, "STATUS0 %#x", val); if (val & AVM_STATUS0_IRQ_ISAC) isacsx_irq(&adapter->isac); - if (val & AVM_STATUS0_IRQ_HDLC) hdlc_irq(adapter); + if (val & AVM_STATUS0_IRQ_ISAC) + isacsx_irq(&adapter->isac); return IRQ_HANDLED; } -static irqreturn_t fcpci_irq(int intno, void *dev, struct pt_regs *regs) +static irqreturn_t +fcpci_irq(int intno, void *dev, struct pt_regs *regs) { struct fritz_adapter *adapter = dev; unsigned char sval; @@ -683,8 +709,7 @@ static inline void fcpci_init(struct fri outb(AVM_STATUS1_ENA_IOM | adapter->irq, adapter->io + AVM_STATUS1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(50*HZ / 1000); /* Timeout 50ms */ + mdelay(10); } // ---------------------------------------------------------------------- @@ -767,14 +792,11 @@ static int __devinit fcpcipnp_setup(stru // Reset outb(0, adapter->io + AVM_STATUS0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(50 * HZ / 1000); // 50 msec + mdelay(10); outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(50 * HZ / 1000); // 50 msec + mdelay(10); outb(0, adapter->io + AVM_STATUS0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10 * HZ / 1000); // 10 msec + mdelay(10); switch (adapter->type) { case AVM_FRITZ_PCIV2: @@ -784,7 +806,7 @@ static int __devinit fcpcipnp_setup(stru case AVM_FRITZ_PCI: case AVM_FRITZ_PNP: fcpci_init(adapter); - hisax_isac_setup(&adapter->isac); + isac_setup(&adapter->isac); break; } val = adapter->read_hdlc_status(adapter, 0); @@ -817,7 +839,7 @@ static void __devexit fcpcipnp_release(s // ---------------------------------------------------------------------- static struct fritz_adapter * __devinit -new_adapter(struct pci_dev *pdev) +new_adapter(void) { struct fritz_adapter *adapter; struct hisax_b_if *b_if[2]; @@ -840,8 +862,6 @@ new_adapter(struct pci_dev *pdev) adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1; } - pci_set_drvdata(pdev, adapter); - for (i = 0; i < 2; i++) b_if[i] = &adapter->bcs[i].b_if; @@ -863,10 +883,12 @@ static int __devinit fcpci_probe(struct int retval; retval = -ENOMEM; - adapter = new_adapter(pdev); + adapter = new_adapter(); if (!adapter) goto err; + pci_set_drvdata(pdev, adapter); + if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) adapter->type = AVM_FRITZ_PCIV2; else @@ -880,7 +902,7 @@ static int __devinit fcpci_probe(struct adapter->irq = pdev->irq; printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n", - (char *) ent->driver_data, pci_name(pdev)); + (char *) ent->driver_data, pdev->slot_name); retval = fcpcipnp_setup(adapter); if (retval) @@ -894,91 +916,87 @@ static int __devinit fcpci_probe(struct return retval; } -static void __devexit fcpci_remove(struct pci_dev *pdev) -{ - struct fritz_adapter *adapter = pci_get_drvdata(pdev); - - fcpcipnp_release(adapter); - pci_disable_device(pdev); - delete_adapter(adapter); -} - -static struct pci_driver fcpci_driver = { - .name = "fcpci", - .probe = fcpci_probe, - .remove = __devexit_p(fcpci_remove), - .id_table = fcpci_ids, -}; - -#ifdef CONFIG_PNP_CARD - -static int __devinit fcpnp_probe(struct pnp_card *card, - const struct pnp_card_device_id *card_id) +#ifdef __ISAPNP__ +static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) { struct fritz_adapter *adapter; - struct pnp_dev *pnp_dev; int retval; - retval = -ENODEV; - pnp_dev = pnp_request_card_device(card, card_id->devs[0].id, NULL); - if (!pnp_dev) - goto err; - - if (!pnp_port_valid(pnp_dev, 0) || !pnp_irq_valid(pnp_dev, 0)) - goto err; + if (!pdev) + return(-ENODEV); retval = -ENOMEM; - adapter = new_adapter((struct pci_dev *)pnp_dev); // FIXME + adapter = new_adapter(); if (!adapter) goto err; - + + pnp_set_drvdata(pdev, adapter); + adapter->type = AVM_FRITZ_PNP; - adapter->io = pnp_port_start(pnp_dev, 0); - adapter->irq = pnp_irq(pnp_dev, 0); - + + pnp_disable_dev(pdev); + retval = pnp_activate_dev(pdev); + if (retval < 0) { + printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__, + (char *)dev_id->driver_data, retval); + goto err_free; + } + adapter->io = pnp_port_start(pdev, 0); + adapter->irq = pnp_irq(pdev, 0); + printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n", - (char *) card_id->driver_data, adapter->io, adapter->irq); - + (char *) dev_id->driver_data, adapter->io, adapter->irq); + retval = fcpcipnp_setup(adapter); if (retval) - goto err_delete; - + goto err_free; + return 0; - err_delete: + err_free: delete_adapter(adapter); err: return retval; } -static void __devexit fcpnp_remove(struct pnp_card *pcard) +static void __devexit fcpnp_remove(struct pnp_dev *pdev) { - struct fritz_adapter *adapter = pnpc_get_drvdata(pcard); + struct fritz_adapter *adapter = pnp_get_drvdata(pdev); - fcpcipnp_release(adapter); - delete_adapter(adapter); + if (adapter) { + fcpcipnp_release(adapter); + delete_adapter(adapter); + } + pnp_disable_dev(pdev); } -static struct pnp_card_device_id fcpnp_ids[] __devinitdata = { - { .id = "AVM0900", - .driver_data = (unsigned long) "Fritz!Card PnP", - .devs = { { "AVM0900" } }, - }, - {} +static struct pnp_driver fcpnp_driver = { + name: "fcpnp", + probe: fcpnp_probe, + remove: __devexit_p(fcpnp_remove), + id_table: fcpnp_ids, }; +#endif -static struct pnpc_driver fcpnp_driver = { - .name = "fcpnp", - .probe = fcpnp_probe, - .remove = __devexit_p(fcpnp_remove), - .id_table = fcpnp_ids, -}; +static void __devexit fcpci_remove(struct pci_dev *pdev) +{ + struct fritz_adapter *adapter = pci_get_drvdata(pdev); -#endif + fcpcipnp_release(adapter); + pci_disable_device(pdev); + delete_adapter(adapter); +} + +static struct pci_driver fcpci_driver = { + name: "fcpci", + probe: fcpci_probe, + remove: __devexit_p(fcpci_remove), + id_table: fcpci_ids, +}; static int __init hisax_fcpcipnp_init(void) { - int retval = 0, pci_nr_found; + int retval, pci_nr_found; printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n"); @@ -986,25 +1004,26 @@ static int __init hisax_fcpcipnp_init(vo if (retval < 0) goto out; pci_nr_found = retval; + retval = 0; -#ifdef CONFIG_PNP_CARD - retval = pnpc_register_driver(&fcpnp_driver); -#endif +#ifdef __ISAPNP__ + retval = pnp_register_driver(&fcpnp_driver); if (retval < 0) goto out_unregister_pci; +#endif #if !defined(CONFIG_HOTPLUG) || defined(MODULE) if (pci_nr_found + retval == 0) { retval = -ENODEV; - goto out_unregister_pnp; + goto out_unregister_isapnp; } #endif return 0; #if !defined(CONFIG_HOTPLUG) || defined(MODULE) - out_unregister_pnp: -#ifdef CONFIG_PNP_CARD - pnpc_unregister_driver(&fcpnp_driver); + out_unregister_isapnp: +#ifdef __ISAPNP__ + pnp_unregister_driver(&fcpnp_driver); #endif #endif out_unregister_pci: @@ -1015,8 +1034,8 @@ static int __init hisax_fcpcipnp_init(vo static void __exit hisax_fcpcipnp_exit(void) { -#ifdef CONFIG_PNP_CARD - pnpc_unregister_driver(&fcpnp_driver); +#ifdef __ISAPNP__ + pnp_unregister_driver(&fcpnp_driver); #endif pci_unregister_driver(&fcpci_driver); } diff -puN drivers/isdn/hisax/hisax_fcpcipnp.h~i4l drivers/isdn/hisax/hisax_fcpcipnp.h --- 25/drivers/isdn/hisax/hisax_fcpcipnp.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hisax_fcpcipnp.h 2004-02-09 22:19:20.000000000 -0800 @@ -12,15 +12,15 @@ enum { struct hdlc_stat_reg { #ifdef __BIG_ENDIAN - u8 fill __attribute__((packed)); - u8 mode __attribute__((packed)); - u8 xml __attribute__((packed)); - u8 cmd __attribute__((packed)); + u_char fill __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char cmd __attribute__((packed)); #else - u8 cmd __attribute__((packed)); - u8 xml __attribute__((packed)); - u8 mode __attribute__((packed)); - u8 fill __attribute__((packed)); + u_char cmd __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char fill __attribute__((packed)); #endif }; @@ -36,8 +36,9 @@ struct fritz_bcs { } ctrl; u_int stat; int rcvidx; - u8 rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */ - + int fifo_size; + u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */ + int tx_cnt; /* B-Channel transmit counter */ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; diff -puN drivers/isdn/hisax/hisax.h~i4l drivers/isdn/hisax/hisax.h --- 25/drivers/isdn/hisax/hisax.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hisax.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hisax.h,v 1.1.4.1.2.1 2001/12/09 20:18:40 kai Exp $ +/* $Id: hisax.h,v 2.64.2.3 2004/01/24 20:47:23 keil Exp $ * * Basic declarations, defines and prototypes * @@ -6,14 +6,11 @@ * of the GNU General Public License, incorporated herein by reference. * */ - -#ifndef __HISAX_H__ -#define __HISAX_H__ - #include #include #include #include +#include #include #include #include @@ -28,7 +25,6 @@ #include #include #include -#include #define ERROR_STATISTIC @@ -51,6 +47,11 @@ #define HW_INFO4_P10 0x0048 #define HW_RSYNC 0x0060 #define HW_TESTLOOP 0x0070 +#define CARD_RESET 0x00F0 +#define CARD_INIT 0x00F2 +#define CARD_RELEASE 0x00F3 +#define CARD_TEST 0x00F4 +#define CARD_AUX_IND 0x00F5 #define PH_ACTIVATE 0x0100 #define PH_DEACTIVATE 0x0110 @@ -68,9 +69,14 @@ #define DL_FLUSH 0x0224 #define DL_UNIT_DATA 0x0230 +#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now +#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now #define MDL_ASSIGN 0x0280 #define MDL_REMOVE 0x0284 #define MDL_ERROR 0x0288 +#define MDL_INFO_SETUP 0x02E0 +#define MDL_INFO_CONN 0x02E4 +#define MDL_INFO_REL 0x02E8 #define CC_SETUP 0x0300 #define CC_RESUME 0x0304 @@ -145,35 +151,6 @@ /* #define I4L_IRQ_FLAG SA_INTERRUPT */ #define I4L_IRQ_FLAG 0 -struct res { - struct list_head node; - const char *name; - unsigned long start, end; - unsigned long flags; - union { - void *ioremap_addr; - } r_u; -}; - -struct resources { - struct list_head res_head; -}; - -void -resources_init(struct resources *rs); - -void -resources_release(struct resources *rs); - -unsigned long -request_io(struct resources *rs, unsigned long start, int len, - const char *name); - -void * -request_mmio(struct resources *rs, unsigned long start, int len, - const char *name); - - /* * Statemachine */ @@ -230,9 +207,9 @@ struct Layer1 { long Flags; struct FsmInst l1m; struct FsmTimer timer; + void (*l1l2) (struct PStack *, int, void *); void (*l1hw) (struct PStack *, int, void *); void (*l1tei) (struct PStack *, int, void *); - void (*l2l1) (struct PStack *, int, void *); int mode, bc; int delay; }; @@ -265,17 +242,18 @@ struct Layer1 { struct Layer2 { int tei; int sap; - u_int maxlen; - unsigned long flag; - unsigned int vs, va, vr; + int maxlen; + u_long flag; + spinlock_t lock; + u_int vs, va, vr; int rc; unsigned int window; unsigned int sow; struct sk_buff *windowar[MAX_WINDOW]; struct sk_buff_head i_queue; struct sk_buff_head ui_queue; - void (*l3l2) (struct PStack *, int, void *); - void (*l1l2) (struct PStack *, int, void *); + void (*l2l1) (struct PStack *, int, void *); + void (*l2l3) (struct PStack *, int, void *); void (*l2tei) (struct PStack *, int, void *); struct FsmInst l2m; struct FsmTimer t200, t203; @@ -285,10 +263,9 @@ struct Layer2 { }; struct Layer3 { - void (*l4l3) (struct PStack *, int, void *); - int (*l4l3_proto) (struct PStack *, isdn_ctrl *); + void (*l3l4) (struct PStack *, int, void *); void (*l3ml3) (struct PStack *, int, void *); - void (*l2l3) (struct PStack *, int, void *); + void (*l3l2) (struct PStack *, int, void *); struct FsmInst l3m; struct FsmTimer l3m_timer; struct sk_buff_head squeue; @@ -300,8 +277,11 @@ struct Layer3 { }; struct LLInterface { - void (*l3l4) (struct PStack *, int, void *); + void (*l4l3) (struct PStack *, int, void *); + int (*l4l3_proto) (struct PStack *, isdn_ctrl *); void *userdata; + void (*l1writewakeup) (struct PStack *, int); + void (*l2writewakeup) (struct PStack *, int); }; @@ -316,14 +296,14 @@ struct Management { #define NO_CAUSE 254 struct Param { - u8 cause; - u8 loc; - u8 diag[6]; + u_char cause; + u_char loc; + u_char diag[6]; int bchannel; int chargeinfo; int spv; /* SPV Flag */ setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - u8 moderate; /* transfer mode and rate (bearer octet 4) */ + u_char moderate; /* transfer mode and rate (bearer octet 4) */ }; @@ -338,7 +318,7 @@ struct PStack { /* protocol specific data fields */ union - { u8 uuuu; /* only as dummy */ + { u_char uuuu; /* only as dummy */ #ifdef CONFIG_HISAX_EURO dss1_stk_priv dss1; /* private dss1 data */ #endif /* CONFIG_HISAX_EURO */ @@ -362,7 +342,7 @@ struct l3_process { /* protocol specific data fields */ union - { u8 uuuu; /* only when euro not defined, avoiding empty union */ + { u_char uuuu; /* only when euro not defined, avoiding empty union */ #ifdef CONFIG_HISAX_EURO dss1_proc_priv dss1; /* private dss1 data */ #endif /* CONFIG_HISAX_EURO */ @@ -373,50 +353,58 @@ struct l3_process { }; struct hscx_hw { - u8 tsaxr0; - u8 tsaxr1; + int hscx; + int rcvidx; + int count; /* Current skb sent count */ + u_char *rcvbuf; /* B-Channel receive Buffer */ + u_char tsaxr0; + u_char tsaxr1; }; struct w6692B_hw { int bchan; + int rcvidx; + int count; /* Current skb sent count */ + u_char *rcvbuf; /* B-Channel receive Buffer */ }; struct isar_reg { unsigned long Flags; - volatile u8 bstat; - volatile u8 iis; - volatile u8 cmsb; - volatile u8 clsb; - volatile u8 par[8]; + volatile u_char bstat; + volatile u_char iis; + volatile u_char cmsb; + volatile u_char clsb; + volatile u_char par[8]; }; struct isar_hw { int dpath; int rcvidx; + int txcnt; int mml; - u8 state; - u8 cmd; - u8 mod; - u8 newcmd; - u8 newmod; + u_char state; + u_char cmd; + u_char mod; + u_char newcmd; + u_char newmod; char try_mod; struct timer_list ftimer; - u8 *rcvbuf; /* B-Channel receive Buffer */ - u8 conmsg[16]; + u_char *rcvbuf; /* B-Channel receive Buffer */ + u_char conmsg[16]; struct isar_reg *reg; }; struct hdlc_stat_reg { #ifdef __BIG_ENDIAN - u8 fill __attribute__((packed)); - u8 mode __attribute__((packed)); - u8 xml __attribute__((packed)); - u8 cmd __attribute__((packed)); -#else - u8 cmd __attribute__((packed)); - u8 xml __attribute__((packed)); - u8 mode __attribute__((packed)); - u8 fill __attribute__((packed)); + u_char fill __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char cmd __attribute__((packed)); +#else + u_char cmd __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char fill __attribute__((packed)); #endif }; @@ -426,6 +414,9 @@ struct hdlc_hw { struct hdlc_stat_reg sr; } ctrl; u_int stat; + int rcvidx; + int count; /* Current skb sent count */ + u_char *rcvbuf; /* B-Channel receive Buffer */ }; struct hfcB_hw { @@ -436,36 +427,35 @@ struct hfcB_hw { struct tiger_hw { u_int *send; - dma_addr_t send_dma; + u_int *s_irq; u_int *s_end; u_int *sendp; u_int *rec; - dma_addr_t rec_dma; int free; - u8 *rcvbuf; - u8 *sendbuf; - u8 *sp; + u_char *rcvbuf; + u_char *sendbuf; + u_char *sp; int sendcnt; u_int s_tot; u_int r_bitcnt; u_int r_tot; u_int r_err; u_int r_fcs; - u8 r_state; - u8 r_one; - u8 r_val; - u8 s_state; + u_char r_state; + u_char r_one; + u_char r_val; + u_char s_state; }; struct amd7930_hw { - u8 *tx_buff; - u8 *rv_buff; + u_char *tx_buff; + u_char *rv_buff; int rv_buff_in; int rv_buff_out; struct sk_buff *rv_skb; struct hdlc_state *hdlc_state; - struct work_struct rcv_work; - struct work_struct xmt_work; + struct work_struct tq_rcv; + struct work_struct tq_xmt; }; #define BC_FLG_INIT 1 @@ -483,6 +473,8 @@ struct amd7930_hw { #define BC_FLG_FTI_RUN 13 #define BC_FLG_LL_OK 14 #define BC_FLG_LL_CONN 15 +#define BC_FLG_FTI_FTS 16 +#define BC_FLG_FRH_WAIT 17 #define L1_MODE_NULL 0 #define L1_MODE_TRANS 1 @@ -496,29 +488,26 @@ struct amd7930_hw { struct BCState { int channel; int mode; - long Flag; + u_long Flag; struct IsdnCardState *cs; - int unit; /* first or second unit (e.g. HSCX) */ - int rcvidx; - u8 *rcvbuf; /* B-Channel receive Buffer */ - int tx_cnt; /* B-Channel transmit counter */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ - struct sk_buff_head rqueue; /* B-Channel receive queue */ - struct sk_buff_head squeue; /* B-Channel send queue */ - struct sk_buff_head cmpl_queue; /* B-Channel send complete queue */ + int tx_cnt; /* B-Channel transmit counter */ + struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ + struct sk_buff_head rqueue; /* B-Channel receive Queue */ + struct sk_buff_head squeue; /* B-Channel send Queue */ struct PStack *st; - u8 *blog; - u8 *conmsg; + u_char *blog; + u_char *conmsg; struct timer_list transbusy; - struct work_struct work; - unsigned long event; + struct work_struct tqueue; + u_long event; + int (*BC_SetStack) (struct PStack *, struct BCState *); + void (*BC_Close) (struct BCState *); #ifdef ERROR_STATISTIC int err_crc; int err_tx; int err_rdo; int err_inv; #endif - int count; union { struct hscx_hw hscx; struct hdlc_hw hdlc; @@ -545,12 +534,12 @@ struct Channel { int data_open; struct l3_process *proc; setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - long Flags; /* for remembering action done in l4 */ - /* long req'd for set_bit --RR */ + u_long Flags; /* for remembering action done in l4 */ int leased; }; struct elsa_hw { + struct pci_dev *dev; unsigned long base; unsigned int cfg; unsigned int ctrl; @@ -565,17 +554,17 @@ struct elsa_hw { struct timer_list tl; unsigned int MFlag; struct BCState *bcs; - u8 *transbuf; - u8 *rcvbuf; + u_char *transbuf; + u_char *rcvbuf; unsigned int transp; unsigned int rcvp; unsigned int transcnt; unsigned int rcvcnt; - u8 IER; - u8 FCR; - u8 LCR; - u8 MCR; - u8 ctrl_reg; + u_char IER; + u_char FCR; + u_char LCR; + u_char MCR; + u_char ctrl_reg; }; struct teles3_hw { @@ -588,8 +577,8 @@ struct teles3_hw { struct teles0_hw { unsigned int cfg_reg; + unsigned long membase; unsigned long phymem; - void *membase; }; struct avm_hw { @@ -599,6 +588,7 @@ struct avm_hw { unsigned int isacfifo; unsigned int hscxfifo[2]; unsigned int counter; + struct pci_dev *dev; }; struct ix1_hw { @@ -617,8 +607,10 @@ struct diva_hw { unsigned int isac; unsigned long hscx_adr; unsigned int hscx; + unsigned int status; struct timer_list tl; - u8 ctrl_reg; + u_char ctrl_reg; + struct pci_dev *dev; }; struct asus_hw { @@ -637,9 +629,9 @@ struct hfc_hw { unsigned char cirm; unsigned char ctmt; unsigned char cip; - u8 isac_spcr; + u_char isac_spcr; struct timer_list timer; -}; +}; struct sedl_hw { unsigned int cfg_reg; @@ -651,6 +643,7 @@ struct sedl_hw { struct isar_reg isar; unsigned int chip; unsigned int bus; + struct pci_dev *dev; }; struct spt_hw { @@ -677,9 +670,7 @@ struct njet_hw { unsigned char irqmask0; unsigned char irqstat0; unsigned char last_is0; - struct pci_dev *pdev; - void (*bc_activate)(struct IsdnCardState *cs, int bc); - void (*bc_deactivate)(struct IsdnCardState *cs, int bc); + struct pci_dev *dev; }; struct hfcPCI_hw { @@ -700,10 +691,10 @@ struct hfcPCI_hw { unsigned char bswapped; unsigned char nt_mode; int nt_timer; + struct pci_dev *dev; unsigned char *pci_io; /* start of PCI IO memory */ + void *share_start; /* shared memory for Fifos start */ void *fifos; /* FIFO memory */ - dma_addr_t fifos_dma; - struct pci_dev* pdev; int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ struct timer_list timer; }; @@ -756,12 +747,14 @@ struct hfcD_hw { struct isurf_hw { unsigned int reset; - void *isac; - void *isar; + unsigned long phymem; + unsigned long isac; + unsigned long isar; struct isar_reg isar_r; }; struct saphir_hw { + struct pci_dev *dev; unsigned int cfg_reg; unsigned int ale; unsigned int isac; @@ -770,6 +763,7 @@ struct saphir_hw { }; struct bkm_hw { + struct pci_dev *dev; unsigned long base; /* A4T stuff */ unsigned long isac_adr; @@ -782,7 +776,9 @@ struct bkm_hw { }; struct gazel_hw { + struct pci_dev *dev; unsigned int cfg_reg; + unsigned int pciaddr[2]; signed int ipac; signed int isac; signed int hscx[2]; @@ -793,6 +789,7 @@ struct gazel_hw { }; struct w6692_hw { + struct pci_dev *dev; unsigned int iobase; struct timer_list timer; }; @@ -812,25 +809,25 @@ struct te_hw { struct arcofi_msg { struct arcofi_msg *next; - u8 receive; - u8 len; - u8 msg[10]; + u_char receive; + u_char len; + u_char msg[10]; }; struct isac_chip { int ph_state; - u8 *mon_tx; - u8 *mon_rx; + u_char *mon_tx; + u_char *mon_rx; int mon_txp; int mon_txc; int mon_rxp; struct arcofi_msg *arcofi_list; struct timer_list arcofitimer; wait_queue_head_t arcofi_wait; - u8 arcofi_bc; - u8 arcofi_state; - u8 mocr; - u8 adf2; + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; }; struct hfcd_chip { @@ -850,80 +847,30 @@ struct w6692_chip { }; struct amd7930_chip { - u8 lmr1; - u8 ph_state; - u8 old_state; - u8 flg_t3; + u_char lmr1; + u_char ph_state; + u_char old_state; + u_char flg_t3; unsigned int tx_xmtlen; struct timer_list timer3; - void (*ph_command) (struct IsdnCardState *, u8, char *); - void (*setIrqMask) (struct IsdnCardState *, u8); + void (*ph_command) (struct IsdnCardState *, u_char, char *); + void (*setIrqMask) (struct IsdnCardState *, u_char); }; struct icc_chip { int ph_state; - u8 *mon_tx; - u8 *mon_rx; + u_char *mon_tx; + u_char *mon_rx; int mon_txp; int mon_txc; int mon_rxp; struct arcofi_msg *arcofi_list; struct timer_list arcofitimer; wait_queue_head_t arcofi_wait; - u8 arcofi_bc; - u8 arcofi_state; - u8 mocr; - u8 adf2; -}; - -struct IsdnCardState; - -/* Methods provided by driver for a specific card */ - -struct card_ops { - void (*init) (struct IsdnCardState *); - void (*test) (struct IsdnCardState *); - int (*reset) (struct IsdnCardState *); - void (*release) (struct IsdnCardState *); - void (*aux_ind) (struct IsdnCardState *, void *); - void (*led_handler)(struct IsdnCardState *); - irqreturn_t (*irq_func) (int, void *, struct pt_regs *); -}; - -/* Card specific drivers provide methods to access the - * chips to the chip drivers */ - -struct bc_hw_ops { - u8 (*read_reg) (struct IsdnCardState *, int, u8); - void (*write_reg) (struct IsdnCardState *, int, u8, u8); - void (*read_fifo) (struct IsdnCardState *, int, u8 *, int); - void (*write_fifo) (struct IsdnCardState *, int, u8 *, int); -}; - -struct dc_hw_ops { - u8 (*read_reg) (struct IsdnCardState *, u8); - void (*write_reg) (struct IsdnCardState *, u8, u8); - void (*read_fifo) (struct IsdnCardState *, u8 *, int); - void (*write_fifo) (struct IsdnCardState *, u8 *, int); -}; - -/* Methods provided to shared B-channel FIFO handling */ - -struct bc_l1_ops { - void (*fill_fifo) (struct BCState *); - int (*open) (struct PStack *, struct BCState *); - void (*close) (struct BCState *); -}; - -/* Methods provided to shared D-channel FIFO handling */ - -struct dc_l1_ops { - void (*fill_fifo) (struct IsdnCardState *); - int (*open) (struct PStack *, struct IsdnCardState *); - void (*close) (struct IsdnCardState *); - - void (*bh_func) (void *); - void (*dbusy_func) (struct IsdnCardState *); + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; }; #define HW_IOM1 0 @@ -933,25 +880,22 @@ struct dc_l1_ops { #define FLG_TWO_DCHAN 4 #define FLG_L1_DBUSY 5 #define FLG_DBUSY_TIMER 6 +#define FLG_LOCK_ATOMIC 7 #define FLG_ARCOFI_TIMER 8 #define FLG_ARCOFI_ERROR 9 #define FLG_HW_L1_UINT 10 -#define FLG_BUGGY_PLX9050 11 struct IsdnCardState { - unsigned char typ; - unsigned char subtyp; - spinlock_t lock; - struct card_ops *card_ops; - int protocol; - struct resources rs; - unsigned int irq; - unsigned long irq_flags; - int status; - long HW_Flags; - int *busy_flag; - int chanlimit; /* limited number of B-chans to use */ - int logecho; /* log echo if supported by card */ + spinlock_t lock; + u_char typ; + u_char subtyp; + int protocol; + u_int irq; + u_long irq_flags; + u_long HW_Flags; + int *busy_flag; + int chanlimit; /* limited number of B-chans to use */ + int logecho; /* log echo if supported by card */ union { struct elsa_hw elsa; struct teles0_hw teles0; @@ -979,25 +923,32 @@ struct IsdnCardState { struct w6692_hw w6692; struct hisax_d_if *hisax_d_if; } hw; - int myid; - isdn_if iif; - u8 *status_buf; - u8 *status_read; - u8 *status_write; - u8 *status_end; - struct dc_hw_ops *dc_hw_ops; - struct bc_hw_ops *bc_hw_ops; - struct dc_l1_ops *dc_l1_ops; - struct bc_l1_ops *bc_l1_ops; - int (*cardmsg) (struct IsdnCardState *, int, void *); - int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); - struct Channel channel[2+MAX_WAITING_CALLS]; - struct BCState bcs[2+MAX_WAITING_CALLS]; - struct PStack *stlist; + int myid; + isdn_if iif; + spinlock_t statlock; + u_char *status_buf; + u_char *status_read; + u_char *status_write; + u_char *status_end; + u_char (*readisac) (struct IsdnCardState *, u_char); + void (*writeisac) (struct IsdnCardState *, u_char, u_char); + void (*readisacfifo) (struct IsdnCardState *, u_char *, int); + void (*writeisacfifo) (struct IsdnCardState *, u_char *, int); + u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char); + void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char); + void (*BC_Send_Data) (struct BCState *); + int (*cardmsg) (struct IsdnCardState *, int, void *); + void (*setstack_d) (struct PStack *, struct IsdnCardState *); + void (*DC_Close) (struct IsdnCardState *); + int (*irq_func) (int, void *, struct pt_regs *); + int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); + struct Channel channel[2+MAX_WAITING_CALLS]; + struct BCState bcs[2+MAX_WAITING_CALLS]; + struct PStack *stlist; struct sk_buff_head rq, sq; /* D-channel queues */ - int cardnr; - char *dlog; - int debug; + int cardnr; + char *dlog; + int debug; union { struct isac_chip isac; struct hfcd_chip hfcd; @@ -1007,83 +958,287 @@ struct IsdnCardState { struct amd7930_chip amd7930; struct icc_chip icc; } dc; - u8 *rcvbuf; - int rcvidx; - struct sk_buff *tx_skb; - int tx_cnt; - long event; - struct work_struct work; + u_char *rcvbuf; + int rcvidx; + struct sk_buff *tx_skb; + int tx_cnt; + u_long event; + struct work_struct tqueue; struct timer_list dbusytimer; #ifdef ERROR_STATISTIC - int err_crc; - int err_tx; - int err_rx; + int err_crc; + int err_tx; + int err_rx; #endif }; -void -hisax_release_resources(struct IsdnCardState *cs); + +#define schedule_event(s, ev) do {test_and_set_bit(ev, &s->event);schedule_work(&s->tqueue); } while(0) #define MON0_RX 1 #define MON1_RX 2 #define MON0_TX 4 #define MON1_TX 8 -#define ISDN_CTYPE_16_0 1 -#define ISDN_CTYPE_8_0 2 -#define ISDN_CTYPE_16_3 3 -#define ISDN_CTYPE_PNP 4 -#define ISDN_CTYPE_A1 5 -#define ISDN_CTYPE_ELSA 6 -#define ISDN_CTYPE_ELSA_PNP 7 -#define ISDN_CTYPE_TELESPCMCIA 8 -#define ISDN_CTYPE_IX1MICROR2 9 -#define ISDN_CTYPE_ELSA_PCMCIA 10 -#define ISDN_CTYPE_DIEHLDIVA 11 -#define ISDN_CTYPE_ASUSCOM 12 -#define ISDN_CTYPE_TELEINT 13 -#define ISDN_CTYPE_TELES3C 14 -#define ISDN_CTYPE_SEDLBAUER 15 -#define ISDN_CTYPE_SPORTSTER 16 -#define ISDN_CTYPE_MIC 17 -#define ISDN_CTYPE_ELSA_PCI 18 -#define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET_S 20 -#define ISDN_CTYPE_TELESPCI 21 -#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 -#define ISDN_CTYPE_AMD7930 23 -#define ISDN_CTYPE_NICCY 24 -#define ISDN_CTYPE_S0BOX 25 -#define ISDN_CTYPE_A1_PCMCIA 26 -#define ISDN_CTYPE_FRITZPCI 27 -#define ISDN_CTYPE_SEDLBAUER_FAX 28 -#define ISDN_CTYPE_ISURF 29 -#define ISDN_CTYPE_ACERP10 30 -#define ISDN_CTYPE_HSTSAPHIR 31 -#define ISDN_CTYPE_BKM_A4T 32 -#define ISDN_CTYPE_SCT_QUADRO 33 -#define ISDN_CTYPE_GAZEL 34 -#define ISDN_CTYPE_HFC_PCI 35 -#define ISDN_CTYPE_W6692 36 -#define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_NETJET_U 38 -#define ISDN_CTYPE_HFC_SP_PCMCIA 39 -#define ISDN_CTYPE_DYNAMIC 40 -#define ISDN_CTYPE_ENTERNOW 41 -#define ISDN_CTYPE_COUNT 41 +#ifdef ISDN_CHIP_ISAC +#undef ISDN_CHIP_ISAC +#endif + +#ifdef CONFIG_HISAX_16_0 +#define CARD_TELES0 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_TELES0 0 +#endif + +#ifdef CONFIG_HISAX_16_3 +#define CARD_TELES3 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_TELES3 0 +#endif + +#ifdef CONFIG_HISAX_TELESPCI +#define CARD_TELESPCI 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_TELESPCI 0 +#endif + +#ifdef CONFIG_HISAX_AVM_A1 +#define CARD_AVM_A1 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_AVM_A1 0 +#endif + +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#define CARD_AVM_A1_PCMCIA 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_AVM_A1_PCMCIA 0 +#endif + +#ifdef CONFIG_HISAX_FRITZPCI +#define CARD_FRITZPCI 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_FRITZPCI 0 +#endif + +#ifdef CONFIG_HISAX_ELSA +#define CARD_ELSA 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_ELSA 0 +#endif + +#ifdef CONFIG_HISAX_IX1MICROR2 +#define CARD_IX1MICROR2 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_IX1MICROR2 0 +#endif + +#ifdef CONFIG_HISAX_DIEHLDIVA +#define CARD_DIEHLDIVA 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_DIEHLDIVA 0 +#endif + +#ifdef CONFIG_HISAX_ASUSCOM +#define CARD_ASUSCOM 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_ASUSCOM 0 +#endif + +#ifdef CONFIG_HISAX_TELEINT +#define CARD_TELEINT 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_TELEINT 0 +#endif + +#ifdef CONFIG_HISAX_SEDLBAUER +#define CARD_SEDLBAUER 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_SEDLBAUER 0 +#endif + +#ifdef CONFIG_HISAX_SPORTSTER +#define CARD_SPORTSTER 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_SPORTSTER 0 +#endif + +#ifdef CONFIG_HISAX_MIC +#define CARD_MIC 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_MIC 0 +#endif + +#ifdef CONFIG_HISAX_NETJET +#define CARD_NETJET_S 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_NETJET_S 0 +#endif + +#ifdef CONFIG_HISAX_HFCS +#define CARD_HFCS 1 +#else +#define CARD_HFCS 0 +#endif + +#ifdef CONFIG_HISAX_HFC_PCI +#define CARD_HFC_PCI 1 +#else +#define CARD_HFC_PCI 0 +#endif + +#ifdef CONFIG_HISAX_HFC_SX +#define CARD_HFC_SX 1 +#else +#define CARD_HFC_SX 0 +#endif + +#ifdef CONFIG_HISAX_AMD7930 +#define CARD_AMD7930 1 +#else +#define CARD_AMD7930 0 +#endif + +#ifdef CONFIG_HISAX_NICCY +#define CARD_NICCY 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_NICCY 0 +#endif + +#ifdef CONFIG_HISAX_ISURF +#define CARD_ISURF 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_ISURF 0 +#endif + +#ifdef CONFIG_HISAX_S0BOX +#define CARD_S0BOX 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_S0BOX 0 +#endif + +#ifdef CONFIG_HISAX_HSTSAPHIR +#define CARD_HSTSAPHIR 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_HSTSAPHIR 0 +#endif #ifdef CONFIG_HISAX_TESTEMU +#define CARD_TESTEMU 1 #define ISDN_CTYPE_TESTEMU 99 #undef ISDN_CTYPE_COUNT #define ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU +#else +#define CARD_TESTEMU 0 +#endif + +#ifdef CONFIG_HISAX_BKM_A4T +#define CARD_BKM_A4T 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_BKM_A4T 0 +#endif + +#ifdef CONFIG_HISAX_SCT_QUADRO +#define CARD_SCT_QUADRO 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_SCT_QUADRO 0 +#endif + +#ifdef CONFIG_HISAX_GAZEL +#define CARD_GAZEL 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_GAZEL 0 +#endif + +#ifdef CONFIG_HISAX_W6692 +#define CARD_W6692 1 +#ifndef ISDN_CHIP_W6692 +#define ISDN_CHIP_W6692 1 +#endif +#else +#define CARD_W6692 0 #endif #ifdef CONFIG_HISAX_NETJET_U +#define CARD_NETJET_U 1 +#ifndef ISDN_CHIP_ICC +#define ISDN_CHIP_ICC 1 +#endif #ifndef HISAX_UINTERFACE #define HISAX_UINTERFACE 1 #endif #else +#define CARD_NETJET_U 0 +#endif + +#ifdef CONFIG_HISAX_ENTERNOW_PCI +#define CARD_FN_ENTERNOW_PCI 1 #endif #define TEI_PER_CARD 1 @@ -1108,12 +1263,7 @@ hisax_release_resources(struct IsdnCardS extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); #endif -struct IsdnCard { - int typ; - int protocol; /* EDSS1, 1TR6 or NI1 */ - unsigned long para[4]; - struct IsdnCardState *cs; -}; +#include "hisax_cfg.h" void init_bcstate(struct IsdnCardState *cs, int bc); @@ -1136,8 +1286,8 @@ void setstack_l3dc(struct PStack *st, st void setstack_l3bc(struct PStack *st, struct Channel *chanp); void releasestack_isdnl3(struct PStack *st); -u8 *findie(u8 * p, int size, u8 ie, int wanted_set); -int getcallref(u8 * p); +u_char *findie(u_char * p, int size, u_char ie, int wanted_set); +int getcallref(u_char * p); int newcallref(void); int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); @@ -1155,12 +1305,15 @@ int jiftime(char *s, long mark); int HiSax_command(isdn_ctrl * ic); int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb); void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...); -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args); +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args); void HiSax_reportcard(int cardnr, int sel); -int QuickHex(char *txt, u8 * p, int cnt); -void LogFrame(struct IsdnCardState *cs, u8 * p, int size); +int QuickHex(char *txt, u_char * p, int cnt); +void LogFrame(struct IsdnCardState *cs, u_char * p, int size); void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); -void iecpy(u8 * dest, u8 * iestart, int ieoffset); +void iecpy(u_char * dest, u_char * iestart, int ieoffset); +#ifdef ISDN_CHIP_ISAC +void setstack_isac(struct PStack *st, struct IsdnCardState *cs); +#endif /* ISDN_CHIP_ISAC */ #endif /* __KERNEL__ */ #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} @@ -1182,43 +1335,3 @@ void release_tei(struct IsdnCardState *c char *HiSax_getrev(const char *revision); int TeiNew(void); void TeiFree(void); -int certification_check(int output); - -static inline void -L2L1(struct PStack *st, int pr, void *arg) -{ - st->l1.l2l1(st, pr, arg); -} - -static inline void -L1L2(struct PStack *st, int pr, void *arg) -{ - st->l2.l1l2(st, pr, arg); -} - -static inline void -L3L2(struct PStack *st, int pr, void *arg) -{ - st->l2.l3l2(st, pr, arg); -} - -static inline void -L2L3(struct PStack *st, int pr, void *arg) -{ - st->l3.l2l3(st, pr, arg); -} - -static inline void -L3L4(struct PStack *st, int pr, void *arg) -{ - st->lli.l3l4(st, pr, arg); -} - -static inline void -L4L3(struct PStack *st, int pr, void *arg) -{ - st->l3.l4l3(st, pr, arg); -} - - -#endif diff -puN -L drivers/isdn/hisax/hisax_hfcpci.c drivers/isdn/hisax/hisax_hfcpci.c~i4l /dev/null --- 25/drivers/isdn/hisax/hisax_hfcpci.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,1645 +0,0 @@ -/* - * Driver for HFC PCI based cards - * - * Author Kai Germaschewski - * Copyright 2002 by Kai Germaschewski - * 2000 by Karsten Keil - * 2000 by Werner Cornelius - * - * based upon Werner Cornelius's original hfc_pci.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -// XXX timer3 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hisax_hfcpci.h" - -// debugging cruft -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_AUTHOR("Kai Germaschewski /Werner Cornelius "); -MODULE_DESCRIPTION("HFC PCI ISDN driver"); - -#define ID(ven, dev, name) \ - { .vendor = PCI_VENDOR_ID_##ven, \ - .device = PCI_DEVICE_ID_##dev, \ - .subvendor = PCI_ANY_ID, \ - .subdevice = PCI_ANY_ID, \ - .class = 0, \ - .class_mask = 0, \ - .driver_data = (unsigned long) name } - -static struct pci_device_id hfcpci_ids[] = { - ID(CCD, CCD_2BD0, "CCD/Billion/Asuscom 2BD0"), - ID(CCD, CCD_B000, "Billion B000"), - ID(CCD, CCD_B006, "Billion B006"), - ID(CCD, CCD_B007, "Billion B007"), - ID(CCD, CCD_B008, "Billion B008"), - ID(CCD, CCD_B009, "Billion B009"), - ID(CCD, CCD_B00A, "Billion B00A"), - ID(CCD, CCD_B00B, "Billion B00B"), - ID(CCD, CCD_B00C, "Billion B00C"), - ID(CCD, CCD_B100, "Seyeon"), - ID(ABOCOM, ABOCOM_2BD1, "Abocom/Magitek"), - ID(ASUSTEK, ASUSTEK_0675, "Asuscom/Askey"), - ID(BERKOM, BERKOM_T_CONCEPT, "German Telekom T-Concept"), - ID(BERKOM, BERKOM_A1T, "German Telekom A1T"), - ID(ANIGMA, ANIGMA_MC145575, "Motorola MC145575"), - ID(ZOLTRIX, ZOLTRIX_2BD0, "Zoltrix 2BD0"), - ID(DIGI, DIGI_DF_M_IOM2_E, "Digi DataFire Micro V IOM2 (Europe)"), - ID(DIGI, DIGI_DF_M_E, "Digi DataFire Micro V (Europe)"), - ID(DIGI, DIGI_DF_M_IOM2_A, "Digi DataFire Micro V IOM2 (America)"), - ID(DIGI, DIGI_DF_M_A, "Digi DataFire Micro V (America)"), - { } -}; -MODULE_DEVICE_TABLE(pci, hfcpci_ids); - -#undef ID - -static int protocol = 2; /* EURO-ISDN Default */ -MODULE_PARM(protocol, "i"); - -// ---------------------------------------------------------------------- -// - -#define DBG_WARN 0x0001 -#define DBG_INFO 0x0002 -#define DBG_IRQ 0x0010 -#define DBG_L1M 0x0020 -#define DBG_PR 0x0040 -#define DBG_D_XMIT 0x0100 -#define DBG_D_RECV 0x0200 -#define DBG_B_XMIT 0x1000 -#define DBG_B_RECV 0x2000 - -/* memory window base address offset (in config space) */ - -#define HFCPCI_MWBA 0x80 - -/* GCI/IOM bus monitor registers */ - -#define HCFPCI_C_I 0x08 -#define HFCPCI_TRxR 0x0C -#define HFCPCI_MON1_D 0x28 -#define HFCPCI_MON2_D 0x2C - - -/* GCI/IOM bus timeslot registers */ - -#define HFCPCI_B1_SSL 0x80 -#define HFCPCI_B2_SSL 0x84 -#define HFCPCI_AUX1_SSL 0x88 -#define HFCPCI_AUX2_SSL 0x8C -#define HFCPCI_B1_RSL 0x90 -#define HFCPCI_B2_RSL 0x94 -#define HFCPCI_AUX1_RSL 0x98 -#define HFCPCI_AUX2_RSL 0x9C - -/* GCI/IOM bus data registers */ - -#define HFCPCI_B1_D 0xA0 -#define HFCPCI_B2_D 0xA4 -#define HFCPCI_AUX1_D 0xA8 -#define HFCPCI_AUX2_D 0xAC - -/* GCI/IOM bus configuration registers */ - -#define HFCPCI_MST_EMOD 0xB4 -#define HFCPCI_MST_MODE 0xB8 -#define HFCPCI_CONNECT 0xBC - - -/* Interrupt and status registers */ - -#define HFCPCI_FIFO_EN 0x44 -#define HFCPCI_TRM 0x48 -#define HFCPCI_B_MODE 0x4C -#define HFCPCI_CHIP_ID 0x58 -#define HFCPCI_CIRM 0x60 -#define HFCPCI_CTMT 0x64 -#define HFCPCI_INT_M1 0x68 -#define HFCPCI_INT_M2 0x6C -#define HFCPCI_INT_S1 0x78 -#define HFCPCI_INT_S2 0x7C -#define HFCPCI_STATUS 0x70 - -/* S/T section registers */ - -#define HFCPCI_STATES 0xC0 -#define HFCPCI_SCTRL 0xC4 -#define HFCPCI_SCTRL_E 0xC8 -#define HFCPCI_SCTRL_R 0xCC -#define HFCPCI_SQ 0xD0 -#define HFCPCI_CLKDEL 0xDC -#define HFCPCI_B1_REC 0xF0 -#define HFCPCI_B1_SEND 0xF0 -#define HFCPCI_B2_REC 0xF4 -#define HFCPCI_B2_SEND 0xF4 -#define HFCPCI_D_REC 0xF8 -#define HFCPCI_D_SEND 0xF8 -#define HFCPCI_E_REC 0xFC - - -/* bits in status register (READ) */ -#define HFCPCI_PCI_PROC 0x02 -#define HFCPCI_NBUSY 0x04 -#define HFCPCI_TIMER_ELAP 0x10 -#define HFCPCI_STATINT 0x20 -#define HFCPCI_FRAMEINT 0x40 -#define HFCPCI_ANYINT 0x80 - -/* bits in CTMT (Write) */ -#define HFCPCI_CLTIMER 0x80 -#define HFCPCI_TIM3_125 0x04 -#define HFCPCI_TIM25 0x10 -#define HFCPCI_TIM50 0x14 -#define HFCPCI_TIM400 0x18 -#define HFCPCI_TIM800 0x1C -#define HFCPCI_AUTO_TIMER 0x20 -#define HFCPCI_TRANSB2 0x02 -#define HFCPCI_TRANSB1 0x01 - -/* bits in CIRM (Write) */ -#define HFCPCI_AUX_MSK 0x07 -#define HFCPCI_RESET 0x08 -#define HFCPCI_B1_REV 0x40 -#define HFCPCI_B2_REV 0x80 - -/* bits in INT_M1 and INT_S1 */ -#define HFCPCI_INTS_B1TRANS 0x01 -#define HFCPCI_INTS_B2TRANS 0x02 -#define HFCPCI_INTS_DTRANS 0x04 -#define HFCPCI_INTS_B1REC 0x08 -#define HFCPCI_INTS_B2REC 0x10 -#define HFCPCI_INTS_DREC 0x20 -#define HFCPCI_INTS_L1STATE 0x40 -#define HFCPCI_INTS_TIMER 0x80 - -/* bits in INT_M2 */ -#define HFCPCI_PROC_TRANS 0x01 -#define HFCPCI_GCI_I_CHG 0x02 -#define HFCPCI_GCI_MON_REC 0x04 -#define HFCPCI_IRQ_ENABLE 0x08 -#define HFCPCI_PMESEL 0x80 - -/* bits in STATES */ -#define HFCPCI_STATE_MSK 0x0F -#define HFCPCI_LOAD_STATE 0x10 -#define HFCPCI_ACTIVATE 0x20 -#define HFCPCI_DO_ACTION 0x40 -#define HFCPCI_NT_G2_G3 0x80 - -/* bits in HFCD_MST_MODE */ -#define HFCPCI_MASTER 0x01 -#define HFCPCI_SLAVE 0x00 -/* remaining bits are for codecs control */ - -/* bits in HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_MODE_TE 0x00 -#define SCTRL_MODE_NT 0x04 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* bits in SCTRL_E */ -#define HFCPCI_AUTO_AWAKE 0x01 -#define HFCPCI_DBIT_1 0x04 -#define HFCPCI_IGNORE_COL 0x08 -#define HFCPCI_CHG_B1_B2 0x80 - -/* bits in FIFO_EN register */ -#define HFCPCI_FIFOEN_B1 0x03 -#define HFCPCI_FIFOEN_B2 0x0C -#define HFCPCI_FIFOEN_DTX 0x10 -#define HFCPCI_FIFOEN_DRX 0x20 -#define HFCPCI_FIFOEN_B1TX 0x01 -#define HFCPCI_FIFOEN_B1RX 0x02 -#define HFCPCI_FIFOEN_B2TX 0x04 -#define HFCPCI_FIFOEN_B2RX 0x08 - -/* - * thresholds for transparent B-channel mode - * change mask and threshold simultaneously - */ -#define HFCPCI_BTRANS_THRESHOLD 128 -#define HFCPCI_BTRANS_THRESMASK 0x00 - -#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ -#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ - -#define MAX_D_FRAMES 0x10 -#define MAX_B_FRAMES 0x20 -#define B_FIFO_START 0x0200 -#define B_FIFO_END 0x2000 -#define B_FIFO_SIZE (B_FIFO_END - B_FIFO_START) -#define D_FIFO_START 0x0000 -#define D_FIFO_END 0x0200 -#define D_FIFO_SIZE (D_FIFO_END - D_FIFO_START) - -// ---------------------------------------------------------------------- -// push messages to the upper layers - -static inline void D_L1L2(struct hfcpci_adapter *adapter, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &adapter->d_if; - - DBG(DBG_PR, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -static inline void B_L1L2(struct hfcpci_bcs *bcs, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; - - DBG(DBG_PR, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -// ---------------------------------------------------------------------- -// MMIO - -static inline void -hfcpci_writeb(struct hfcpci_adapter *adapter, u8 b, unsigned char offset) -{ - writeb(b, adapter->mmio + offset); -} - -static inline u8 -hfcpci_readb(struct hfcpci_adapter *adapter, unsigned char offset) -{ - return readb(adapter->mmio + offset); -} - -// ---------------------------------------------------------------------- -// magic to define the various F/Z counter accesses - -#define DECL_B_F(r, f) \ -static inline u8 \ -get_b_##r##_##f (struct hfcpci_bcs *bcs) \ -{ \ - u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \ - \ - return *(bcs->adapter->fifo + off); \ -} \ - \ -static inline void \ -set_b_##r##_##f (struct hfcpci_bcs *bcs, u8 f) \ -{ \ - u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \ - \ - *(bcs->adapter->fifo + off) = f; \ -} - -#define OFF_B1_rx_f1 0x6080 -#define OFF_B2_rx_f1 0x6180 -#define OFF_B1_rx_f2 0x6081 -#define OFF_B2_rx_f2 0x6181 - -#define OFF_B1_tx_f1 0x2080 -#define OFF_B2_tx_f1 0x2180 -#define OFF_B1_tx_f2 0x2081 -#define OFF_B2_tx_f2 0x2181 - -DECL_B_F(rx, f1) -DECL_B_F(rx, f2) -DECL_B_F(tx, f1) -DECL_B_F(tx, f2) - -#undef DECL_B_F - -#define DECL_B_Z(r, z) \ -static inline u16 \ -get_b_##r##_##z (struct hfcpci_bcs *bcs, u8 f) \ -{ \ - u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \ - \ - return le16_to_cpu(*((u16 *) (bcs->adapter->fifo + off + f * 4))); \ -} \ - \ -static inline void \ -set_b_##r##_##z(struct hfcpci_bcs *bcs, u8 f, u16 z) \ -{ \ - u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \ - \ - *((u16 *) (bcs->adapter->fifo + off + f * 4)) = cpu_to_le16(z); \ -} - -#define OFF_B1_rx_z1 0x6000 -#define OFF_B2_rx_z1 0x6100 -#define OFF_B1_rx_z2 0x6002 -#define OFF_B2_rx_z2 0x6102 - -#define OFF_B1_tx_z1 0x2000 -#define OFF_B2_tx_z1 0x2100 -#define OFF_B1_tx_z2 0x2002 -#define OFF_B2_tx_z2 0x2102 - -DECL_B_Z(rx, z1) -DECL_B_Z(rx, z2) -DECL_B_Z(tx, z1) -DECL_B_Z(tx, z2) - -#undef DECL_B_Z - -#define DECL_D_F(r, f) \ -static inline u8 \ -get_d_##r##_##f (struct hfcpci_adapter *adapter) \ -{ \ - u16 off = OFF_D_##r##_##f; \ - \ - return *(adapter->fifo + off) & 0xf; \ -} \ - \ -static inline void \ -set_d_##r##_##f (struct hfcpci_adapter *adapter, u8 f) \ -{ \ - u16 off = OFF_D_##r##_##f; \ - \ - *(adapter->fifo + off) = f | 0x10; \ -} - -#define OFF_D_rx_f1 0x60a0 -#define OFF_D_rx_f2 0x60a1 - -#define OFF_D_tx_f1 0x20a0 -#define OFF_D_tx_f2 0x20a1 - -DECL_D_F(rx, f1) -DECL_D_F(rx, f2) -DECL_D_F(tx, f1) -DECL_D_F(tx, f2) - -#undef DECL_D_F - -#define DECL_D_Z(r, z) \ -static inline u16 \ -get_d_##r##_##z (struct hfcpci_adapter *adapter, u8 f) \ -{ \ - u16 off = OFF_D_##r##_##z; \ - \ - return le16_to_cpu(*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)));\ -} \ - \ -static inline void \ -set_d_##r##_##z(struct hfcpci_adapter *adapter, u8 f, u16 z) \ -{ \ - u16 off = OFF_D_##r##_##z; \ - \ - *((u16 *) (adapter->fifo + off + (f | 0x10) * 4)) = cpu_to_le16(z); \ -} - -#define OFF_D_rx_z1 0x6080 -#define OFF_D_rx_z2 0x6082 - -#define OFF_D_tx_z1 0x2080 -#define OFF_D_tx_z2 0x2082 - -DECL_D_Z(rx, z1) -DECL_D_Z(rx, z2) -DECL_D_Z(tx, z1) -DECL_D_Z(tx, z2) - -#undef DECL_B_Z - -// ---------------------------------------------------------------------- -// fill b / d fifos - -static inline void -hfcpci_fill_d_fifo(struct hfcpci_adapter *adapter) -{ - u8 f1, f2; - u16 z1, z2; - int cnt, fcnt; - char *fifo_adr = adapter->fifo; - struct sk_buff *tx_skb = adapter->tx_skb; - - f1 = get_d_tx_f1(adapter); - f2 = get_d_tx_f2(adapter); - DBG(DBG_D_XMIT, "f1 %#x f2 %#x", f1, f2); - - fcnt = f1 - f2; - if (fcnt < 0) - fcnt += MAX_D_FRAMES; - - if (fcnt) { - printk("BUG\n"); - return; - } - - z1 = get_d_tx_z1(adapter, f1); - z2 = get_d_tx_z2(adapter, f1); //XXX - DBG(DBG_D_XMIT, "z1 %#x z2 %#x", z1, z2); - - cnt = z2 - z1; - if (cnt <= 0) - cnt += D_FIFO_SIZE; - - if (tx_skb->len > cnt) { - printk("BUG\n"); - return; - } - - cnt = tx_skb->len; - if (z1 + cnt <= D_FIFO_END) { - memcpy(fifo_adr + z1, tx_skb->data, cnt); - } else { - memcpy(fifo_adr + z1, tx_skb->data, D_FIFO_END - z1); - memcpy(fifo_adr + D_FIFO_START, - tx_skb->data + (D_FIFO_END - z1), - cnt - (D_FIFO_END - z1)); - } - z1 += cnt; - if (z1 >= D_FIFO_END) - z1 -= D_FIFO_SIZE; - - f1 = (f1 + 1) & (MAX_D_FRAMES - 1); - mb(); - set_d_tx_z1(adapter, f1, z1); - mb(); - set_d_tx_f1(adapter, f1); -} - -static inline void -hfcpci_fill_b_fifo_hdlc(struct hfcpci_bcs *bcs) -{ - u8 f1, f2; - u16 z1, z2; - int cnt, fcnt; - char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000); - struct sk_buff *tx_skb = bcs->tx_skb; - - f1 = get_b_tx_f1(bcs); - f2 = get_b_tx_f2(bcs); - DBG(DBG_B_XMIT, "f1 %#x f2 %#x", f1, f2); - - fcnt = f1 - f2; - if (fcnt < 0) - fcnt += MAX_B_FRAMES; - - if (fcnt) { - printk("BUG\n"); - return; - } - - z1 = get_b_tx_z1(bcs, f1); - z2 = get_b_tx_z2(bcs, f1); //XXX - DBG(DBG_B_XMIT, "z1 %#x z2 %#x", z1, z2); - - cnt = z2 - z1; - if (cnt <= 0) - cnt += B_FIFO_SIZE; - - if (tx_skb->len > cnt) { - printk("BUG\n"); - return; - } - - cnt = tx_skb->len; - if (z1 + cnt <= B_FIFO_END) { - memcpy(fifo_adr + z1, tx_skb->data, cnt); - } else { - memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1); - memcpy(fifo_adr + B_FIFO_START, - tx_skb->data + (B_FIFO_END - z1), - cnt - (B_FIFO_END - z1)); - } - z1 += cnt; - if (z1 >= B_FIFO_END) - z1 -= B_FIFO_SIZE; - - f1 = (f1 + 1) & (MAX_B_FRAMES - 1); - mb(); - set_b_tx_z1(bcs, f1, z1); - mb(); - set_b_tx_f1(bcs, f1); -} - -static inline void -hfcpci_fill_b_fifo_trans(struct hfcpci_bcs *bcs) -{ - int cnt; - char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000); - struct sk_buff *tx_skb = bcs->tx_skb; - u8 f1, f2; - u16 z1, z2; - - f1 = get_b_tx_f1(bcs); - f2 = get_b_tx_f2(bcs); - - if (f1 != f2) - BUG(); - - z1 = get_b_tx_z1(bcs, f1); - z2 = get_b_tx_z2(bcs, f1); - - cnt = z2 - z1; - if (cnt <= 0) - cnt += B_FIFO_SIZE; - - if (tx_skb->len > cnt) - BUG(); - - if (z1 + cnt <= B_FIFO_END) { - memcpy(fifo_adr + z1, tx_skb->data, cnt); - } else { - memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1); - memcpy(fifo_adr + B_FIFO_START, - tx_skb->data + (B_FIFO_END - z1), - cnt - (B_FIFO_END - z1)); - } - z1 += cnt; - if (z1 >= B_FIFO_END) - z1 -= B_FIFO_SIZE; - - mb(); - set_b_tx_z1(bcs, f1, z1); -} - -static inline void -hfcpci_fill_b_fifo(struct hfcpci_bcs *bcs) -{ - if (!bcs->tx_skb) { - DBG(DBG_WARN, "?"); - return; - } - - switch (bcs->mode) { - case L1_MODE_TRANS: - hfcpci_fill_b_fifo_trans(bcs); - break; - case L1_MODE_HDLC: - hfcpci_fill_b_fifo_hdlc(bcs); - break; - default: - DBG(DBG_WARN, "?"); - } -} - -static void hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs); -static void hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs); - -static void -hfcpci_b_mode(struct hfcpci_bcs *bcs, int mode) -{ - struct hfcpci_adapter *adapter = bcs->adapter; - - DBG(DBG_B_XMIT, "B%d mode %d --> %d", - bcs->channel + 1, bcs->mode, mode); - - if (bcs->mode == mode) - return; - - switch (mode) { - case L1_MODE_NULL: - if (bcs->channel == 0) { - adapter->sctrl &= ~SCTRL_B1_ENA; - adapter->sctrl_r &= ~SCTRL_B1_ENA; - adapter->fifo_en &= ~HFCPCI_FIFOEN_B1; - adapter->int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - } else { - adapter->sctrl &= ~SCTRL_B2_ENA; - adapter->sctrl_r &= ~SCTRL_B2_ENA; - adapter->fifo_en &= ~HFCPCI_FIFOEN_B2; - adapter->int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - } - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - hfcpci_clear_b_rx_fifo(bcs); - hfcpci_clear_b_tx_fifo(bcs); - if (bcs->channel == 0) { - adapter->sctrl |= SCTRL_B1_ENA; - adapter->sctrl_r |= SCTRL_B1_ENA; - adapter->fifo_en |= HFCPCI_FIFOEN_B1; - adapter->int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - - if (mode == L1_MODE_TRANS) - adapter->ctmt |= 1; - else - adapter->ctmt &= ~1; - - } else { - adapter->sctrl |= SCTRL_B2_ENA; - adapter->sctrl_r |= SCTRL_B2_ENA; - adapter->fifo_en |= HFCPCI_FIFOEN_B2; - adapter->int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - - if (mode == L1_MODE_TRANS) - adapter->ctmt |= 2; - else - adapter->ctmt &= ~2; - - } - break; - } - hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL); - hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R); - hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT); - hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT); - - bcs->mode = mode; -} - -// ---------------------------------------------------------------------- -// Layer 1 state machine - -static struct Fsm l1fsm; - -enum { - ST_L1_F0, - ST_L1_F2, - ST_L1_F3, - ST_L1_F4, - ST_L1_F5, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1_STATE_COUNT (ST_L1_F8+1) - -static char *strL1State[] = -{ - "ST_L1_F0", - "ST_L1_F2", - "ST_L1_F3", - "ST_L1_F4", - "ST_L1_F5", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -enum { - EV_PH_F0, - EV_PH_1, - EV_PH_F2, - EV_PH_F3, - EV_PH_F4, - EV_PH_F5, - EV_PH_F6, - EV_PH_F7, - EV_PH_F8, - EV_PH_ACTIVATE_REQ, - EV_PH_DEACTIVATE_REQ, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -static char *strL1Event[] = -{ - "EV_PH_F0", - "EV_PH_1", - "EV_PH_F2", - "EV_PH_F3", - "EV_PH_F4", - "EV_PH_F5", - "EV_PH_F6", - "EV_PH_F7", - "EV_PH_F8", - "EV_PH_ACTIVATE_REQ", - "EV_PH_DEACTIVATE_REQ", - "EV_TIMER3", -}; - -static void l1_ignore(struct FsmInst *fi, int event, void *arg) -{ -} - -static void l1_go_f3(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3); -} - -static void l1_go_f3_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct hfcpci_adapter *adapter = fi->userdata; - - FsmChangeState(fi, ST_L1_F3); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_go_f4(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3); -} - -static void l1_go_f5(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3); -} - -static void l1_go_f6(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F6); -} - -static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct hfcpci_adapter *adapter = fi->userdata; - - FsmChangeState(fi, ST_L1_F6); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_go_f7(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F7); -} - -static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg) -{ - struct hfcpci_adapter *adapter = fi->userdata; - - FsmChangeState(fi, ST_L1_F7); - D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL); -} - -static void l1_go_f8(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F8); -} - -static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct hfcpci_adapter *adapter = fi->userdata; - - FsmChangeState(fi, ST_L1_F8); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_act_req(struct FsmInst *fi, int event, void *arg) -{ - struct hfcpci_adapter *adapter = fi->userdata; - - hfcpci_writeb(adapter, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION, HFCPCI_STATES); -} - -static struct FsmNode L1FnList[] __initdata = -{ - {ST_L1_F2, EV_PH_F3, l1_go_f3}, - {ST_L1_F2, EV_PH_F6, l1_go_f6}, - {ST_L1_F2, EV_PH_F7, l1_go_f7_act_ind}, - - {ST_L1_F3, EV_PH_F3, l1_ignore}, - {ST_L1_F3, EV_PH_F4, l1_go_f4}, - {ST_L1_F3, EV_PH_F5, l1_go_f5}, - {ST_L1_F3, EV_PH_F6, l1_go_f6}, - {ST_L1_F3, EV_PH_F7, l1_go_f7_act_ind}, - {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_act_req}, - - {ST_L1_F4, EV_PH_F7, l1_ignore}, - {ST_L1_F4, EV_PH_F3, l1_go_f3}, - {ST_L1_F4, EV_PH_F5, l1_go_f5}, - {ST_L1_F4, EV_PH_F6, l1_go_f6}, - {ST_L1_F4, EV_PH_F7, l1_go_f7}, - - {ST_L1_F5, EV_PH_F7, l1_ignore}, - {ST_L1_F5, EV_PH_F3, l1_go_f3}, - {ST_L1_F5, EV_PH_F6, l1_go_f6}, - {ST_L1_F5, EV_PH_F7, l1_go_f7}, - - {ST_L1_F6, EV_PH_F7, l1_ignore}, - {ST_L1_F6, EV_PH_F3, l1_go_f3}, - {ST_L1_F6, EV_PH_F7, l1_go_f7_act_ind}, - {ST_L1_F6, EV_PH_F8, l1_go_f8}, - - {ST_L1_F7, EV_PH_F7, l1_ignore}, - {ST_L1_F7, EV_PH_F3, l1_go_f3_deact_ind}, - {ST_L1_F7, EV_PH_F6, l1_go_f6_deact_ind}, - {ST_L1_F7, EV_PH_F8, l1_go_f8_deact_ind}, - - {ST_L1_F8, EV_PH_F7, l1_ignore}, - {ST_L1_F8, EV_PH_F3, l1_go_f3}, - {ST_L1_F8, EV_PH_F6, l1_go_f6}, - {ST_L1_F8, EV_PH_F7, l1_go_f7_act_ind}, - -}; - -static void l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsprintf(buf, fmt, args); - DBG(DBG_L1M, "%s", buf); - va_end(args); -} - -// ---------------------------------------------------------------------- -// clear FIFOs - -static void -hfcpci_clear_d_rx_fifo(struct hfcpci_adapter *adapter) -{ - u8 fifo_state; - - DBG(DBG_D_RECV, ""); - - fifo_state = adapter->fifo_en & HFCPCI_FIFOEN_DRX; - - if (fifo_state) { // enabled - // XXX locking - adapter->fifo_en &= ~fifo_state; - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - } - - adapter->last_fcnt = 0; - - set_d_rx_z1(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1); - set_d_rx_z2(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1); - mb(); - set_d_rx_f1(adapter, MAX_D_FRAMES - 1); - set_d_rx_f2(adapter, MAX_D_FRAMES - 1); - mb(); - - if (fifo_state) { - adapter->fifo_en |= fifo_state; - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - } -} - -static void -hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs) -{ - struct hfcpci_adapter *adapter = bcs->adapter; - int nr = bcs->channel; - u8 fifo_state; - - DBG(DBG_B_RECV, ""); - - fifo_state = adapter->fifo_en & - (nr ? HFCPCI_FIFOEN_B2RX : HFCPCI_FIFOEN_B1RX); - - if (fifo_state) { // enabled - adapter->fifo_en &= ~fifo_state; - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - } - - bcs->last_fcnt = 0; - - set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); - set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); - mb(); - set_b_rx_f1(bcs, MAX_B_FRAMES - 1); - set_b_rx_f2(bcs, MAX_B_FRAMES - 1); - mb(); - - if (fifo_state) { - adapter->fifo_en |= fifo_state; - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - } -} - -// XXX clear d_tx_fifo? - -static void -hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs) -{ - struct hfcpci_adapter *adapter = bcs->adapter; - int nr = bcs->channel; - u8 fifo_state; - - fifo_state = adapter->fifo_en & - (nr ? HFCPCI_FIFOEN_B2TX : HFCPCI_FIFOEN_B1TX); - - if (fifo_state) { // enabled - adapter->fifo_en &= ~fifo_state; - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - } - - bcs->last_fcnt = 0; - - set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); - set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); - mb(); - set_b_rx_f1(bcs, MAX_B_FRAMES - 1); - set_b_rx_f2(bcs, MAX_B_FRAMES - 1); - mb(); - - if (fifo_state) { - adapter->fifo_en |= fifo_state; - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - } -} - -// ---------------------------------------------------------------------- -// receive messages from upper layers - -static void -hfcpci_d_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct hfcpci_adapter *adapter = ifc->priv; - struct sk_buff *skb = arg; - - DBG(DBG_PR, "pr %#x", pr); - - switch (pr) { - case PH_ACTIVATE | REQUEST: - FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL); - break; - case PH_DEACTIVATE | REQUEST: - FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL); - break; - case PH_DATA | REQUEST: - DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len); - DBG_SKB(DBG_D_XMIT, skb); - if (adapter->l1m.state != ST_L1_F7) { - DBG(DBG_WARN, "L1 wrong state %d", adapter->l1m.state); - break; - } - if (adapter->tx_skb) - BUG(); - - adapter->tx_skb = skb; - hfcpci_fill_d_fifo(adapter); - break; - } -} - -static void -hfcpci_b_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct hfcpci_bcs *bcs = ifc->priv; - struct sk_buff *skb = arg; - int mode; - - DBG(DBG_PR, "pr %#x", pr); - - switch (pr) { - case PH_DATA | REQUEST: - if (bcs->tx_skb) - BUG(); - - bcs->tx_skb = skb; - DBG_SKB(DBG_B_XMIT, skb); - hfcpci_fill_b_fifo(bcs); - break; - case PH_ACTIVATE | REQUEST: - mode = (int) arg; - DBG(DBG_PR,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); - hfcpci_b_mode(bcs, mode); - B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); - break; - case PH_DEACTIVATE | REQUEST: - DBG(DBG_PR,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); - hfcpci_b_mode(bcs, L1_MODE_NULL); - B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); - break; - } -} - -// ---------------------------------------------------------------------- -// receive IRQ - -static inline void -hfcpci_d_recv_irq(struct hfcpci_adapter *adapter) -{ - struct sk_buff *skb; - char *fifo_adr = adapter->fifo + 0x4000; - char *p; - int cnt, fcnt; - int loop = 5; - u8 f1, f2; - u16 z1, z2; - - while (loop-- > 0) { - f1 = get_d_rx_f1(adapter); - f2 = get_d_rx_f2(adapter); - DBG(DBG_D_RECV, "f1 %#x f2 %#x", f1, f2); - - fcnt = f1 - f2; - if (fcnt < 0) - fcnt += 16; - - if (!fcnt) - return; - - if (fcnt < adapter->last_fcnt) - /* overrun */ - hfcpci_clear_d_rx_fifo(adapter); - // XXX init last_fcnt - - z1 = get_d_rx_z1(adapter, f2); - z2 = get_d_rx_z2(adapter, f2); - DBG(DBG_D_RECV, "z1 %#x z2 %#x", z1, z2); - - cnt = z1 - z2; - if (cnt < 0) - cnt += D_FIFO_SIZE; - cnt++; - - if (cnt < 4) { - DBG(DBG_WARN, "frame too short"); - goto next; - } - if (fifo_adr[z1] != 0) { - DBG(DBG_WARN, "CRC error"); - goto next; - } - cnt -= 3; - skb = dev_alloc_skb(cnt); - if (!skb) { - DBG(DBG_WARN, "no mem"); - goto next; - } - p = skb_put(skb, cnt); - if (z2 + cnt <= D_FIFO_END) { - memcpy(p, fifo_adr + z2, cnt); - } else { - memcpy(p, fifo_adr + z2, D_FIFO_END - z2); - memcpy(p + (D_FIFO_END - z2), fifo_adr + D_FIFO_START, - cnt - (D_FIFO_END - z2)); - } - - DBG_SKB(DBG_D_RECV, skb); - D_L1L2(adapter, PH_DATA | INDICATION, skb); - - next: - if (++z1 >= D_FIFO_END) - z1 -= D_FIFO_START; - - f2 = (f2 + 1) & (MAX_D_FRAMES - 1); - mb(); - set_d_rx_z2(adapter, f2, z1); - mb(); - set_d_rx_f2(adapter, f2); - - adapter->last_fcnt = fcnt - 1; - } -} - -static inline void -hfcpci_b_recv_hdlc_irq(struct hfcpci_adapter *adapter, int nr) -{ - struct hfcpci_bcs *bcs = &adapter->bcs[nr]; - struct sk_buff *skb; - char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000); - char *p; - int cnt, fcnt; - int loop = 5; - u8 f1, f2; - u16 z1, z2; - - while (loop-- > 0) { - f1 = get_b_rx_f1(bcs); - f2 = get_b_rx_f2(bcs); - DBG(DBG_B_RECV, "f1 %d f2 %d", f1, f2); - - fcnt = f1 - f2; - if (fcnt < 0) - fcnt += 32; - - if (!fcnt) - return; - - if (fcnt < bcs->last_fcnt) - /* overrun */ - hfcpci_clear_b_rx_fifo(bcs); - // XXX init last_fcnt - - z1 = get_b_rx_z1(bcs, f2); - z2 = get_b_rx_z2(bcs, f2); - DBG(DBG_B_RECV, "z1 %d z2 %d", z1, z2); - - cnt = z1 - z2; - if (cnt < 0) - cnt += B_FIFO_SIZE; - cnt++; - - if (cnt < 4) { - DBG(DBG_WARN, "frame too short"); - goto next; - } - if (fifo_adr[z1] != 0) { - DBG(DBG_WARN, "CRC error"); - goto next; - } - cnt -= 3; - skb = dev_alloc_skb(cnt); - if (!skb) { - DBG(DBG_WARN, "no mem"); - goto next; - } - p = skb_put(skb, cnt); - if (z2 + cnt <= B_FIFO_END) { - memcpy(p, fifo_adr + z2, cnt); - } else { - memcpy(p, fifo_adr + z2, B_FIFO_END - z2); - memcpy(p + (B_FIFO_END - z2), fifo_adr + B_FIFO_START, - cnt - (B_FIFO_END - z2)); - } - - DBG_SKB(DBG_B_RECV, skb); - B_L1L2(bcs, PH_DATA | INDICATION, skb); - - next: - if (++z1 >= B_FIFO_END) - z1 -= B_FIFO_SIZE; - - f2 = (f2 + 1) & (MAX_B_FRAMES - 1); - mb(); - set_b_rx_z2(bcs, f2, z1); - mb(); - set_b_rx_f2(bcs, f2); - - bcs->last_fcnt = fcnt - 1; - } -} - -static inline void -hfcpci_b_recv_trans_irq(struct hfcpci_adapter *adapter, int nr) -{ - struct hfcpci_bcs *bcs = &adapter->bcs[nr]; - struct sk_buff *skb; - char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000); - char *p; - int cnt; - int loop = 5; - u8 f1, f2; - u16 z1, z2; - - f1 = get_b_rx_f1(bcs); - f2 = get_b_rx_f2(bcs); - - if (f1 != f2) - BUG(); - - while (loop-- > 0) { - z1 = get_b_rx_z1(bcs, f2); - z2 = get_b_rx_z2(bcs, f2); - - cnt = z1 - z2; - if (!cnt) - /* no data available */ - return; - - if (cnt < 0) - cnt += B_FIFO_SIZE; - - if (cnt > HFCPCI_BTRANS_THRESHOLD) - cnt = HFCPCI_BTRANS_THRESHOLD; - - skb = dev_alloc_skb(cnt); - if (!skb) { - DBG(DBG_WARN, "no mem"); - goto next; - } - - p = skb_put(skb, cnt); - if (z2 + cnt <= 0x2000) { - memcpy(p, fifo_adr + z2, cnt); - } else { - memcpy(p, fifo_adr + z2, 0x2000 - z2); - p += 0x2000 - z2; - memcpy(p, fifo_adr + 0x200, cnt - (0x2000 - z2)); - } - - DBG_SKB(DBG_B_RECV, skb); - B_L1L2(bcs, PH_DATA | INDICATION, skb); - - next: - z2 += cnt; - if (z2 >= 0x2000) - z2 -= B_FIFO_SIZE; - - mb(); - set_b_rx_z2(bcs, f2, z2); - // XXX always receive buffers of a given size - } -} - -static inline void -hfcpci_b_recv_irq(struct hfcpci_adapter *adapter, int nr) -{ - DBG(DBG_B_RECV, ""); - - switch (adapter->bcs[nr].mode) { - case L1_MODE_NULL: - DBG(DBG_WARN, "?"); - break; - - case L1_MODE_HDLC: - hfcpci_b_recv_hdlc_irq(adapter, nr); - break; - - case L1_MODE_TRANS: - hfcpci_b_recv_trans_irq(adapter, nr); - break; - } -} - -// ---------------------------------------------------------------------- -// transmit IRQ - -// XXX make xmit FIFO deeper than 1 - -static inline void -hfcpci_d_xmit_irq(struct hfcpci_adapter *adapter) -{ - struct sk_buff *skb; - - DBG(DBG_D_XMIT, ""); - - skb = adapter->tx_skb; - if (!skb) { - DBG(DBG_WARN, "?"); - return; - } - - adapter->tx_skb = NULL; - D_L1L2(adapter, PH_DATA | CONFIRM, (void *) skb->truesize); - dev_kfree_skb_irq(skb); -} - -static inline void -hfcpci_b_xmit_irq(struct hfcpci_adapter *adapter, int nr) -{ - struct hfcpci_bcs *bcs = &adapter->bcs[nr]; - struct sk_buff *skb; - - DBG(DBG_B_XMIT, ""); - - skb = bcs->tx_skb; - if (!skb) { - DBG(DBG_WARN, "?"); - return; - } - - bcs->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, skb); -} - -// ---------------------------------------------------------------------- -// Layer 1 state change IRQ - -static inline void -hfcpci_state_irq(struct hfcpci_adapter *adapter) -{ - u8 val; - - val = hfcpci_readb(adapter, HFCPCI_STATES); - DBG(DBG_L1M, "STATES %#x", val); - FsmEvent(&adapter->l1m, val & 0xf, NULL); -} - -// ---------------------------------------------------------------------- -// Timer IRQ - -static inline void -hfcpci_timer_irq(struct hfcpci_adapter *adapter) -{ - hfcpci_writeb(adapter, adapter->ctmt | HFCPCI_CLTIMER, HFCPCI_CTMT); -} - -// ---------------------------------------------------------------------- -// IRQ handler - -static irqreturn_t -hfcpci_irq(int intno, void *dev, struct pt_regs *regs) -{ - struct hfcpci_adapter *adapter = dev; - int loop = 15; - u8 val, stat; - - if (!(adapter->int_m2 & 0x08)) - return IRQ_NONE; /* not initialised */ // XX - - stat = hfcpci_readb(adapter, HFCPCI_STATUS); - if (!(stat & HFCPCI_ANYINT)) - return IRQ_NONE; - - spin_lock(&adapter->hw_lock); - while (loop-- > 0) { - val = hfcpci_readb(adapter, HFCPCI_INT_S1); - DBG(DBG_IRQ, "stat %02x s1 %02x", stat, val); - val &= adapter->int_m1; - - if (!val) - break; - - if (val & 0x08) - hfcpci_b_recv_irq(adapter, 0); - - if (val & 0x10) - hfcpci_b_recv_irq(adapter, 1); - - if (val & 0x01) - hfcpci_b_xmit_irq(adapter, 0); - - if (val & 0x02) - hfcpci_b_xmit_irq(adapter, 1); - - if (val & 0x20) - hfcpci_d_recv_irq(adapter); - - if (val & 0x04) - hfcpci_d_xmit_irq(adapter); - - if (val & 0x40) - hfcpci_state_irq(adapter); - - if (val & 0x80) - hfcpci_timer_irq(adapter); - } - spin_unlock(&adapter->hw_lock); - return IRQ_HANDLED; -} - -// ---------------------------------------------------------------------- -// reset hardware - -static void -hfcpci_reset(struct hfcpci_adapter *adapter) -{ - /* disable all interrupts */ - adapter->int_m1 = 0; - adapter->int_m2 = 0; - hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); - hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2); - - /* reset */ - hfcpci_writeb(adapter, HFCPCI_RESET, HFCPCI_CIRM); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30 * HZ) / 1000); - hfcpci_writeb(adapter, 0, HFCPCI_CIRM); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((20 * HZ) / 1000); - if (hfcpci_readb(adapter, HFCPCI_STATUS) & 2) // XX - printk(KERN_WARNING "HFC-PCI init bit busy\n"); -} - -// ---------------------------------------------------------------------- -// init hardware - -static void -hfcpci_hw_init(struct hfcpci_adapter *adapter) -{ - adapter->fifo_en = 0x30; /* only D fifos enabled */ // XX - hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); - - /* no echo connect , threshold */ - adapter->trm = HFCPCI_BTRANS_THRESMASK; - hfcpci_writeb(adapter, adapter->trm, HFCPCI_TRM); - - /* ST-Bit delay for TE-Mode */ - hfcpci_writeb(adapter, CLKDEL_TE, HFCPCI_CLKDEL); - - /* S/T Auto awake */ - adapter->sctrl_e = HFCPCI_AUTO_AWAKE; - hfcpci_writeb(adapter, adapter->sctrl_e, HFCPCI_SCTRL_E); - - /* no exchange */ - adapter->bswapped = 0; - /* we are in TE mode */ - adapter->nt_mode = 0; - - adapter->ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; - hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT); - - adapter->int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | - HFCPCI_INTS_L1STATE; - hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); - - /* clear already pending ints */ - hfcpci_readb(adapter, HFCPCI_INT_S1); - - adapter->l1m.state = 2; - hfcpci_writeb(adapter, HFCPCI_LOAD_STATE | 2, HFCPCI_STATES); // XX /* HFC ST 2 */ - udelay(10); - hfcpci_writeb(adapter, 2, HFCPCI_STATES); /* HFC ST 2 */ - - /* HFC Master Mode */ - adapter->mst_m = HFCPCI_MASTER; - hfcpci_writeb(adapter, adapter->mst_m, HFCPCI_MST_MODE); - - /* set tx_lo mode, error in datasheet ! */ - adapter->sctrl = 0x40; - hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL); - - adapter->sctrl_r = 0; - hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R); - - // XXX - /* Init GCI/IOM2 in master mode */ - /* Slots 0 and 1 are set for B-chan 1 and 2 */ - /* D- and monitor/CI channel are not enabled */ - /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ - /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continous 1s */ - /* The IOM slots are always enabled */ - adapter->conn = 0; /* set data flow directions */ - hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT); - hfcpci_writeb(adapter, 0x80, HFCPCI_B1_SSL); /* B1-Slot 0 STIO1 out enabled */ - hfcpci_writeb(adapter, 0x81, HFCPCI_B2_SSL); /* B2-Slot 1 STIO1 out enabled */ - hfcpci_writeb(adapter, 0x80, HFCPCI_B1_RSL); /* B1-Slot 0 STIO2 in enabled */ - hfcpci_writeb(adapter, 0x81, HFCPCI_B2_RSL); /* B2-Slot 1 STIO2 in enabled */ - - /* Finally enable IRQ output */ - adapter->int_m2 = HFCPCI_IRQ_ENABLE; - hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2); - - hfcpci_readb(adapter, HFCPCI_INT_S2); -} - -// ---------------------------------------------------------------------- -// probe / remove - -static struct hfcpci_adapter * __devinit -new_adapter(struct pci_dev *pdev) -{ - struct hfcpci_adapter *adapter; - struct hisax_b_if *b_if[2]; - int i; - - adapter = kmalloc(sizeof(struct hfcpci_adapter), GFP_KERNEL); - if (!adapter) - return NULL; - - memset(adapter, 0, sizeof(struct hfcpci_adapter)); - - adapter->d_if.owner = THIS_MODULE; - adapter->d_if.ifc.priv = adapter; - adapter->d_if.ifc.l2l1 = hfcpci_d_l2l1; - - for (i = 0; i < 2; i++) { - adapter->bcs[i].adapter = adapter; - adapter->bcs[i].channel = i; - adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; - adapter->bcs[i].b_if.ifc.l2l1 = hfcpci_b_l2l1; - } - - pci_set_drvdata(pdev, adapter); - - for (i = 0; i < 2; i++) - b_if[i] = &adapter->bcs[i].b_if; - - hisax_register(&adapter->d_if, b_if, "hfcpci", protocol); - - return adapter; -} - -static void delete_adapter(struct hfcpci_adapter *adapter) -{ - hisax_unregister(&adapter->d_if); - kfree(adapter); -} - -static int __devinit hfcpci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct hfcpci_adapter *adapter; - int retval; - - DBG(DBG_INFO, ""); - retval = -ENOMEM; - adapter = new_adapter(pdev); - if (!adapter) - goto err; - - retval = pci_enable_device(pdev); - if (retval) - goto err_free; - - adapter->irq = pdev->irq; - retval = request_irq(adapter->irq, hfcpci_irq, SA_SHIRQ, - "hfcpci", adapter); - if (retval) - goto err_free; - - retval = -EBUSY; - if (!request_mem_region(pci_resource_start(pdev, 1), 256, "hfcpci")) - goto err_free_irq; - - adapter->mmio = ioremap(pci_resource_start(pdev, 1), 256); // XX pci_io - if (!adapter->mmio) - goto err_release_region; - - /* Allocate 32K for FIFOs */ - if (pci_set_dma_mask(pdev, 0xffffffff)) - goto err_unmap; - - adapter->fifo = pci_alloc_consistent(pdev, 32768, &adapter->fifo_dma); - if (!adapter->fifo) - goto err_unmap; - - pci_write_config_dword(pdev, HFCPCI_MWBA, (u32) adapter->fifo_dma); - pci_set_master(pdev); - - adapter->l1m.fsm = &l1fsm; - adapter->l1m.state = ST_L1_F0; -#ifdef CONFIG_HISAX_DEBUG - adapter->l1m.debug = 1; -#else - adapter->l1m.debug = 0; -#endif - adapter->l1m.userdata = adapter; - adapter->l1m.printdebug = l1m_debug; - FsmInitTimer(&adapter->l1m, &adapter->timer); - - hfcpci_reset(adapter); - hfcpci_hw_init(adapter); - - printk(KERN_INFO "hisax_hfcpci: found adapter %s at %s\n", - (char *) ent->driver_data, pci_name(pdev)); - - return 0; - - err_unmap: - iounmap(adapter->mmio); - err_release_region: - release_mem_region(pci_resource_start(pdev, 1), 256); - err_free_irq: - free_irq(adapter->irq, adapter); - err_free: - delete_adapter(adapter); - err: - return retval; -} - -static void __devexit hfcpci_remove(struct pci_dev *pdev) -{ - struct hfcpci_adapter *adapter = pci_get_drvdata(pdev); - - hfcpci_reset(adapter); - -// del_timer(&cs->hw.hfcpci.timer); XX - - /* disable DMA */ - pci_disable_device(pdev); - pci_write_config_dword(pdev, HFCPCI_MWBA, 0); - pci_free_consistent(pdev, 32768, adapter->fifo, adapter->fifo_dma); - - iounmap(adapter->mmio); - release_mem_region(pci_resource_start(pdev, 1), 256); - free_irq(adapter->irq, adapter); - delete_adapter(adapter); -} - -static struct pci_driver hfcpci_driver = { - .name = "hfcpci", - .probe = hfcpci_probe, - .remove = __devexit_p(hfcpci_remove), - .id_table = hfcpci_ids, -}; - -static int __init hisax_hfcpci_init(void) -{ - int retval; - - printk(KERN_INFO "hisax_hfcpcipnp: HFC PCI ISDN driver v0.0.1\n"); - - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strState = strL1State; - l1fsm.strEvent = strL1Event; - retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); - if (retval) - goto err; - - retval = pci_module_init(&hfcpci_driver); - if (retval) - goto err_fsm; - - return 0; - - err_fsm: - FsmFree(&l1fsm); - err: - return retval; -} - -static void __exit hisax_hfcpci_exit(void) -{ - FsmFree(&l1fsm); - pci_unregister_driver(&hfcpci_driver); -} - -module_init(hisax_hfcpci_init); -module_exit(hisax_hfcpci_exit); diff -puN -L drivers/isdn/hisax/hisax_hfcpci.h drivers/isdn/hisax/hisax_hfcpci.h~i4l /dev/null --- 25/drivers/isdn/hisax/hisax_hfcpci.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,40 +0,0 @@ -#include "hisax_if.h" -#include "hisax_isac.h" -#include - -struct hfcpci_bcs { - struct hisax_b_if b_if; - struct hfcpci_adapter *adapter; - int mode; - int channel; - int last_fcnt; - - struct sk_buff *tx_skb; -}; - -struct hfcpci_adapter { - struct hisax_d_if d_if; - spinlock_t hw_lock; - unsigned int irq; - void *mmio; - u8 *fifo; - dma_addr_t fifo_dma; - - struct FsmInst l1m; - struct FsmTimer timer; - struct sk_buff *tx_skb; - int last_fcnt; - - u8 int_m1, int_m2; - u8 fifo_en; - u8 trm; - u8 sctrl, sctrl_r, sctrl_e; - u8 nt_mode; - u8 ctmt; - u8 mst_m; - u8 conn; - u8 bswapped; - - struct hfcpci_bcs bcs[2]; -}; - diff -puN -L drivers/isdn/hisax/hisax_hscx.c drivers/isdn/hisax/hisax_hscx.c~i4l /dev/null --- 25/drivers/isdn/hisax/hisax_hscx.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,420 +0,0 @@ -/* - * Driver for HSCX - * High-Level Serial Communcation Controller Extended - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski - * 2001 by Karsten Keil - * - * based upon Karsten Keil's original isac.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -/* TODO: - * comments in .h - */ - -#include -#include -#include -#include "hisax_hscx.h" - -// debugging cruft - -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 1; -MODULE_PARM(debug, "i"); - -static char *HSCXVer[] = -{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", - "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; -#endif - -MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); -MODULE_DESCRIPTION("HSCX driver"); - -#define DBG_WARN 0x0001 -#define DBG_IRQ 0x0002 -#define DBG_L1M 0x0004 -#define DBG_PR 0x0008 -#define DBG_RFIFO 0x0100 -#define DBG_RPACKET 0x0200 -#define DBG_XFIFO 0x1000 -#define DBG_XPACKET 0x2000 - -#define HSCX_ISTA 0x20 -#define HSCX_ISTA_EXB 0x01 -#define HSCX_ISTA_EXA 0x02 -#define HSCX_ISTA_ICA 0x04 -#define HSCX_ISTA_TIN 0x08 -#define HSCX_ISTA_XPR 0x10 -#define HSCX_ISTA_RSC 0x20 -#define HSCX_ISTA_RPF 0x40 -#define HSCX_ISTA_RME 0x80 - -#define HSCX_CMDR 0x21 -#define HSCX_CMDR_RMC 0x80 -#define HSCX_CMDR_RHR 0x40 -#define HSCX_CMDR_RNR 0x20 -#define HSCX_CMDR_STI 0x10 -#define HSCX_CMDR_XTF 0x08 -#define HSCX_CMDR_XIF 0x04 -#define HSCX_CMDR_XME 0x02 -#define HSCX_CMDR_XRES 0x01 - -#define HSCX_EXIR 0x24 -#define HSCX_EXIR_XDU 0x40 - -#define HSCX_RSTA 0x27 -#define HSCX_RSTA_VFR 0x80 -#define HSCX_RSTA_RDO 0x40 -#define HSCX_RSTA_CRC 0x20 -#define HSCX_RSTA_RAB 0x10 - -#define HSCX_CCR1 0x2f -#define HSCX_CCR2 0x2c -#define HSCX_TSAR 0x31 -#define HSCX_TSAX 0x30 -#define HSCX_XCCR 0x32 -#define HSCX_RCCR 0x33 -#define HSCX_MODE 0x22 - -#define HSCX_XAD1 0x24 -#define HSCX_XAD2 0x25 -#define HSCX_RAH2 0x27 -#define HSCX_TIMR 0x23 -#define HSCX_STAR 0x21 -#define HSCX_RBCL 0x25 -#define HSCX_XBCH 0x2d -#define HSCX_VSTR 0x2e -#define HSCX_RLCR 0x2e -#define HSCX_MASK 0x20 - -static inline void B_L1L2(struct hscx *hscx, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &hscx->b_if; - - DBG(0x10, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -static void hscx_version(struct hscx *hscx) -{ - int val; - - val = hscx->read_hscx(hscx, HSCX_VSTR) & 0xf; - DBG(1, "HSCX version (%x): %s", val, HSCXVer[val]); -} - -static void hscx_empty_fifo(struct hscx *hscx, int count) -{ - u8 *ptr; - - DBG(DBG_IRQ, "count %d", count); - - if ((hscx->rcvidx + count) >= HSCX_BUFMAX) { - DBG(DBG_WARN, "overrun %d", hscx->rcvidx + count); - hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC); - hscx->rcvidx = 0; - return; - } - ptr = hscx->rcvbuf + hscx->rcvidx; - hscx->rcvidx += count; - hscx->read_hscx_fifo(hscx, ptr, count); - hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC); - DBG_PACKET(DBG_RFIFO, ptr, count); -} - -static void hscx_fill_fifo(struct hscx *hscx) -{ - int count; - unsigned char cmd; - int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32; - unsigned char *ptr; - - if (!hscx->tx_skb) - BUG(); - - count = hscx->tx_skb->len; - if (count <= 0) - BUG(); - - DBG(DBG_IRQ, "count %d", count); - - if (count > fifo_size || hscx->mode == L1_MODE_TRANS) { - count = fifo_size; - cmd = 0x8; - } else { - cmd = 0xa; - } - - ptr = hscx->tx_skb->data; - skb_pull(hscx->tx_skb, count); - hscx->tx_cnt += count; - DBG_PACKET(DBG_XFIFO, ptr, count); - hscx->write_hscx_fifo(hscx, ptr, count); - hscx->write_hscx(hscx, HSCX_CMDR, cmd); -} - -static void hscx_retransmit(struct hscx *hscx) -{ - if (!hscx->tx_skb) { - DBG(DBG_WARN, "no skb"); - return; - } - skb_push(hscx->tx_skb, hscx->tx_cnt); - hscx->tx_cnt = 0; - hscx->write_hscx(hscx, HSCX_CMDR, 0x01); -} - -static inline void hscx_rme_interrupt(struct hscx *hscx) -{ - unsigned char val; - int count; - struct sk_buff *skb; - int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32; - - val = hscx->read_hscx(hscx, HSCX_RSTA); - if ((val & (HSCX_RSTA_VFR | HSCX_RSTA_RDO | HSCX_RSTA_CRC | HSCX_RSTA_RAB) ) - != (HSCX_RSTA_VFR | HSCX_RSTA_CRC)) { - DBG(DBG_WARN, "RSTA %#x, dropped", val); - hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC); - goto out; - } - - count = hscx->read_hscx(hscx, HSCX_RBCL) & (fifo_size-1); - DBG(DBG_IRQ, "RBCL %#x", count); - if (count == 0) - count = fifo_size; - - hscx_empty_fifo(hscx, count); - - count = hscx->rcvidx; - if (count < 1) { - DBG(DBG_WARN, "count %d < 1", count); - goto out; - } - - skb = alloc_skb(count, GFP_ATOMIC); - if (!skb) { - DBG(DBG_WARN, "no memory, dropping\n"); - goto out; - } - memcpy(skb_put(skb, count), hscx->rcvbuf, count); - DBG_SKB(DBG_RPACKET, skb); - B_L1L2(hscx, PH_DATA | INDICATION, skb); - out: - hscx->rcvidx = 0; -} - -static inline void hscx_xpr_interrupt(struct hscx *hscx) -{ - struct sk_buff *skb; - - skb = hscx->tx_skb; - if (!skb) - return; - - if (skb->len > 0) { - hscx_fill_fifo(hscx); - return; - } - hscx->tx_cnt = 0; - hscx->tx_skb = NULL; - B_L1L2(hscx, PH_DATA | CONFIRM, skb); -} - -static inline void hscx_exi_interrupt(struct hscx *hscx) -{ - unsigned char val; - - val = hscx->read_hscx(hscx, HSCX_EXIR); - DBG(2, "EXIR %#x", val); - - if (val & HSCX_EXIR_XDU) { - DBG(DBG_WARN, "HSCX XDU"); - if (hscx->mode == L1_MODE_TRANS) { - hscx_fill_fifo(hscx); - } else { - hscx_retransmit(hscx); - } - } -} - -static void hscx_reg_interrupt(struct hscx *hscx, unsigned char val) -{ - struct sk_buff *skb; - - if (val & HSCX_ISTA_XPR) { - DBG(DBG_IRQ, "XPR"); - hscx_xpr_interrupt(hscx); - } - if (val & HSCX_ISTA_RME) { - DBG(DBG_IRQ, "RME"); - hscx_rme_interrupt(hscx); - } - if (val & HSCX_ISTA_RPF) { - int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32; - - DBG(DBG_IRQ, "RPF"); - hscx_empty_fifo(hscx, fifo_size); - if (hscx->mode == L1_MODE_TRANS) { - skb = dev_alloc_skb(fifo_size); - if (!skb) { - DBG(DBG_WARN, "no memory, dropping\n"); - goto out; - } - memcpy(skb_put(skb, fifo_size), hscx->rcvbuf, fifo_size); - DBG_SKB(DBG_RPACKET, skb); - B_L1L2(hscx, PH_DATA | INDICATION, skb); - out: - hscx->rcvidx = 0; - } - } -} - -void hscx_irq(struct hscx *hscx_a) -{ - struct hscx *hscx_b = hscx_a + 1; - unsigned char val; - - val = hscx_b->read_hscx(hscx_b, HSCX_ISTA); - DBG(DBG_IRQ, "ISTA B %#x", val); - - if (val & HSCX_ISTA_EXB) { - DBG(DBG_IRQ, "EXI B"); - hscx_exi_interrupt(hscx_b); - } - if (val & HSCX_ISTA_EXA) { - DBG(DBG_IRQ, "EXI A"); - hscx_exi_interrupt(hscx_a); - } - if (val & 0xf8) { - hscx_reg_interrupt(hscx_b, val); - } - if (val & HSCX_ISTA_ICA) { - val = hscx_a->read_hscx(hscx_a, HSCX_ISTA); - DBG(DBG_IRQ, "ISTA A %#x", val); - hscx_reg_interrupt(hscx_a, val); - hscx_a->write_hscx(hscx_a, HSCX_MASK, 0xff); - hscx_a->write_hscx(hscx_a, HSCX_MASK, 0x00); - } - hscx_b->write_hscx(hscx_b, HSCX_MASK, 0xff); - hscx_b->write_hscx(hscx_b, HSCX_MASK, 0x00); -} - -static void modehscx(struct hscx *hscx, int mode) -{ - int bc = hscx->channel; - - DBG(0x40, "hscx %c mode %d --> %d", - 'A' + hscx->channel, hscx->mode, mode); - - hscx->mode = mode; - hscx->write_hscx(hscx, HSCX_XAD1, 0xFF); - hscx->write_hscx(hscx, HSCX_XAD2, 0xFF); - hscx->write_hscx(hscx, HSCX_RAH2, 0xFF); - hscx->write_hscx(hscx, HSCX_XBCH, 0x0); - hscx->write_hscx(hscx, HSCX_RLCR, 0x0); - hscx->write_hscx(hscx, HSCX_CCR1, - test_bit(HSCX_IPAC, &hscx->flags) ? 0x82 : 0x85); - hscx->write_hscx(hscx, HSCX_CCR2, 0x30); - hscx->write_hscx(hscx, HSCX_XCCR, 7); - hscx->write_hscx(hscx, HSCX_RCCR, 7); - - /* Switch IOM 1 SSI */ - if (test_bit(HSCX_IOM1, &hscx->flags)) - bc = 1; - - hscx->write_hscx(hscx, HSCX_TSAX, hscx->tsaxr); - hscx->write_hscx(hscx, HSCX_TSAR, hscx->tsaxr); - - switch (mode) { - case (L1_MODE_NULL): - hscx->write_hscx(hscx, HSCX_TSAX, 0x1f); - hscx->write_hscx(hscx, HSCX_TSAR, 0x1f); - hscx->write_hscx(hscx, HSCX_MODE, 0x84); - break; - case (L1_MODE_TRANS): - hscx->write_hscx(hscx, HSCX_MODE, 0xe4); - break; - case (L1_MODE_HDLC): - hscx->write_hscx(hscx, HSCX_CCR1, test_bit(HSCX_IPAC, &hscx->flags) ? 0x8a : 0x8d); - hscx->write_hscx(hscx, HSCX_MODE, 0x8c); - break; - } - if (mode) - hscx->write_hscx(hscx, HSCX_CMDR, 0x41); - - hscx->write_hscx(hscx, HSCX_ISTA, 0x00); -} - -void hscx_init(struct hscx *hscx) -{ - if (hscx->channel) - hscx->tsaxr = 0x03; - else - hscx->tsaxr = 0x2f; -} - -void hscx_setup(struct hscx *hscx) -{ - hscx_version(hscx); - hscx->mode = -1; - modehscx(hscx, L1_MODE_NULL); -} - -void hscx_b_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct hscx *hscx = ifc->priv; - struct sk_buff *skb = arg; - int mode; - - DBG(0x10, "pr %#x", pr); - - switch (pr) { - case PH_DATA | REQUEST: - if (hscx->tx_skb) - BUG(); - - hscx->tx_skb = skb; - DBG_SKB(1, skb); - hscx_fill_fifo(hscx); - break; - case PH_ACTIVATE | REQUEST: - mode = (int) arg; - DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", hscx->channel + 1, mode); - modehscx(hscx, mode); - B_L1L2(hscx, PH_ACTIVATE | INDICATION, NULL); - break; - case PH_DEACTIVATE | REQUEST: - DBG(4,"B%d,PH_DEACTIVATE_REQUEST", hscx->channel + 1); - modehscx(hscx, L1_MODE_NULL); - B_L1L2(hscx, PH_DEACTIVATE | INDICATION, NULL); - break; - } -} - -static int __init hisax_hscx_init(void) -{ - printk(KERN_INFO "hisax_hscx: HSCX ISDN driver v0.1.0\n"); - return 0; -} - -static void __exit hisax_hscx_exit(void) -{ -} - -EXPORT_SYMBOL(hscx_init); -EXPORT_SYMBOL(hscx_b_l2l1); - -EXPORT_SYMBOL(hscx_setup); -EXPORT_SYMBOL(hscx_irq); - -module_init(hisax_hscx_init); -module_exit(hisax_hscx_exit); diff -puN -L drivers/isdn/hisax/hisax_hscx.h drivers/isdn/hisax/hisax_hscx.h~i4l /dev/null --- 25/drivers/isdn/hisax/hisax_hscx.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,37 +0,0 @@ -#ifndef __HISAX_HSCX_H__ -#define __HISAX_HSCX_H__ - -#include -#include "fsm.h" -#include "hisax_if.h" - -#define HSCX_BUFMAX 4096 - -#define HSCX_IOM1 0 -#define HSCX_IPAC 1 - -struct hscx { - void *priv; - u_long flags; - struct hisax_b_if b_if; - int mode; - int channel; - u8 tsaxr; - struct sk_buff *tx_skb; - int tx_cnt; - u8 rcvbuf[HSCX_BUFMAX]; - int rcvidx; - - u8 (*read_hscx) (struct hscx *, u8); - void (*write_hscx) (struct hscx *, u8, u8); - void (*read_hscx_fifo) (struct hscx *, u8 *, int); - void (*write_hscx_fifo)(struct hscx *, u8 *, int); -}; - -void hscx_init(struct hscx *hscx); -void hscx_b_l2l1(struct hisax_if *hisax_b_if, int pr, void *arg); - -void hscx_setup(struct hscx *hscx); -void hscx_irq(struct hscx *hscx); - -#endif diff -puN drivers/isdn/hisax/hisax_isac.c~i4l drivers/isdn/hisax/hisax_isac.c --- 25/drivers/isdn/hisax/hisax_isac.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hisax_isac.c 2004-02-09 22:19:20.000000000 -0800 @@ -450,7 +450,7 @@ static void isac_empty_fifo(struct isac { // this also works for isacsx, since // CMDR(D) register works the same - u8 *ptr; + u_char *ptr; DBG(DBG_IRQ, "count %d", count); @@ -474,7 +474,7 @@ static void isac_fill_fifo(struct isac * int count; unsigned char cmd; - u8 *ptr; + u_char *ptr; if (!isac->tx_skb) BUG(); @@ -770,7 +770,7 @@ void isac_init(struct isac *isac) FsmInitTimer(&isac->l1m, &isac->timer); } -void hisax_isac_setup(struct isac *isac) +void isac_setup(struct isac *isac) { int val, eval; @@ -890,7 +890,7 @@ EXPORT_SYMBOL(isac_d_l2l1); EXPORT_SYMBOL(isacsx_setup); EXPORT_SYMBOL(isacsx_irq); -EXPORT_SYMBOL(hisax_isac_setup); +EXPORT_SYMBOL(isac_setup); EXPORT_SYMBOL(isac_irq); module_init(hisax_isac_init); diff -puN drivers/isdn/hisax/hisax_isac.h~i4l drivers/isdn/hisax/hisax_isac.h --- 25/drivers/isdn/hisax/hisax_isac.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hisax_isac.h 2004-02-09 22:19:20.000000000 -0800 @@ -17,26 +17,26 @@ struct isac { struct hisax_d_if hisax_d_if; struct FsmInst l1m; struct FsmTimer timer; - u8 mocr; - u8 adf2; + u_char mocr; + u_char adf2; int type; - u8 rcvbuf[MAX_DFRAME_LEN_L1]; + u_char rcvbuf[MAX_DFRAME_LEN_L1]; int rcvidx; struct sk_buff *tx_skb; int tx_cnt; - u8 (*read_isac) (struct isac *, u8); - void (*write_isac) (struct isac *, u8, u8); - void (*read_isac_fifo) (struct isac *, u8 *, int); - void (*write_isac_fifo)(struct isac *, u8 *, int); + u_char (*read_isac) (struct isac *, u_char); + void (*write_isac) (struct isac *, u_char, u_char); + void (*read_isac_fifo) (struct isac *, u_char *, int); + void (*write_isac_fifo)(struct isac *, u_char *, int); }; void isac_init(struct isac *isac); void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg); -void hisax_isac_setup(struct isac *isac); +void isac_setup(struct isac *isac); void isac_irq(struct isac *isac); void isacsx_setup(struct isac *isac); diff -puN drivers/isdn/hisax/hscx.c~i4l drivers/isdn/hisax/hscx.c --- 25/drivers/isdn/hisax/hscx.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hscx.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hscx.c,v 1.21.6.3 2001/09/23 22:24:48 kai Exp $ +/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $ * * HSCX specific routines * @@ -17,133 +17,136 @@ #include "isdnl1.h" #include -static char *HSCXVer[] __initdata = +static char *HSCXVer[] = {"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; -static inline u8 -hscx_read(struct BCState *bcs, u8 addr) -{ - struct IsdnCardState *cs = bcs->cs; - - return cs->bc_hw_ops->read_reg(cs, bcs->unit, addr); -} - -static inline void -hscx_write(struct BCState *bcs, u8 addr, u8 val) -{ - struct IsdnCardState *cs = bcs->cs; - - cs->bc_hw_ops->write_reg(cs, bcs->unit, addr, val); -} - -static inline void -hscx_write_fifo(struct BCState *bcs, u8 *p, int len) -{ - struct IsdnCardState *cs = bcs->cs; - - cs->bc_hw_ops->write_fifo(cs, bcs->unit, p, len); -} - -static int +int HscxVersion(struct IsdnCardState *cs, char *s) { int verA, verB; - verA = cs->bc_hw_ops->read_reg(cs, 0, HSCX_VSTR) & 0xf; - verB = cs->bc_hw_ops->read_reg(cs, 1, HSCX_VSTR) & 0xf; + verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf; + verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf; printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s, HSCXVer[verA], HSCXVer[verB]); if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) - return 1; + return (1); else - return 0; + return (0); } void modehscx(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->unit; + int hscx = bcs->hw.hscx.hscx; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hscx %c mode %d ichan %d", 'A' + hscx, mode, bc); bcs->mode = mode; bcs->channel = bc; - hscx_write(bcs, HSCX_XAD1, 0xFF); - hscx_write(bcs, HSCX_XAD2, 0xFF); - hscx_write(bcs, HSCX_RAH2, 0xFF); - hscx_write(bcs, HSCX_XBCH, 0x0); - hscx_write(bcs, HSCX_RLCR, 0x0); - hscx_write(bcs, HSCX_CCR1, + cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF); + cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF); + cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF); + cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0); + cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0); + cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85); - hscx_write(bcs, HSCX_CCR2, 0x30); - hscx_write(bcs, HSCX_XCCR, 7); - hscx_write(bcs, HSCX_RCCR, 7); + cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30); + cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7); + cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7); /* Switch IOM 1 SSI */ if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0)) bc = 1 - bc; if (bc == 0) { - hscx_write(bcs, HSCX_TSAX, + cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); - hscx_write(bcs, HSCX_TSAR, + cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); } else { - hscx_write(bcs, HSCX_TSAX, bcs->hw.hscx.tsaxr1); - hscx_write(bcs, HSCX_TSAR, bcs->hw.hscx.tsaxr1); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1); } switch (mode) { - case L1_MODE_NULL: - hscx_write(bcs, HSCX_TSAX, 0x1f); - hscx_write(bcs, HSCX_TSAR, 0x1f); - hscx_write(bcs, HSCX_MODE, 0x84); - break; - case L1_MODE_TRANS: - hscx_write(bcs, HSCX_MODE, 0xe4); - break; - case L1_MODE_HDLC: - hscx_write(bcs, HSCX_CCR1, - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d); - hscx_write(bcs, HSCX_MODE, 0x8c); - break; + case (L1_MODE_NULL): + cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f); + cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84); + break; + case (L1_MODE_TRANS): + cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4); + break; + case (L1_MODE_HDLC): + cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, + test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d); + cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c); + break; } if (mode) - hscx_write(bcs, HSCX_CMDR, 0x41); - - hscx_write(bcs, HSCX_ISTA, 0x00); + cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41); + cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00); } void hscx_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; + u_long flags; struct sk_buff *skb = arg; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->hw.hscx.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); + } else { + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->hw.hscx.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - modehscx(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + modehscx(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - modehscx(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + modehscx(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -152,17 +155,50 @@ void close_hscxstate(struct BCState *bcs) { modehscx(bcs, 0, bcs->channel); - bc_close(bcs); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } } int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs) { - bc_open(bcs); + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hscx.rcvbuf\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; - bcs->rcvidx = 0; + bcs->hw.hscx.rcvidx = 0; bcs->tx_cnt = 0; return (0); } @@ -174,80 +210,71 @@ setstack_hscx(struct PStack *st, struct if (open_hscxstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = hscx_l2l1; + st->l2.l2l1 = hscx_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); return (0); } -static void hscx_fill_fifo(struct BCState *bcs); - -static struct bc_l1_ops hscx_l1_ops = { - .fill_fifo = hscx_fill_fifo, - .open = setstack_hscx, - .close = close_hscxstate, -}; - -void __init -inithscx(struct IsdnCardState *cs) +void +clear_pending_hscx_ints(struct IsdnCardState *cs) { int val, eval; - - cs->bc_l1_ops = &hscx_l1_ops; - cs->bcs[0].unit = 0; - cs->bcs[1].unit = 1; - cs->bcs[0].hw.hscx.tsaxr0 = 0x2f; - cs->bcs[0].hw.hscx.tsaxr1 = 3; - cs->bcs[1].hw.hscx.tsaxr0 = 0x2f; - cs->bcs[1].hw.hscx.tsaxr1 = 3; - val = hscx_read(&cs->bcs[1], HSCX_ISTA); + val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA); debugl1(cs, "HSCX B ISTA %x", val); if (val & 0x01) { - eval = hscx_read(&cs->bcs[1], HSCX_EXIR); + eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); debugl1(cs, "HSCX B EXIR %x", eval); } if (val & 0x02) { - eval = hscx_read(&cs->bcs[0], HSCX_EXIR); + eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); debugl1(cs, "HSCX A EXIR %x", eval); } - val = hscx_read(&cs->bcs[0], HSCX_ISTA); + val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA); debugl1(cs, "HSCX A ISTA %x", val); - val = hscx_read(&cs->bcs[1], HSCX_STAR); + val = cs->BC_Read_Reg(cs, 1, HSCX_STAR); debugl1(cs, "HSCX B STAR %x", val); - val = hscx_read(&cs->bcs[0], HSCX_STAR); + val = cs->BC_Read_Reg(cs, 0, HSCX_STAR); debugl1(cs, "HSCX A STAR %x", val); /* disable all IRQ */ - hscx_write(&cs->bcs[0], HSCX_MASK, 0xFF); - hscx_write(&cs->bcs[1], HSCX_MASK, 0xFF); - - modehscx(&cs->bcs[0], 0, 0); - modehscx(&cs->bcs[1], 0, 0); - - /* Reenable all IRQ */ - hscx_write(&cs->bcs[0], HSCX_MASK, 0x0); - hscx_write(&cs->bcs[1], HSCX_MASK, 0x0); + cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF); + cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF); } void -inithscxisac(struct IsdnCardState *cs) +inithscx(struct IsdnCardState *cs) { - initisac(cs); - inithscx(cs); + cs->bcs[0].BC_SetStack = setstack_hscx; + cs->bcs[1].BC_SetStack = setstack_hscx; + cs->bcs[0].BC_Close = close_hscxstate; + cs->bcs[1].BC_Close = close_hscxstate; + cs->bcs[0].hw.hscx.hscx = 0; + cs->bcs[1].hw.hscx.hscx = 1; + cs->bcs[0].hw.hscx.tsaxr0 = 0x2f; + cs->bcs[0].hw.hscx.tsaxr1 = 3; + cs->bcs[1].hw.hscx.tsaxr0 = 0x2f; + cs->bcs[1].hw.hscx.tsaxr1 = 3; + modehscx(cs->bcs, 0, 0); + modehscx(cs->bcs + 1, 0, 0); } -int -hscxisac_setup(struct IsdnCardState *cs, struct dc_hw_ops *isac_ops, - struct bc_hw_ops *hscx_ops) +void +inithscxisac(struct IsdnCardState *cs, int part) { - isac_setup(cs, isac_ops); - cs->bc_hw_ops = hscx_ops; - if (HscxVersion(cs, "HiSax:")) { - printk(KERN_WARNING "HiSax: invalid HSCX version\n"); - return -ENODEV; + if (part & 1) { + clear_pending_isac_ints(cs); + clear_pending_hscx_ints(cs); + initisac(cs); + inithscx(cs); + } + if (part & 2) { + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); + cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); } - return 0; } - -#include "hscx_irq.c" diff -puN drivers/isdn/hisax/hscx.h~i4l drivers/isdn/hisax/hscx.h --- 25/drivers/isdn/hisax/hscx.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hscx.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hscx.h,v 1.6.6.2 2001/09/23 22:24:48 kai Exp $ +/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $ * * HSCX specific defines * @@ -10,8 +10,6 @@ * */ -#include - /* All Registers original Siemens Spec */ #define HSCX_ISTA 0x20 @@ -36,10 +34,8 @@ #define HSCX_RLCR 0x2e #define HSCX_MASK 0x20 +extern int HscxVersion(struct IsdnCardState *cs, char *s); extern void modehscx(struct BCState *bcs, int mode, int bc); -extern void inithscxisac(struct IsdnCardState *cs); -extern void hscx_int_main(struct IsdnCardState *cs, u8 val); -extern irqreturn_t hscxisac_irq(int intno, void *dev_id, struct pt_regs *regs); -extern int hscxisac_setup(struct IsdnCardState *cs, - struct dc_hw_ops *isac_ops, - struct bc_hw_ops *hscx_ops); +extern void clear_pending_hscx_ints(struct IsdnCardState *cs); +extern void inithscx(struct IsdnCardState *cs); +extern void inithscxisac(struct IsdnCardState *cs, int part); diff -puN drivers/isdn/hisax/hscx_irq.c~i4l drivers/isdn/hisax/hscx_irq.c --- 25/drivers/isdn/hisax/hscx_irq.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/hscx_irq.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hscx_irq.c,v 1.16.6.2 2001/09/23 22:24:48 kai Exp $ +/* $Id: hscx_irq.c,v 1.18.2.2 2004/01/12 22:52:26 keil Exp $ * * low level b-channel stuff for Siemens HSCX * @@ -12,12 +12,13 @@ * */ -static void -waitforCEC(struct BCState *bcs) + +static inline void +waitforCEC(struct IsdnCardState *cs, int hscx) { int to = 50; - while ((hscx_read(bcs, HSCX_STAR) & 0x04) && to) { + while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { udelay(1); to--; } @@ -26,12 +27,12 @@ waitforCEC(struct BCState *bcs) } -static void -waitforXFW(struct BCState *bcs) +static inline void +waitforXFW(struct IsdnCardState *cs, int hscx) { int to = 50; - while ((!(hscx_read(bcs, HSCX_STAR) & 0x44) == 0x40) && to) { + while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { udelay(1); to--; } @@ -40,18 +41,42 @@ waitforXFW(struct BCState *bcs) } static inline void -WriteHSCXCMDR(struct BCState *bcs, u8 data) +WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) { - waitforCEC(bcs); - hscx_write(bcs, HSCX_CMDR, data); + waitforCEC(cs, hscx); + WRITEHSCX(cs, hscx, HSCX_CMDR, data); } + static void hscx_empty_fifo(struct BCState *bcs, int count) { - recv_empty_fifo_b(bcs, count); - WriteHSCXCMDR(bcs, 0x80); + u_char *ptr; + struct IsdnCardState *cs = bcs->cs; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hscx_empty_fifo"); + + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hscx_empty_fifo: incoming packet too large"); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); + bcs->hw.hscx.rcvidx = 0; + return; + } + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static void @@ -60,22 +85,46 @@ hscx_fill_fifo(struct BCState *bcs) struct IsdnCardState *cs = bcs->cs; int more, count; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; - u8 *p; + u_char *ptr; - p = xmit_fill_fifo_b(bcs, fifo_size, &count, &more); - if (!p) + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hscx_fill_fifo"); + + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) return; - waitforXFW(bcs); - hscx_write_fifo(bcs, p, count); - WriteHSCXCMDR(bcs, more ? 0x8 : 0xa); + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > fifo_size) { + more = !0; + count = fifo_size; + } else + count = bcs->tx_skb->len; + + waitforXFW(cs, bcs->hw.hscx.hscx); + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static inline void -hscx_interrupt(struct IsdnCardState *cs, u8 val, u8 hscx) +hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) { - u8 r; + u_char r; struct BCState *bcs = cs->bcs + hscx; + struct sk_buff *skb; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; int count; @@ -83,7 +132,7 @@ hscx_interrupt(struct IsdnCardState *cs, return; if (val & 0x80) { /* RME */ - r = hscx_read(bcs, HSCX_RSTA); + r = READHSCX(cs, hscx, HSCX_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) { if (cs->debug & L1_DEB_WARN) @@ -107,46 +156,97 @@ hscx_interrupt(struct IsdnCardState *cs, bcs->err_crc++; #endif } - WriteHSCXCMDR(bcs, 0x80); - bcs->rcvidx = 0; + WriteHSCXCMDR(cs, hscx, 0x80); } else { - count = hscx_read(bcs, HSCX_RBCL) & (fifo_size-1); + count = READHSCX(cs, hscx, HSCX_RBCL) & ( + test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); if (count == 0) count = fifo_size; - hscx_empty_fifo(bcs, count); - recv_rme_b(bcs); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HSCX: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); } if (val & 0x40) { /* RPF */ hscx_empty_fifo(bcs, fifo_size); - recv_rpf_b(bcs); + if (bcs->mode == L1_MODE_TRANS) { + /* receive audio data */ + if (!(skb = dev_alloc_skb(fifo_size))) + printk(KERN_WARNING "HiSax: receive out of memory\n"); + else { + memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); + } } - if (val & 0x10) { - xmit_xpr_b(bcs); + if (val & 0x10) { /* XPR */ + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + hscx_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + hscx_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } } } -static void -reset_xmit(struct BCState *bcs) +static inline void +hscx_int_main(struct IsdnCardState *cs, u_char val) { - WriteHSCXCMDR(bcs, 0x01); -} -void -hscx_int_main(struct IsdnCardState *cs, u8 val) -{ - u8 exval; + u_char exval; struct BCState *bcs; if (val & 0x01) { bcs = cs->bcs + 1; - exval = hscx_read(bcs, HSCX_EXIR); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B EXIR %x", exval); + exval = READHSCX(cs, 1, HSCX_EXIR); if (exval & 0x40) { - xmit_xdu_b(bcs, reset_xmit); - } + if (bcs->mode == 1) + hscx_fill_fifo(bcs); + else { +#ifdef ERROR_STATISTIC + bcs->err_tx++; +#endif + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX B EXIR %x Lost TX", exval); + } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B EXIR %x", exval); } if (val & 0xf8) { if (cs->debug & L1_DEB_HSCX) @@ -155,72 +255,33 @@ hscx_int_main(struct IsdnCardState *cs, } if (val & 0x02) { bcs = cs->bcs; - exval = hscx_read(bcs, HSCX_EXIR); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A EXIR %x", exval); + exval = READHSCX(cs, 0, HSCX_EXIR); if (exval & 0x40) { - xmit_xdu_b(bcs, reset_xmit); - } + if (bcs->mode == L1_MODE_TRANS) + hscx_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ +#ifdef ERROR_STATISTIC + bcs->err_tx++; +#endif + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX A EXIR %x Lost TX", exval); + } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A EXIR %x", exval); } if (val & 0x04) { - bcs = cs->bcs; - exval = hscx_read(bcs, HSCX_ISTA); + exval = READHSCX(cs, 0, HSCX_ISTA); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX A interrupt %x", exval); hscx_interrupt(cs, exval, 0); } } - -/* ====================================================================== */ - -static inline u8 -isac_read(struct IsdnCardState *cs, u8 addr) -{ - return cs->dc_hw_ops->read_reg(cs, addr); -} - -static inline void -isac_write(struct IsdnCardState *cs, u8 addr, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, addr, val); -} - -irqreturn_t -hscxisac_irq(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u8 val; - int count = 0; - - spin_lock(&cs->lock); - val = hscx_read(&cs->bcs[1], HSCX_ISTA); - Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = isac_read(cs, ISAC_ISTA); - Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = hscx_read(&cs->bcs[1], HSCX_ISTA); - if (val && count < 5) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = isac_read(cs, ISAC_ISTA); - if (val && count < 5) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - hscx_write(&cs->bcs[0], HSCX_MASK, 0xFF); - hscx_write(&cs->bcs[1], HSCX_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0x0); - hscx_write(&cs->bcs[0], HSCX_MASK, 0x0); - hscx_write(&cs->bcs[1], HSCX_MASK, 0x0); - spin_unlock(&cs->lock); - return IRQ_HANDLED; -} - diff -puN drivers/isdn/hisax/icc.c~i4l drivers/isdn/hisax/icc.c --- 25/drivers/isdn/hisax/icc.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/icc.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: icc.c,v 1.5.6.4 2001/09/23 22:24:48 kai Exp $ +/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $ * * ICC specific routines * @@ -24,39 +24,15 @@ #define DBUSY_TIMER_VALUE 80 #define ARCOFI_USE 0 -static inline u8 -icc_read_reg(struct IsdnCardState *cs, u8 addr) -{ - return cs->dc_hw_ops->read_reg(cs, addr); -} - -static inline void -icc_write_reg(struct IsdnCardState *cs, u8 addr, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, addr, val); -} - -static inline void -icc_read_fifo(struct IsdnCardState *cs, u8 *p, int len) -{ - return cs->dc_hw_ops->read_fifo(cs, p, len); -} - -static inline void -icc_write_fifo(struct IsdnCardState *cs, u8 *p, int len) -{ - return cs->dc_hw_ops->write_fifo(cs, p, len); -} - static char *ICCVer[] __initdata = {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; -static void +void ICCVersion(struct IsdnCardState *cs, char *s) { int val; - val = icc_read_reg(cs, ICC_RBCH); + val = cs->readisac(cs, ICC_RBCH); printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); } @@ -65,7 +41,7 @@ ph_command(struct IsdnCardState *cs, uns { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_command %x", command); - icc_write_reg(cs, ICC_CIX0, (command << 2) | 3); + cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); } @@ -101,9 +77,8 @@ icc_new_ph(struct IsdnCardState *cs) } static void -icc_bh(void *data) +icc_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; struct PStack *stptr; if (!cs) @@ -113,7 +88,7 @@ icc_bh(void *data) debugl1(cs, "D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - L1L2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -136,22 +111,58 @@ icc_bh(void *data) void icc_empty_fifo(struct IsdnCardState *cs, int count) { - recv_empty_fifo_d(cs, count); - icc_write_reg(cs, ICC_CMDR, 0x80); + u_char *ptr; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeisac(cs, ICC_CMDR, 0x80); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, 0x80); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } static void icc_fill_fifo(struct IsdnCardState *cs) { int count, more; - unsigned char *p; + u_char *ptr; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_fill_fifo"); - p = xmit_fill_fifo_d(cs, 32, &count, &more); - if (!p) + if (!cs->tx_skb) return; - icc_write_fifo(cs, p, count); - icc_write_reg(cs, ICC_CMDR, more ? 0x8 : 0xa); + count = cs->tx_skb->len; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { debugl1(cs, "icc_fill_fifo dbusytimer running"); del_timer(&cs->dbusytimer); @@ -159,18 +170,26 @@ icc_fill_fifo(struct IsdnCardState *cs) init_timer(&cs->dbusytimer); cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); add_timer(&cs->dbusytimer); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } void -icc_interrupt(struct IsdnCardState *cs, u8 val) +icc_interrupt(struct IsdnCardState *cs, u_char val) { - u8 exval, v1; + u_char exval, v1; + struct sk_buff *skb; unsigned int count; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ICC interrupt %x", val); if (val & 0x80) { /* RME */ - exval = icc_read_reg(cs, ICC_RSTA); + exval = cs->readisac(cs, ICC_RSTA); if ((exval & 0x70) != 0x20) { if (exval & 0x40) { if (cs->debug & L1_DEB_WARN) @@ -186,15 +205,24 @@ icc_interrupt(struct IsdnCardState *cs, cs->err_crc++; #endif } - icc_write_reg(cs, ICC_CMDR, 0x80); - cs->rcvidx = 0; + cs->writeisac(cs, ICC_CMDR, 0x80); } else { - count = icc_read_reg(cs, ICC_RBCL) & 0x1f; + count = cs->readisac(cs, ICC_RBCL) & 0x1f; if (count == 0) count = 32; icc_empty_fifo(cs, count); - recv_rme_d(cs); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } } + cs->rcvidx = 0; + schedule_event(cs, D_RCVBUFREADY); } if (val & 0x40) { /* RPF */ icc_empty_fifo(cs, 32); @@ -205,20 +233,39 @@ icc_interrupt(struct IsdnCardState *cs, debugl1(cs, "ICC RSC interrupt"); } if (val & 0x10) { /* XPR */ - xmit_xpr_d(cs); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + icc_fill_fifo(cs); + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else + schedule_event(cs, D_XMTBUFREADY); } + afterXPR: if (val & 0x04) { /* CISQ */ - exval = icc_read_reg(cs, ICC_CIR0); + exval = cs->readisac(cs, ICC_CIR0); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ICC CIR0 %02X", exval ); if (exval & 2) { cs->dc.icc.ph_state = (exval >> 2) & 0xf; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); } if (exval & 1) { - exval = icc_read_reg(cs, ICC_CIR1); + exval = cs->readisac(cs, ICC_CIR1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ICC CIR1 %02X", exval ); } @@ -229,7 +276,7 @@ icc_interrupt(struct IsdnCardState *cs, debugl1(cs, "ICC SIN interrupt"); } if (val & 0x01) { /* EXI */ - exval = icc_read_reg(cs, ICC_EXIR); + exval = cs->readisac(cs, ICC_EXIR); if (cs->debug & L1_DEB_WARN) debugl1(cs, "ICC EXIR %02x", exval); if (exval & 0x80) { /* XMR */ @@ -237,10 +284,26 @@ icc_interrupt(struct IsdnCardState *cs, printk(KERN_WARNING "HiSax: ICC XMR\n"); } if (exval & 0x40) { /* XDU */ - xmit_xdu_d(cs, NULL); + debugl1(cs, "ICC XDU"); + printk(KERN_WARNING "HiSax: ICC XDU\n"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); + debugl1(cs, "ICC XDU no skb"); + } } if (exval & 0x04) { /* MOS */ - v1 = icc_read_reg(cs, ICC_MOSR); + v1 = cs->readisac(cs, ICC_MOSR); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ICC MOSR %02x", v1); #if ARCOFI_USE @@ -251,7 +314,7 @@ icc_interrupt(struct IsdnCardState *cs, debugl1(cs, "ICC MON RX out of memory!"); cs->dc.icc.mocr &= 0xf0; cs->dc.icc.mocr |= 0x0a; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); goto afterMONR0; } else cs->dc.icc.mon_rxp = 0; @@ -259,18 +322,18 @@ icc_interrupt(struct IsdnCardState *cs, if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { cs->dc.icc.mocr &= 0xf0; cs->dc.icc.mocr |= 0x0a; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); cs->dc.icc.mon_rxp = 0; if (cs->debug & L1_DEB_WARN) debugl1(cs, "ICC MON RX overflow!"); goto afterMONR0; } - cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = icc_read_reg(cs, ICC_MOR0); + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); if (cs->dc.icc.mon_rxp == 1) { cs->dc.icc.mocr |= 0x04; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); } } afterMONR0: @@ -281,7 +344,7 @@ icc_interrupt(struct IsdnCardState *cs, debugl1(cs, "ICC MON RX out of memory!"); cs->dc.icc.mocr &= 0x0f; cs->dc.icc.mocr |= 0xa0; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); goto afterMONR1; } else cs->dc.icc.mon_rxp = 0; @@ -289,51 +352,51 @@ icc_interrupt(struct IsdnCardState *cs, if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { cs->dc.icc.mocr &= 0x0f; cs->dc.icc.mocr |= 0xa0; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); cs->dc.icc.mon_rxp = 0; if (cs->debug & L1_DEB_WARN) debugl1(cs, "ICC MON RX overflow!"); goto afterMONR1; } - cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = icc_read_reg(cs, ICC_MOR1); + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); cs->dc.icc.mocr |= 0x40; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); } afterMONR1: if (v1 & 0x04) { cs->dc.icc.mocr &= 0xf0; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); cs->dc.icc.mocr |= 0x0a; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); - sched_d_event(cs, D_RX_MON0); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + schedule_event(cs, D_RX_MON0); } if (v1 & 0x40) { cs->dc.icc.mocr &= 0x0f; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); cs->dc.icc.mocr |= 0xa0; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); - sched_d_event(cs, D_RX_MON1); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + schedule_event(cs, D_RX_MON1); } if (v1 & 0x02) { if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && !(v1 & 0x08))) { cs->dc.icc.mocr &= 0xf0; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); cs->dc.icc.mocr |= 0x0a; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) - sched_d_event(cs, D_TX_MON0); + schedule_event(cs, D_TX_MON0); goto AfterMOX0; } if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { - sched_d_event(cs, D_TX_MON0); + schedule_event(cs, D_TX_MON0); goto AfterMOX0; } - icc_write_reg(cs, ICC_MOX0, + cs->writeisac(cs, ICC_MOX0, cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); @@ -344,19 +407,19 @@ icc_interrupt(struct IsdnCardState *cs, (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && !(v1 & 0x80))) { cs->dc.icc.mocr &= 0x0f; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); cs->dc.icc.mocr |= 0xa0; - icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) - sched_d_event(cs, D_TX_MON1); + schedule_event(cs, D_TX_MON1); goto AfterMOX1; } if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { - sched_d_event(cs, D_TX_MON1); + schedule_event(cs, D_TX_MON1); goto AfterMOX1; } - icc_write_reg(cs, ICC_MOX1, + cs->writeisac(cs, ICC_MOX1, cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); @@ -372,35 +435,91 @@ ICC_l1hw(struct PStack *st, int pr, void { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; + u_long flags; int val; switch (pr) { case (PH_DATA |REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + icc_fill_fifo(cs); + } + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL |INDICATION): - xmit_pull_ind_d(cs, skb); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + icc_fill_fifo(cs); + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): + spin_lock_irqsave(&cs->lock, flags); if ((cs->dc.icc.ph_state == ICC_IND_EI1) || (cs->dc.icc.ph_state == ICC_IND_DR)) ph_command(cs, ICC_CMD_DI); else ph_command(cs, ICC_CMD_RES); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_ENABLE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, ICC_CMD_DI); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO1 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, ICC_CMD_AR); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, ICC_CMD_AI); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): + spin_lock_irqsave(&cs->lock, flags); val = 0; if (1 & (long) arg) val |= 0x0c; @@ -409,20 +528,21 @@ ICC_l1hw(struct PStack *st, int pr, void if (test_bit(HW_IOM1, &cs->HW_Flags)) { /* IOM 1 Mode */ if (!val) { - icc_write_reg(cs, ICC_SPCR, 0xa); - icc_write_reg(cs, ICC_ADF1, 0x2); + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); } else { - icc_write_reg(cs, ICC_SPCR, val); - icc_write_reg(cs, ICC_ADF1, 0xa); + cs->writeisac(cs, ICC_SPCR, val); + cs->writeisac(cs, ICC_ADF1, 0xa); } } else { /* IOM 2 Mode */ - icc_write_reg(cs, ICC_SPCR, val); + cs->writeisac(cs, ICC_SPCR, val); if (val) - icc_write_reg(cs, ICC_ADF1, 0x8); + cs->writeisac(cs, ICC_ADF1, 0x8); else - icc_write_reg(cs, ICC_ADF1, 0x0); + cs->writeisac(cs, ICC_ADF1, 0x0); } + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_DEACTIVATE | RESPONSE): skb_queue_purge(&cs->rq); @@ -434,7 +554,7 @@ ICC_l1hw(struct PStack *st, int pr, void if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); break; default: if (cs->debug & L1_DEB_WARN) @@ -443,11 +563,10 @@ ICC_l1hw(struct PStack *st, int pr, void } } -static int +void setstack_icc(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = ICC_l1hw; - return 0; } void @@ -469,8 +588,8 @@ dbusy_timer_handler(struct IsdnCardState int rbch, star; if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = icc_read_reg(cs, ICC_RBCH); - star = icc_read_reg(cs, ICC_STAR); + rbch = cs->readisac(cs, ICC_RBCH); + star = cs->readisac(cs, ICC_STAR); if (cs->debug) debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", rbch, star); @@ -478,7 +597,7 @@ dbusy_timer_handler(struct IsdnCardState test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); stptr = cs->stlist; while (stptr != NULL) { - L1L2(stptr, PH_PAUSE | INDICATION, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } else { @@ -492,77 +611,75 @@ dbusy_timer_handler(struct IsdnCardState printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); debugl1(cs, "D-Channel Busy no skb"); } - icc_write_reg(cs, ICC_CMDR, 0x01); /* Transmitter reset */ - cs->card_ops->irq_func(cs->irq, cs, NULL); /* FIXME? */ + cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); } } } -static struct dc_l1_ops icc_l1_ops = { - .fill_fifo = icc_fill_fifo, - .open = setstack_icc, - .close = DC_Close_icc, - .bh_func = icc_bh, - .dbusy_func = dbusy_timer_handler, -}; - void __init initicc(struct IsdnCardState *cs) { - int val, eval; - - dc_l1_init(cs, &icc_l1_ops); + cs->setstack_d = setstack_icc; + cs->DC_Close = DC_Close_icc; cs->dc.icc.mon_tx = NULL; cs->dc.icc.mon_rx = NULL; + cs->writeisac(cs, ICC_MASK, 0xff); + cs->dc.icc.mocr = 0xaa; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + cs->writeisac(cs, ICC_ADF2, 0x0); + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xc9); + } else { + /* IOM 2 Mode */ + if (!cs->dc.icc.adf2) + cs->dc.icc.adf2 = 0x80; + cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); + cs->writeisac(cs, ICC_SQXR, 0xa0); + cs->writeisac(cs, ICC_SPCR, 0x20); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xca); + cs->writeisac(cs, ICC_TIMR, 0x00); + cs->writeisac(cs, ICC_ADF1, 0x20); + } + ph_command(cs, ICC_CMD_RES); + cs->writeisac(cs, ICC_MASK, 0x0); + ph_command(cs, ICC_CMD_DI); +} + +void __init +clear_pending_icc_ints(struct IsdnCardState *cs) +{ + int val, eval; - val = icc_read_reg(cs, ICC_STAR); + val = cs->readisac(cs, ICC_STAR); debugl1(cs, "ICC STAR %x", val); - val = icc_read_reg(cs, ICC_MODE); + val = cs->readisac(cs, ICC_MODE); debugl1(cs, "ICC MODE %x", val); - val = icc_read_reg(cs, ICC_ADF2); + val = cs->readisac(cs, ICC_ADF2); debugl1(cs, "ICC ADF2 %x", val); - val = icc_read_reg(cs, ICC_ISTA); + val = cs->readisac(cs, ICC_ISTA); debugl1(cs, "ICC ISTA %x", val); if (val & 0x01) { - eval = icc_read_reg(cs, ICC_EXIR); + eval = cs->readisac(cs, ICC_EXIR); debugl1(cs, "ICC EXIR %x", eval); } - val = icc_read_reg(cs, ICC_CIR0); + val = cs->readisac(cs, ICC_CIR0); debugl1(cs, "ICC CIR0 %x", val); cs->dc.icc.ph_state = (val >> 2) & 0xf; - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); /* Disable all IRQ */ - icc_write_reg(cs, ICC_MASK, 0xFF); - - cs->dc.icc.mocr = 0xaa; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - icc_write_reg(cs, ICC_ADF2, 0x0); - icc_write_reg(cs, ICC_SPCR, 0xa); - icc_write_reg(cs, ICC_ADF1, 0x2); - icc_write_reg(cs, ICC_STCR, 0x70); - icc_write_reg(cs, ICC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!cs->dc.icc.adf2) - cs->dc.icc.adf2 = 0x80; - icc_write_reg(cs, ICC_ADF2, cs->dc.icc.adf2); - icc_write_reg(cs, ICC_SQXR, 0xa0); - icc_write_reg(cs, ICC_SPCR, 0x20); - icc_write_reg(cs, ICC_STCR, 0x70); - icc_write_reg(cs, ICC_MODE, 0xca); - icc_write_reg(cs, ICC_TIMR, 0x00); - icc_write_reg(cs, ICC_ADF1, 0x20); - } - ph_command(cs, ICC_CMD_RES); - icc_write_reg(cs, ICC_MASK, 0x0); - ph_command(cs, ICC_CMD_DI); + cs->writeisac(cs, ICC_MASK, 0xFF); } -int -icc_setup(struct IsdnCardState *cs, struct dc_hw_ops *icc_ops) +void __devinit +setup_icc(struct IsdnCardState *cs) { - cs->dc_hw_ops = icc_ops; - ICCVersion(cs, "HiSax:"); - return 0; + INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs); + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); } diff -puN drivers/isdn/hisax/icc.h~i4l drivers/isdn/hisax/icc.h --- 25/drivers/isdn/hisax/icc.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/icc.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: icc.h,v 1.2.6.3 2001/09/23 22:24:48 kai Exp $ +/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $ * * ICC specific routines * @@ -65,6 +65,8 @@ #define ICC_IND_AIL 0xE #define ICC_IND_DC 0xF -extern int icc_setup(struct IsdnCardState *cs, struct dc_hw_ops *icc_ops); +extern void ICCVersion(struct IsdnCardState *cs, char *s); extern void initicc(struct IsdnCardState *cs); -extern void icc_interrupt(struct IsdnCardState *cs, u8 val); +extern void icc_interrupt(struct IsdnCardState *cs, u_char val); +extern void clear_pending_icc_ints(struct IsdnCardState *cs); +extern void setup_icc(struct IsdnCardState *); diff -puN -L drivers/isdn/hisax/ipac.c drivers/isdn/hisax/ipac.c~i4l /dev/null --- 25/drivers/isdn/hisax/ipac.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,107 +0,0 @@ -#include "hisax.h" -#include "isdnl1.h" -#include "ipac.h" -#include "hscx.h" -#include "isac.h" - -static inline u8 -ipac_dc_read(struct IsdnCardState *cs, u8 addr) -{ - return cs->dc_hw_ops->read_reg(cs, addr); -} - -static inline void -ipac_dc_write(struct IsdnCardState *cs, u8 addr, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, addr, val); -} - -static inline u8 -ipac_bc_read(struct IsdnCardState *cs, int hscx, u8 addr) -{ - return cs->bc_hw_ops->read_reg(cs, hscx, addr); -} - -static inline void -ipac_bc_write(struct IsdnCardState *cs, int hscx, u8 addr, u8 val) -{ - cs->bc_hw_ops->write_reg(cs, hscx, addr, val); -} - -static inline u8 -ipac_read(struct IsdnCardState *cs, u8 offset) -{ - return ipac_dc_read(cs, offset - 0x80); -} - -static inline void -ipac_write(struct IsdnCardState *cs, u8 offset, u8 value) -{ - ipac_dc_write(cs, offset - 0x80, value); -} - -void -ipac_init(struct IsdnCardState *cs) -{ - set_bit(HW_IPAC, &cs->HW_Flags); - inithscxisac(cs); -} - -irqreturn_t -ipac_irq(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u8 ista, val, icnt = 5; - - spin_lock(&cs->lock); - ista = ipac_read(cs, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = ipac_bc_read(cs, 1, HSCX_ISTA); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = ipac_dc_read(cs, ISAC_ISTA) & 0xfe; - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = ipac_read(cs, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "IRQ LOOP\n"); - - ipac_write(cs, IPAC_MASK, 0xFF); - ipac_write(cs, IPAC_MASK, 0xC0); - spin_unlock(&cs->lock); - return IRQ_HANDLED; -} - -int -ipac_setup(struct IsdnCardState *cs, struct dc_hw_ops *ipac_dc_ops, - struct bc_hw_ops *ipac_bc_ops) -{ - u8 val; - - cs->dc_hw_ops = ipac_dc_ops; - cs->bc_hw_ops = ipac_bc_ops; - val = ipac_read(cs, IPAC_ID); - printk(KERN_INFO "HiSax: IPAC version %#x\n", val); - return 0; -} diff -puN drivers/isdn/hisax/ipac.h~i4l drivers/isdn/hisax/ipac.h --- 25/drivers/isdn/hisax/ipac.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/ipac.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: ipac.h,v 1.5.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $ * * IPAC specific defines * @@ -10,8 +10,6 @@ * */ -#include - /* All Registers original Siemens Spec */ #define IPAC_CONF 0xC0 @@ -29,76 +27,3 @@ #define IPAC_PCFG 0xCA #define IPAC_SCFG 0xCB #define IPAC_TIMR2 0xCC - -void ipac_init(struct IsdnCardState *cs); -irqreturn_t ipac_irq(int intno, void *dev_id, struct pt_regs *regs); -int ipac_setup(struct IsdnCardState *cs, struct dc_hw_ops *ipac_dc_ops, - struct bc_hw_ops *ipac_bc_ops); - -/* Macro to build the needed D- and B-Channel access routines given - * access functions for the IPAC */ - -#define BUILD_IPAC_OPS(ipac) \ - \ -static u8 \ -ipac ## _dc_read(struct IsdnCardState *cs, u8 offset) \ -{ \ - return ipac ## _read(cs, offset+0x80); \ -} \ - \ -static void \ -ipac ## _dc_write(struct IsdnCardState *cs, u8 offset, u8 value) \ -{ \ - ipac ## _write(cs, offset+0x80, value); \ -} \ - \ -static void \ -ipac ## _dc_read_fifo(struct IsdnCardState *cs, u8 * data, int size) \ -{ \ - ipac ## _readfifo(cs, 0x80, data, size); \ -} \ - \ -static void \ -ipac ## _dc_write_fifo(struct IsdnCardState *cs, u8 * data, int size) \ -{ \ - ipac ## _writefifo(cs, 0x80, data, size); \ -} \ - \ -static struct dc_hw_ops ipac ## _dc_ops = { \ - .read_reg = ipac ## _dc_read, \ - .write_reg = ipac ## _dc_write, \ - .read_fifo = ipac ## _dc_read_fifo, \ - .write_fifo = ipac ## _dc_write_fifo, \ -}; \ - \ -static u8 \ -ipac ## _bc_read(struct IsdnCardState *cs, int hscx, u8 offset) \ -{ \ - return ipac ## _read(cs, offset + (hscx ? 0x40 : 0)); \ -} \ - \ -static void \ -ipac ## _bc_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) \ -{ \ - ipac ## _write(cs, offset + (hscx ? 0x40 : 0), value); \ -} \ - \ -static void \ -ipac ## _bc_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) \ -{ \ - ipac ## _readfifo(cs, hscx ? 0x40 : 0, data, size); \ -} \ - \ -static void \ -ipac ## _bc_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)\ -{ \ - ipac ## _writefifo(cs, hscx ? 0x40 : 0, data, size); \ -} \ - \ -static struct bc_hw_ops ipac ## _bc_ops = { \ - .read_reg = ipac ## _bc_read, \ - .write_reg = ipac ## _bc_write, \ - .read_fifo = ipac ## _bc_read_fifo, \ - .write_fifo = ipac ## _bc_write_fifo, \ -} - diff -puN drivers/isdn/hisax/ipacx.c~i4l drivers/isdn/hisax/ipacx.c --- 25/drivers/isdn/hisax/ipacx.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/ipacx.c 2004-02-09 22:19:20.000000000 -0800 @@ -12,7 +12,6 @@ #include #include #include -#include #include "hisax_if.h" #include "hisax.h" #include "isdnl1.h" @@ -24,6 +23,7 @@ #define B_FIFO_SIZE 64 #define D_FIFO_SIZE 32 + // ipacx interrupt mask values #define _MASK_IMASK 0x2E // global mask #define _MASKB_IMASK 0x0B @@ -37,13 +37,16 @@ static inline void cic_int(struct IsdnCa static void dch_l2l1(struct PStack *st, int pr, void *arg); static void dbusy_timer_handler(struct IsdnCardState *cs); static void ipacx_new_ph(struct IsdnCardState *cs); -static void dch_bh(void *data); +static void dch_bh(struct IsdnCardState *cs); static void dch_empty_fifo(struct IsdnCardState *cs, int count); static void dch_fill_fifo(struct IsdnCardState *cs); static inline void dch_int(struct IsdnCardState *cs); +static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs); +static void __devinit dch_init(struct IsdnCardState *cs); static void bch_l2l1(struct PStack *st, int pr, void *arg); -static void ipacx_bc_empty_fifo(struct BCState *bcs, int count); -static void bch_int(struct IsdnCardState *cs, u8 hscx); +static void bch_empty_fifo(struct BCState *bcs, int count); +static void bch_fill_fifo(struct BCState *bcs); +static void bch_int(struct IsdnCardState *cs, u_char hscx); static void bch_mode(struct BCState *bcs, int mode, int bc); static void bch_close_state(struct BCState *bcs); static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs); @@ -51,45 +54,6 @@ static int bch_setstack(struct PStack *s static void __devinit bch_init(struct IsdnCardState *cs, int hscx); static void __init clear_pending_ints(struct IsdnCardState *cs); -static inline u8 -ipacx_bc_read_reg(struct BCState *bcs, u8 addr) -{ - struct IsdnCardState *cs = bcs->cs; - - return cs->bc_hw_ops->read_reg(cs, bcs->unit, addr); -} - -static inline void -ipacx_bc_write_reg(struct BCState *bcs, u8 addr, u8 val) -{ - struct IsdnCardState *cs = bcs->cs; - - cs->bc_hw_ops->write_reg(cs, bcs->unit, addr, val); -} - -static inline u8 -ipacx_read_reg(struct IsdnCardState *cs, u8 addr) -{ - return cs->dc_hw_ops->read_reg(cs, addr); -} - -static inline void -ipacx_write_reg(struct IsdnCardState *cs, u8 addr, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, addr, val); -} - -static inline void -ipacx_read_fifo(struct IsdnCardState *cs, u8 *p, int len) -{ - return cs->dc_hw_ops->read_fifo(cs, p, len); -} - -static inline void -ipacx_write_fifo(struct IsdnCardState *cs, u8 *p, int len) -{ - return cs->dc_hw_ops->write_fifo(cs, p, len); -} //---------------------------------------------------------- // Issue Layer 1 command to chip //---------------------------------------------------------- @@ -99,7 +63,10 @@ ph_command(struct IsdnCardState *cs, uns if (cs->debug &L1_DEB_ISAC) debugl1(cs, "ph_command (%#x) in (%#x)", command, cs->dc.isac.ph_state); - ipacx_write_reg(cs, IPACX_CIX0, (command << 4) | 0x0E); +//################################### +// printk(KERN_INFO "ph_command (%#x)\n", command); +//################################### + cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E); } //---------------------------------------------------------- @@ -108,12 +75,15 @@ ph_command(struct IsdnCardState *cs, uns static inline void cic_int(struct IsdnCardState *cs) { - u8 event; + u_char event; - event = ipacx_read_reg(cs, IPACX_CIR0) >> 4; + event = cs->readisac(cs, IPACX_CIR0) >> 4; if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event); - cs->dc.isac.ph_state = event; - sched_d_event(cs, D_L1STATECHANGE); +//######################################### +// printk(KERN_INFO "cic_int(%x)\n", event); +//######################################### + cs->dc.isac.ph_state = event; + schedule_event(cs, D_L1STATECHANGE); } //========================================================== @@ -128,21 +98,63 @@ dch_l2l1(struct PStack *st, int pr, void { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - u8 cda1_cr, cda2_cr; + u_char cda1_cr, cda2_cr; switch (pr) { case (PH_DATA |REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug &DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); + if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG + if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG + if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + dch_fill_fifo(cs); + } break; + case (PH_PULL |INDICATION): - xmit_pull_ind_d(cs, skb); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG + if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + dch_fill_fifo(cs); break; + case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG + if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (HW_RESET | REQUEST): case (HW_ENABLE | REQUEST): - ph_command(cs, IPACX_CMD_TIM); + if ((cs->dc.isac.ph_state == IPACX_IND_RES) || + (cs->dc.isac.ph_state == IPACX_IND_DR) || + (cs->dc.isac.ph_state == IPACX_IND_DC)) + ph_command(cs, IPACX_CMD_TIM); + else + ph_command(cs, IPACX_CMD_RES); break; case (HW_INFO3 | REQUEST): @@ -150,21 +162,21 @@ dch_l2l1(struct PStack *st, int pr, void break; case (HW_TESTLOOP | REQUEST): - ipacx_write_reg(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 - ipacx_write_reg(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 - cda1_cr = ipacx_read_reg(cs, IPACX_CDA1_CR); - cda2_cr = ipacx_read_reg(cs, IPACX_CDA2_CR); + cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 + cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 + cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); + cda2_cr = cs->readisac(cs, IPACX_CDA2_CR); if ((long)arg &1) { // loop B1 - ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr |0x0a); + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); } else { // B1 off - ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); } if ((long)arg &2) { // loop B2 - ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr |0x14); + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); } else { // B2 off - ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr &~0x14); + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); } break; @@ -194,14 +206,14 @@ dbusy_timer_handler(struct IsdnCardState int rbchd, stard; if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbchd = ipacx_read_reg(cs, IPACX_RBCHD); - stard = ipacx_read_reg(cs, IPACX_STARD); + rbchd = cs->readisac(cs, IPACX_RBCHD); + stard = cs->readisac(cs, IPACX_STARD); if (cs->debug) debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard); if (!(stard &0x40)) { // D-Channel Busy set_bit(FLG_L1_DBUSY, &cs->HW_Flags); for (st = cs->stlist; st; st = st->next) { - st->l2.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on + st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on } } else { // seems we lost an interrupt; reset transceiver */ @@ -214,7 +226,7 @@ dbusy_timer_handler(struct IsdnCardState printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); debugl1(cs, "D-Channel Busy no skb"); } - ipacx_write_reg(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR + cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR } } } @@ -268,9 +280,8 @@ ipacx_new_ph(struct IsdnCardState *cs) // bottom half handler for D channel //---------------------------------------------------------- static void -dch_bh(void *data) +dch_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; struct PStack *st; if (!cs) return; @@ -278,7 +289,7 @@ dch_bh(void *data) if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); for (st = cs->stlist; st; st = st->next) { - st->l2.l1l2(st, PH_PAUSE | CONFIRM, NULL); + st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); } } @@ -301,8 +312,33 @@ dch_bh(void *data) static void dch_empty_fifo(struct IsdnCardState *cs, int count) { - recv_empty_fifo_d(cs, count); - ipacx_write_reg(cs, IPACX_CMDRD, 0x80); // RMC + u_char *ptr; + + if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO)) + debugl1(cs, "dch_empty_fifo()"); + + // message too large, remove + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_empty_fifo() incoming message too large"); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + cs->rcvidx = 0; + return; + } + + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + + if (cs->debug &L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "dch_empty_fifo() cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } //---------------------------------------------------------- @@ -311,21 +347,28 @@ dch_empty_fifo(struct IsdnCardState *cs, static void dch_fill_fifo(struct IsdnCardState *cs) { - int count, more; - unsigned char cmd, *p; + int count; + u_char cmd, *ptr; - p = xmit_fill_fifo_d(cs, 32, &count, &more); - if (!p) - return; + if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO)) + debugl1(cs, "dch_fill_fifo()"); + + if (!cs->tx_skb) return; + count = cs->tx_skb->len; + if (count <= 0) return; - if (more) { + if (count > D_FIFO_SIZE) { + count = D_FIFO_SIZE; cmd = 0x08; // XTF } else { cmd = 0x0A; // XTF | XME } - ipacx_write_fifo(cs, p, count); - ipacx_write_reg(cs, IPACX_CMDRD, cmd); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, IPACX_CMDRD, cmd); // set timeout for transmission contol if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { @@ -335,6 +378,14 @@ dch_fill_fifo(struct IsdnCardState *cs) init_timer(&cs->dbusytimer); cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); add_timer(&cs->dbusytimer); + + if (cs->debug &L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "dch_fill_fifo() cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } //---------------------------------------------------------- @@ -343,35 +394,46 @@ dch_fill_fifo(struct IsdnCardState *cs) static inline void dch_int(struct IsdnCardState *cs) { - u8 istad, rstad; + struct sk_buff *skb; + u_char istad, rstad; int count; - istad = ipacx_read_reg(cs, IPACX_ISTAD); + istad = cs->readisac(cs, IPACX_ISTAD); +//############################################## +// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad); +//############################################## if (istad &0x80) { // RME - rstad = ipacx_read_reg(cs, IPACX_RSTAD); + rstad = cs->readisac(cs, IPACX_RSTAD); if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) if (!(rstad &0x80)) if (cs->debug &L1_DEB_WARN) - debugl1(cs, "dch_int(): invalid frame"); + debugl1(cs, "dch_int(): invalid frame"); if ((rstad &0x40)) if (cs->debug &L1_DEB_WARN) - debugl1(cs, "dch_int(): RDO"); + debugl1(cs, "dch_int(): RDO"); if (!(rstad &0x20)) if (cs->debug &L1_DEB_WARN) - debugl1(cs, "dch_int(): CRC error"); - ipacx_write_reg(cs, IPACX_CMDRD, 0x80); // RMC - cs->rcvidx = 0; + debugl1(cs, "dch_int(): CRC error"); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC } else { // received frame ok - count = ipacx_read_reg(cs, IPACX_RBCLD); - // FIXME this looks flaky - if (count) count--; // RSTAB is last byte + count = cs->readisac(cs, IPACX_RBCLD); + if (count) count--; // RSTAB is last byte count &= D_FIFO_SIZE-1; - if (count == 0) - count = D_FIFO_SIZE; + if (count == 0) count = D_FIFO_SIZE; dch_empty_fifo(cs, count); - recv_rme_d(cs); - } + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + } + cs->rcvidx = 0; + schedule_event(cs, D_RCVBUFREADY); } if (istad &0x40) { // RPF @@ -380,34 +442,56 @@ dch_int(struct IsdnCardState *cs) if (istad &0x20) { // RFO if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO"); - ipacx_write_reg(cs, IPACX_CMDRD, 0x40); //RRES + cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES } - if (istad &0x10) { // XPR - xmit_xpr_d(cs); - } + if (istad &0x10) { // XPR + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + dch_fill_fifo(cs); + goto afterXPR; + } + else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_skb = NULL; + cs->tx_cnt = 0; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + dch_fill_fifo(cs); + } + else { + schedule_event(cs, D_XMTBUFREADY); + } + } + afterXPR: if (istad &0x0C) { // XDU or XMR - xmit_xdu_d(cs, NULL); - } + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU"); + if (cs->tx_skb) { + skb_push(cs->tx_skb, cs->tx_cnt); // retransmit + cs->tx_cnt = 0; + dch_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); + debugl1(cs, "ISAC XDU no skb"); + } + } } //---------------------------------------------------------- //---------------------------------------------------------- -static int +static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = dch_l2l1; - return 0; } -static struct dc_l1_ops ipacx_dc_l1_ops = { - .fill_fifo = dch_fill_fifo, - .open = dch_setstack, - .bh_func = dch_bh, - .dbusy_func = dbusy_timer_handler, -}; - //---------------------------------------------------------- //---------------------------------------------------------- static void __devinit @@ -415,12 +499,16 @@ dch_init(struct IsdnCardState *cs) { printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n"); - dc_l1_init(cs, &ipacx_dc_l1_ops); + cs->setstack_d = dch_setstack; + + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); - ipacx_write_reg(cs, IPACX_TR_CONF0, 0x00); // clear LDD - ipacx_write_reg(cs, IPACX_TR_CONF2, 0x00); // enable transmitter - ipacx_write_reg(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go - ipacx_write_reg(cs, IPACX_MON_CR, 0x00); // disable monitor channel + cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD + cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter + cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go + cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel } @@ -434,31 +522,59 @@ dch_init(struct IsdnCardState *cs) static void bch_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->hw.hscx.count = 0; + bch_fill_fifo(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n"); + } else { + set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->hw.hscx.count = 0; + bch_fill_fifo(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + set_bit(BC_FLG_ACTIV, &bcs->Flag); + bch_mode(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - bch_mode(st->l1.bcs, 0, st->l1.bc); - st->l2.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + clear_bit(BC_FLG_ACTIV, &bcs->Flag); + clear_bit(BC_FLG_BUSY, &bcs->Flag); + bch_mode(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -467,94 +583,201 @@ bch_l2l1(struct PStack *st, int pr, void // Read B channel fifo to receive buffer //---------------------------------------------------------- static void -ipacx_bc_empty_fifo(struct BCState *bcs, int count) +bch_empty_fifo(struct BCState *bcs, int count) { - recv_empty_fifo_b(bcs, count); - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x80); // RMC + u_char *ptr, hscx; + struct IsdnCardState *cs; + int cnt; + + cs = bcs->cs; + hscx = bcs->hw.hscx.hscx; + if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO)) + debugl1(cs, "bch_empty_fifo()"); + + // message too large, remove + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_empty_fifo() incoming packet too large"); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + bcs->hw.hscx.rcvidx = 0; + return; + } + + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + cnt = count; + while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + + if (cs->debug &L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } //---------------------------------------------------------- // Fill buffer to transmit FIFO //---------------------------------------------------------- static void -ipacx_bc_fill_fifo(struct BCState *bcs) +bch_fill_fifo(struct BCState *bcs) { - int more, count; - unsigned char *p; - - p = xmit_fill_fifo_b(bcs, B_FIFO_SIZE, &count, &more); - if (!p) - return; - - while (count--) - ipacx_bc_write_reg(bcs, IPACX_XFIFOB, *p++); - - ipacx_bc_write_reg(bcs, IPACX_CMDRB, (more ? 0x08 : 0x0a)); + struct IsdnCardState *cs; + int more, count, cnt; + u_char *ptr, *p, hscx; + + cs = bcs->cs; + if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO)) + debugl1(cs, "bch_fill_fifo()"); + + if (!bcs->tx_skb) return; + if (bcs->tx_skb->len <= 0) return; + + hscx = bcs->hw.hscx.hscx; + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > B_FIFO_SIZE) { + more = 1; + count = B_FIFO_SIZE; + } else { + count = bcs->tx_skb->len; + } + cnt = count; + + p = ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a)); + + if (cs->debug &L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } //---------------------------------------------------------- // B channel interrupt handler //---------------------------------------------------------- - -static void -reset_xmit(struct BCState *bcs) -{ - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x01); // XRES -} - static void -bch_int(struct IsdnCardState *cs, u8 hscx) +bch_int(struct IsdnCardState *cs, u_char hscx) { - u8 istab; + u_char istab; struct BCState *bcs; + struct sk_buff *skb; int count; - u8 rstab; + u_char rstab; bcs = cs->bcs + hscx; - istab = ipacx_bc_read_reg(bcs, IPACX_ISTAB); + istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB); +//############################################## +// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab); +//############################################## if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; if (istab &0x80) { // RME - rstab = ipacx_bc_read_reg(bcs, IPACX_RSTAB); + rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB); if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) if (!(rstab &0x80)) if (cs->debug &L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: invalid frame", hscx); + debugl1(cs, "bch_int() B-%d: invalid frame", hscx); if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL)) if (cs->debug &L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode); + debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode); if (!(rstab &0x20)) if (cs->debug &L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: CRC error", hscx); - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x80); // RMC - bcs->rcvidx = 0; - } else { // received frame ok - count = ipacx_bc_read_reg(bcs, IPACX_RBCLB) &(B_FIFO_SIZE-1); - if (count == 0) - count = B_FIFO_SIZE; - - ipacx_bc_empty_fifo(bcs, count); - recv_rme_b(bcs); + debugl1(cs, "bch_int() B-%d: CRC error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + } + else { // received frame ok + count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1); + if (count == 0) count = B_FIFO_SIZE; + bch_empty_fifo(bcs, count); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug &L1_DEB_HSCX_FIFO) + debugl1(cs, "bch_int Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n"); + else { + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); } if (istab &0x40) { // RPF - ipacx_bc_empty_fifo(bcs, B_FIFO_SIZE); - recv_rpf_b(bcs); + bch_empty_fifo(bcs, B_FIFO_SIZE); + + if (bcs->mode == L1_MODE_TRANS) { // queue every chunk + // receive transparent audio data + if (!(skb = dev_alloc_skb(B_FIFO_SIZE))) + printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n"); + else { + memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); + } } if (istab &0x20) { // RFO if (cs->debug &L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RFO error", hscx); - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x40); // RRES + debugl1(cs, "bch_int() B-%d: RFO error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES } if (istab &0x10) { // XPR - xmit_xpr_b(bcs); - } + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + bch_fill_fifo(bcs); + goto afterXPR; + } + else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + } + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + set_bit(BC_FLG_BUSY, &bcs->Flag); + bch_fill_fifo(bcs); + } else { + clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } + } + afterXPR: if (istab &0x04) { // XDU - xmit_xdu_b(bcs, reset_xmit); + if (bcs->mode == L1_MODE_TRANS) { + bch_fill_fifo(bcs); + } + else { + if (bcs->tx_skb) { // restart transmitting the whole frame + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d XDU error", hscx); + } } } @@ -564,7 +787,7 @@ static void bch_mode(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->unit; + int hscx = bcs->hw.hscx.hscx; bc = bc ? 1 : 0; // in case bc is greater than 1 if (cs->debug & L1_DEB_HSCX) @@ -575,33 +798,33 @@ bch_mode(struct BCState *bcs, int mode, // map controller to according timeslot if (!hscx) { - ipacx_write_reg(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc); - ipacx_write_reg(cs, IPACX_BCHA_CR, 0x88); + cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc); + cs->writeisac(cs, IPACX_BCHA_CR, 0x88); } else { - ipacx_write_reg(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc); - ipacx_write_reg(cs, IPACX_BCHB_CR, 0x88); + cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc); + cs->writeisac(cs, IPACX_BCHB_CR, 0x88); } switch (mode) { case (L1_MODE_NULL): - ipacx_bc_write_reg(bcs, IPACX_MODEB, 0xC0); // rec off - ipacx_bc_write_reg(bcs, IPACX_EXMB, 0x30); // std adj. - ipacx_bc_write_reg(bcs, IPACX_MASKB, 0xFF); // ints off - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj. + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments break; case (L1_MODE_TRANS): - ipacx_bc_write_reg(bcs, IPACX_MODEB, 0x88); // ext transp mode - ipacx_bc_write_reg(bcs, IPACX_EXMB, 0x00); // xxx00000 - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x41); // validate adjustments - ipacx_bc_write_reg(bcs, IPACX_MASKB, _MASKB_IMASK); + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000 + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); break; case (L1_MODE_HDLC): - ipacx_bc_write_reg(bcs, IPACX_MODEB, 0xC8); // transp mode 0 - ipacx_bc_write_reg(bcs, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled - ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x41); // validate adjustments - ipacx_bc_write_reg(bcs, IPACX_MASKB, _MASKB_IMASK); + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0 + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); break; } } @@ -612,7 +835,23 @@ static void bch_close_state(struct BCState *bcs) { bch_mode(bcs, 0, bcs->channel); - bc_close(bcs); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } } //---------------------------------------------------------- @@ -620,7 +859,30 @@ bch_close_state(struct BCState *bcs) static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs) { - return bc_open(bcs); + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax open_bchstate(): No memory for hscx.rcvbuf\n"); + clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax open_bchstate: No memory for bcs->blog\n"); + clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hscx.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); } //---------------------------------------------------------- @@ -631,7 +893,7 @@ bch_setstack(struct PStack *st, struct B bcs->channel = st->l1.bc; if (bch_open_state(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = bch_l2l1; + st->l2.l2l1 = bch_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -643,7 +905,9 @@ bch_setstack(struct PStack *st, struct B static void __devinit bch_init(struct IsdnCardState *cs, int hscx) { - cs->bcs[hscx].unit = hscx; + cs->bcs[hscx].BC_SetStack = bch_setstack; + cs->bcs[hscx].BC_Close = bch_close_state; + cs->bcs[hscx].hw.hscx.hscx = hscx; cs->bcs[hscx].cs = cs; bch_mode(cs->bcs + hscx, 0, hscx); } @@ -659,16 +923,18 @@ bch_init(struct IsdnCardState *cs, int h void interrupt_ipacx(struct IsdnCardState *cs) { - u8 ista; - - spin_lock(&cs->lock); - while ((ista = ipacx_read_reg(cs, IPACX_ISTA))) { - if (ista &0x80) bch_int(cs, 0); // B channel interrupts - if (ista &0x40) bch_int(cs, 1); - if (ista &0x01) dch_int(cs); // D channel - if (ista &0x10) cic_int(cs); // Layer 1 state - } - spin_unlock(&cs->lock); + u_char ista; + + while ((ista = cs->readisac(cs, IPACX_ISTA))) { +//################################################# +// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista); +//################################################# + if (ista &0x80) bch_int(cs, 0); // B channel interrupts + if (ista &0x40) bch_int(cs, 1); + + if (ista &0x01) dch_int(cs); // D channel + if (ista &0x10) cic_int(cs); // Layer 1 state + } } //---------------------------------------------------------- @@ -680,23 +946,17 @@ clear_pending_ints(struct IsdnCardState int ista; // all interrupts off - ipacx_write_reg(cs, IPACX_MASK, 0xff); - ipacx_write_reg(cs, IPACX_MASKD, 0xff); - cs->bc_hw_ops->write_reg(cs, 0, IPACX_MASKB, 0xff); - cs->bc_hw_ops->write_reg(cs, 1, IPACX_MASKB, 0xff); - - ista = ipacx_read_reg(cs, IPACX_ISTA); - if (ista &0x80) cs->bc_hw_ops->read_reg(cs, 0, IPACX_ISTAB); - if (ista &0x40) cs->bc_hw_ops->read_reg(cs, 1, IPACX_ISTAB); - if (ista &0x10) ipacx_read_reg(cs, IPACX_CIR0); - if (ista &0x01) ipacx_read_reg(cs, IPACX_ISTAD); -} - -static struct bc_l1_ops ipacx_bc_l1_ops = { - .fill_fifo = ipacx_bc_fill_fifo, - .open = bch_setstack, - .close = bch_close_state, -}; + cs->writeisac(cs, IPACX_MASK, 0xff); + cs->writeisac(cs, IPACX_MASKD, 0xff); + cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff); + cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff); + + ista = cs->readisac(cs, IPACX_ISTA); + if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB); + if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB); + if (ista &0x10) cs->readisac(cs, IPACX_CIR0); + if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); +} //---------------------------------------------------------- // Does chip configuration work @@ -706,36 +966,36 @@ void __init init_ipacx(struct IsdnCardState *cs, int part) { if (part &1) { // initialise chip - cs->bc_l1_ops = &ipacx_bc_l1_ops; +//################################################## +// printk(KERN_INFO "init_ipacx(%x)\n", part); +//################################################## clear_pending_ints(cs); bch_init(cs, 0); bch_init(cs, 1); dch_init(cs); } if (part &2) { // reenable all interrupts and start chip - cs->bc_hw_ops->write_reg(cs, 0, IPACX_MASKB, _MASKB_IMASK); - cs->bc_hw_ops->write_reg(cs, 1, IPACX_MASKB, _MASKB_IMASK); - ipacx_write_reg(cs, IPACX_MASKD, _MASKD_IMASK); - ipacx_write_reg(cs, IPACX_MASK, _MASK_IMASK); // global mask register - - // reset HDLC Transmitters/receivers - ipacx_write_reg(cs, IPACX_CMDRD, 0x41); - cs->bc_hw_ops->write_reg(cs, 0, IPACX_CMDRB, 0x41); - cs->bc_hw_ops->write_reg(cs, 1, IPACX_CMDRB, 0x41); + cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK); + cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK); + cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK); + cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register + + // reset HDLC Transmitters/receivers + cs->writeisac(cs, IPACX_CMDRD, 0x41); + cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41); + cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41); ph_command(cs, IPACX_CMD_RES); } } -int -ipacx_setup(struct IsdnCardState *cs, struct dc_hw_ops *ipacx_dc_ops, - struct bc_hw_ops *ipacx_bc_ops) -{ - u8 val; - - cs->dc_hw_ops = ipacx_dc_ops; - cs->bc_hw_ops = ipacx_bc_ops; - val = ipacx_read_reg(cs, IPACX_ID) & 0x3f; - printk(KERN_INFO "HiSax: IPACX Design Id: %#x\n", val); - return 0; + +void __devinit +setup_ipacx(struct IsdnCardState *cs) +{ + INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs); + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); } +//----------------- end of file ----------------------- diff -puN drivers/isdn/hisax/ipacx.h~i4l drivers/isdn/hisax/ipacx.h --- 25/drivers/isdn/hisax/ipacx.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/ipacx.h 2004-02-09 22:19:20.000000000 -0800 @@ -155,10 +155,8 @@ #define IPACX_IND_AIL 0xe #define IPACX_IND_DC 0xf -extern void init_ipacx(struct IsdnCardState *cs, int part); -extern void interrupt_ipacx(struct IsdnCardState *cs); -extern int ipacx_setup(struct IsdnCardState *cs, - struct dc_hw_ops *ipacx_dc_ops, - struct bc_hw_ops *ipacx_bc_ops); +extern void init_ipacx(struct IsdnCardState *, int); +extern void interrupt_ipacx(struct IsdnCardState *); +extern void setup_isac(struct IsdnCardState *); #endif diff -puN drivers/isdn/hisax/isac.c~i4l drivers/isdn/hisax/isac.c --- 25/drivers/isdn/hisax/isac.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isac.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.28.6.3 2001/09/23 22:24:49 kai Exp $ +/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $ * * ISAC specific routines * @@ -27,30 +27,12 @@ static char *ISACVer[] __devinitdata = {"2086/2186 V1.1", "2085 B1", "2085 B2", "2085 V2.3"}; -static inline u8 -isac_read(struct IsdnCardState *cs, u8 addr) -{ - return cs->dc_hw_ops->read_reg(cs, addr); -} - -static inline void -isac_write(struct IsdnCardState *cs, u8 addr, u8 val) -{ - cs->dc_hw_ops->write_reg(cs, addr, val); -} - -static inline void -isac_write_fifo(struct IsdnCardState *cs, u8 *p, int len) -{ - return cs->dc_hw_ops->write_fifo(cs, p, len); -} - -static void +void ISACVersion(struct IsdnCardState *cs, char *s) { int val; - val = isac_read(cs, ISAC_RBCH); + val = cs->readisac(cs, ISAC_RBCH); printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]); } @@ -59,7 +41,7 @@ ph_command(struct IsdnCardState *cs, uns { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_command %x", command); - isac_write(cs, ISAC_CIX0, (command << 2) | 3); + cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3); } @@ -99,9 +81,8 @@ isac_new_ph(struct IsdnCardState *cs) } static void -isac_bh(void *data) +isac_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; struct PStack *stptr; if (!cs) @@ -111,7 +92,7 @@ isac_bh(void *data) debugl1(cs, "D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - L1L2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -134,22 +115,58 @@ isac_bh(void *data) void isac_empty_fifo(struct IsdnCardState *cs, int count) { - recv_empty_fifo_d(cs, count); - isac_write(cs, ISAC_CMDR, 0x80); + u_char *ptr; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "isac_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isac_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeisac(cs, ISAC_CMDR, 0x80); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, ISAC_CMDR, 0x80); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "isac_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } static void isac_fill_fifo(struct IsdnCardState *cs) { int count, more; - unsigned char *p; + u_char *ptr; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "isac_fill_fifo"); + + if (!cs->tx_skb) + return; - p = xmit_fill_fifo_d(cs, 32, &count, &more); - if (!p) + count = cs->tx_skb->len; + if (count <= 0) return; - isac_write_fifo(cs, p, count); - isac_write(cs, ISAC_CMDR, more ? 0x8 : 0xa); + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa); if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { debugl1(cs, "isac_fill_fifo dbusytimer running"); del_timer(&cs->dbusytimer); @@ -157,18 +174,26 @@ isac_fill_fifo(struct IsdnCardState *cs) init_timer(&cs->dbusytimer); cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); add_timer(&cs->dbusytimer); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "isac_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } void -isac_interrupt(struct IsdnCardState *cs, u8 val) +isac_interrupt(struct IsdnCardState *cs, u_char val) { - u8 exval, v1; + u_char exval, v1; + struct sk_buff *skb; unsigned int count; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC interrupt %x", val); if (val & 0x80) { /* RME */ - exval = isac_read(cs, ISAC_RSTA); + exval = cs->readisac(cs, ISAC_RSTA); if ((exval & 0x70) != 0x20) { if (exval & 0x40) { if (cs->debug & L1_DEB_WARN) @@ -184,17 +209,24 @@ isac_interrupt(struct IsdnCardState *cs, cs->err_crc++; #endif } - isac_write(cs, ISAC_CMDR, 0x80); - cs->rcvidx = 0; + cs->writeisac(cs, ISAC_CMDR, 0x80); } else { - count = isac_read(cs, ISAC_RBCL) & 0x1f; + count = cs->readisac(cs, ISAC_RBCL) & 0x1f; if (count == 0) count = 32; isac_empty_fifo(cs, count); - recv_rme_d(cs); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } } cs->rcvidx = 0; - sched_d_event(cs, D_RCVBUFREADY); + schedule_event(cs, D_RCVBUFREADY); } if (val & 0x40) { /* RPF */ isac_empty_fifo(cs, 32); @@ -205,20 +237,39 @@ isac_interrupt(struct IsdnCardState *cs, debugl1(cs, "ISAC RSC interrupt"); } if (val & 0x10) { /* XPR */ - xmit_xpr_d(cs); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + isac_fill_fifo(cs); + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + isac_fill_fifo(cs); + } else + schedule_event(cs, D_XMTBUFREADY); } + afterXPR: if (val & 0x04) { /* CISQ */ - exval = isac_read(cs, ISAC_CIR0); + exval = cs->readisac(cs, ISAC_CIR0); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC CIR0 %02X", exval ); if (exval & 2) { cs->dc.isac.ph_state = (exval >> 2) & 0xf; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state); - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); } if (exval & 1) { - exval = isac_read(cs, ISAC_CIR1); + exval = cs->readisac(cs, ISAC_CIR1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC CIR1 %02X", exval ); } @@ -229,7 +280,7 @@ isac_interrupt(struct IsdnCardState *cs, debugl1(cs, "ISAC SIN interrupt"); } if (val & 0x01) { /* EXI */ - exval = isac_read(cs, ISAC_EXIR); + exval = cs->readisac(cs, ISAC_EXIR); if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC EXIR %02x", exval); if (exval & 0x80) { /* XMR */ @@ -237,10 +288,26 @@ isac_interrupt(struct IsdnCardState *cs, printk(KERN_WARNING "HiSax: ISAC XMR\n"); } if (exval & 0x40) { /* XDU */ - xmit_xdu_d(cs, NULL); + debugl1(cs, "ISAC XDU"); + printk(KERN_WARNING "HiSax: ISAC XDU\n"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + isac_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); + debugl1(cs, "ISAC XDU no skb"); + } } if (exval & 0x04) { /* MOS */ - v1 = isac_read(cs, ISAC_MOSR); + v1 = cs->readisac(cs, ISAC_MOSR); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ISAC MOSR %02x", v1); #if ARCOFI_USE @@ -251,7 +318,7 @@ isac_interrupt(struct IsdnCardState *cs, debugl1(cs, "ISAC MON RX out of memory!"); cs->dc.isac.mocr &= 0xf0; cs->dc.isac.mocr |= 0x0a; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); goto afterMONR0; } else cs->dc.isac.mon_rxp = 0; @@ -259,18 +326,18 @@ isac_interrupt(struct IsdnCardState *cs, if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { cs->dc.isac.mocr &= 0xf0; cs->dc.isac.mocr |= 0x0a; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); cs->dc.isac.mon_rxp = 0; if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON RX overflow!"); goto afterMONR0; } - cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = isac_read(cs, ISAC_MOR0); + cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]); if (cs->dc.isac.mon_rxp == 1) { cs->dc.isac.mocr |= 0x04; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); } } afterMONR0: @@ -281,7 +348,7 @@ isac_interrupt(struct IsdnCardState *cs, debugl1(cs, "ISAC MON RX out of memory!"); cs->dc.isac.mocr &= 0x0f; cs->dc.isac.mocr |= 0xa0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); goto afterMONR1; } else cs->dc.isac.mon_rxp = 0; @@ -289,51 +356,51 @@ isac_interrupt(struct IsdnCardState *cs, if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { cs->dc.isac.mocr &= 0x0f; cs->dc.isac.mocr |= 0xa0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); cs->dc.isac.mon_rxp = 0; if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON RX overflow!"); goto afterMONR1; } - cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = isac_read(cs, ISAC_MOR1); + cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]); cs->dc.isac.mocr |= 0x40; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); } afterMONR1: if (v1 & 0x04) { cs->dc.isac.mocr &= 0xf0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); cs->dc.isac.mocr |= 0x0a; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); - sched_d_event(cs, D_RX_MON0); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + schedule_event(cs, D_RX_MON0); } if (v1 & 0x40) { cs->dc.isac.mocr &= 0x0f; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); cs->dc.isac.mocr |= 0xa0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); - sched_d_event(cs, D_RX_MON1); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + schedule_event(cs, D_RX_MON1); } if (v1 & 0x02) { if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && !(v1 & 0x08))) { cs->dc.isac.mocr &= 0xf0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); cs->dc.isac.mocr |= 0x0a; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) - sched_d_event(cs, D_TX_MON0); + schedule_event(cs, D_TX_MON0); goto AfterMOX0; } if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { - sched_d_event(cs, D_TX_MON0); + schedule_event(cs, D_TX_MON0); goto AfterMOX0; } - isac_write(cs, ISAC_MOX0, + cs->writeisac(cs, ISAC_MOX0, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); @@ -344,19 +411,19 @@ isac_interrupt(struct IsdnCardState *cs, (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && !(v1 & 0x80))) { cs->dc.isac.mocr &= 0x0f; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); cs->dc.isac.mocr |= 0xa0; - isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) - sched_d_event(cs, D_TX_MON1); + schedule_event(cs, D_TX_MON1); goto AfterMOX1; } if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { - sched_d_event(cs, D_TX_MON1); + schedule_event(cs, D_TX_MON1); goto AfterMOX1; } - isac_write(cs, ISAC_MOX1, + cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); @@ -372,33 +439,87 @@ ISAC_l1hw(struct PStack *st, int pr, voi { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; + u_long flags; int val; switch (pr) { case (PH_DATA |REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + isac_fill_fifo(cs); + } + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL |INDICATION): - xmit_pull_ind_d(cs, skb); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + } else { + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + isac_fill_fifo(cs); + } + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): + spin_lock_irqsave(&cs->lock, flags); if ((cs->dc.isac.ph_state == ISAC_IND_EI) || (cs->dc.isac.ph_state == ISAC_IND_DR) || (cs->dc.isac.ph_state == ISAC_IND_RS)) ph_command(cs, ISAC_CMD_TIM); else ph_command(cs, ISAC_CMD_RS); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_ENABLE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, ISAC_CMD_TIM); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, ISAC_CMD_AR8); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): + spin_lock_irqsave(&cs->lock, flags); val = 0; if (1 & (long) arg) val |= 0x0c; @@ -407,20 +528,21 @@ ISAC_l1hw(struct PStack *st, int pr, voi if (test_bit(HW_IOM1, &cs->HW_Flags)) { /* IOM 1 Mode */ if (!val) { - isac_write(cs, ISAC_SPCR, 0xa); - isac_write(cs, ISAC_ADF1, 0x2); + cs->writeisac(cs, ISAC_SPCR, 0xa); + cs->writeisac(cs, ISAC_ADF1, 0x2); } else { - isac_write(cs, ISAC_SPCR, val); - isac_write(cs, ISAC_ADF1, 0xa); + cs->writeisac(cs, ISAC_SPCR, val); + cs->writeisac(cs, ISAC_ADF1, 0xa); } } else { /* IOM 2 Mode */ - isac_write(cs, ISAC_SPCR, val); + cs->writeisac(cs, ISAC_SPCR, val); if (val) - isac_write(cs, ISAC_ADF1, 0x8); + cs->writeisac(cs, ISAC_ADF1, 0x8); else - isac_write(cs, ISAC_ADF1, 0x0); + cs->writeisac(cs, ISAC_ADF1, 0x0); } + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_DEACTIVATE | RESPONSE): skb_queue_purge(&cs->rq); @@ -432,7 +554,7 @@ ISAC_l1hw(struct PStack *st, int pr, voi if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); break; default: if (cs->debug & L1_DEB_WARN) @@ -441,14 +563,13 @@ ISAC_l1hw(struct PStack *st, int pr, voi } } -static int +void setstack_isac(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = ISAC_l1hw; - return 0; } -static void +void DC_Close_isac(struct IsdnCardState *cs) { if (cs->dc.isac.mon_rx) { kfree(cs->dc.isac.mon_rx); @@ -467,8 +588,8 @@ dbusy_timer_handler(struct IsdnCardState int rbch, star; if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = isac_read(cs, ISAC_RBCH); - star = isac_read(cs, ISAC_STAR); + rbch = cs->readisac(cs, ISAC_RBCH); + star = cs->readisac(cs, ISAC_STAR); if (cs->debug) debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", rbch, star); @@ -476,7 +597,7 @@ dbusy_timer_handler(struct IsdnCardState test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); stptr = cs->stlist; while (stptr != NULL) { - L1L2(stptr, PH_PAUSE | INDICATION, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } else { @@ -490,80 +611,74 @@ dbusy_timer_handler(struct IsdnCardState printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); debugl1(cs, "D-Channel Busy no skb"); } - isac_write(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ - cs->card_ops->irq_func(cs->irq, cs, NULL); + cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); } } } -static struct dc_l1_ops isac_l1_ops = { - .fill_fifo = isac_fill_fifo, - .open = setstack_isac, - .close = DC_Close_isac, - .bh_func = isac_bh, - .dbusy_func = dbusy_timer_handler, -}; - void __devinit initisac(struct IsdnCardState *cs) { - int val, eval; - - dc_l1_init(cs, &isac_l1_ops); - - val = isac_read(cs, ISAC_STAR); - debugl1(cs, "ISAC STAR %x", val); - val = isac_read(cs, ISAC_MODE); - debugl1(cs, "ISAC MODE %x", val); - val = isac_read(cs, ISAC_ADF2); - debugl1(cs, "ISAC ADF2 %x", val); - val = isac_read(cs, ISAC_ISTA); - debugl1(cs, "ISAC ISTA %x", val); - if (val & 0x01) { - eval = isac_read(cs, ISAC_EXIR); - debugl1(cs, "ISAC EXIR %x", eval); - } - /* Disable all IRQ */ - isac_write(cs, ISAC_MASK, 0xFF); - + cs->setstack_d = setstack_isac; + cs->DC_Close = DC_Close_isac; cs->dc.isac.mon_tx = NULL; cs->dc.isac.mon_rx = NULL; + cs->writeisac(cs, ISAC_MASK, 0xff); cs->dc.isac.mocr = 0xaa; if (test_bit(HW_IOM1, &cs->HW_Flags)) { /* IOM 1 Mode */ - isac_write(cs, ISAC_ADF2, 0x0); - isac_write(cs, ISAC_SPCR, 0xa); - isac_write(cs, ISAC_ADF1, 0x2); - isac_write(cs, ISAC_STCR, 0x70); - isac_write(cs, ISAC_MODE, 0xc9); + cs->writeisac(cs, ISAC_ADF2, 0x0); + cs->writeisac(cs, ISAC_SPCR, 0xa); + cs->writeisac(cs, ISAC_ADF1, 0x2); + cs->writeisac(cs, ISAC_STCR, 0x70); + cs->writeisac(cs, ISAC_MODE, 0xc9); } else { /* IOM 2 Mode */ if (!cs->dc.isac.adf2) cs->dc.isac.adf2 = 0x80; - isac_write(cs, ISAC_ADF2, cs->dc.isac.adf2); - isac_write(cs, ISAC_SQXR, 0x2f); - isac_write(cs, ISAC_SPCR, 0x00); - isac_write(cs, ISAC_STCR, 0x70); - isac_write(cs, ISAC_MODE, 0xc9); - isac_write(cs, ISAC_TIMR, 0x00); - isac_write(cs, ISAC_ADF1, 0x00); + cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2); + cs->writeisac(cs, ISAC_SQXR, 0x2f); + cs->writeisac(cs, ISAC_SPCR, 0x00); + cs->writeisac(cs, ISAC_STCR, 0x70); + cs->writeisac(cs, ISAC_MODE, 0xc9); + cs->writeisac(cs, ISAC_TIMR, 0x00); + cs->writeisac(cs, ISAC_ADF1, 0x00); } ph_command(cs, ISAC_CMD_RS); - isac_write(cs, ISAC_MASK, 0x0); + cs->writeisac(cs, ISAC_MASK, 0x0); +} - val = isac_read(cs, ISAC_CIR0); +void __devinit +clear_pending_isac_ints(struct IsdnCardState *cs) +{ + int val, eval; + + val = cs->readisac(cs, ISAC_STAR); + debugl1(cs, "ISAC STAR %x", val); + val = cs->readisac(cs, ISAC_MODE); + debugl1(cs, "ISAC MODE %x", val); + val = cs->readisac(cs, ISAC_ADF2); + debugl1(cs, "ISAC ADF2 %x", val); + val = cs->readisac(cs, ISAC_ISTA); + debugl1(cs, "ISAC ISTA %x", val); + if (val & 0x01) { + eval = cs->readisac(cs, ISAC_EXIR); + debugl1(cs, "ISAC EXIR %x", eval); + } + val = cs->readisac(cs, ISAC_CIR0); debugl1(cs, "ISAC CIR0 %x", val); cs->dc.isac.ph_state = (val >> 2) & 0xf; - sched_d_event(cs, D_L1STATECHANGE); - - /* RESET Receiver and Transmitter */ - isac_write(cs, ISAC_CMDR, 0x41); + schedule_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0xFF); } -int -isac_setup(struct IsdnCardState *cs, struct dc_hw_ops *isac_ops) +void __devinit +setup_isac(struct IsdnCardState *cs) { - cs->dc_hw_ops = isac_ops; - ISACVersion(cs, "HiSax:"); - return 0; + INIT_WORK(&cs->tqueue, (void *)(void *) isac_bh, cs); + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); } diff -puN drivers/isdn/hisax/isac.h~i4l drivers/isdn/hisax/isac.h --- 25/drivers/isdn/hisax/isac.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isac.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isac.h,v 1.7.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $ * * ISAC specific defines * @@ -63,6 +63,8 @@ #define ISAC_IND_AI10 0xD #define ISAC_IND_DID 0xF -extern void initisac(struct IsdnCardState *cs); -extern void isac_interrupt(struct IsdnCardState *cs, u8 val); -extern int isac_setup(struct IsdnCardState *cs, struct dc_hw_ops *isac_ops); +extern void ISACVersion(struct IsdnCardState *, char *); +extern void setup_isac(struct IsdnCardState *); +extern void initisac(struct IsdnCardState *); +extern void isac_interrupt(struct IsdnCardState *, u_char); +extern void clear_pending_isac_ints(struct IsdnCardState *); diff -puN drivers/isdn/hisax/isar.c~i4l drivers/isdn/hisax/isar.c --- 25/drivers/isdn/hisax/isar.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isar.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.17.6.5 2001/09/23 11:51:33 keil Exp $ +/* $Id: isar.c,v 1.22.2.5 2004/01/14 00:49:44 keil Exp $ * * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -20,33 +20,22 @@ #define DLE 0x10 #define ETX 0x03 - -const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; -const u8 faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; -#define FAXMODCNT 13 - -static void __isar_setup(struct IsdnCardState *cs); -static void isar_pump_cmd(struct BCState *bcs, u8 cmd, u8 para); -static inline void ll_deliver_faxstat(struct BCState *bcs, u8 status); -static spinlock_t isar_lock = SPIN_LOCK_UNLOCKED; - -static inline u8 -isar_read_reg(struct IsdnCardState *cs, int mode, u8 addr) -{ - return cs->bc_hw_ops->read_reg(cs, mode, addr); -} - -static inline void -isar_write_reg(struct IsdnCardState *cs, int mode, u8 addr, u8 val) -{ - cs->bc_hw_ops->write_reg(cs, mode, addr, val); -} +#define FAXMODCNT 13 +const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; +static u_int modmask = 0x1fff; +static int frm_extra_delay = 2; +static int para_TOA = 6; +const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" }; + +void isar_setup(struct IsdnCardState *cs); +static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para); +static void ll_deliver_faxstat(struct BCState *bcs, u_char status); static inline int waitforHIA(struct IsdnCardState *cs, int timeout) { - while ((isar_read_reg(cs, 0, ISAR_HIA) & 1) && timeout) { + while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) { udelay(1); timeout--; } @@ -57,10 +46,9 @@ waitforHIA(struct IsdnCardState *cs, int int -sendmsg(struct IsdnCardState *cs, u8 his, u8 creg, u8 len, - u8 *msg) +sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, + u_char *msg) { - unsigned long flags; int i; if (!waitforHIA(cs, 4000)) @@ -69,14 +57,13 @@ sendmsg(struct IsdnCardState *cs, u8 his if (cs->debug & L1_DEB_HSCX) debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len); #endif - spin_lock_irqsave(&isar_lock, flags); - isar_write_reg(cs, 0, ISAR_CTRL_H, creg); - isar_write_reg(cs, 0, ISAR_CTRL_L, len); - isar_write_reg(cs, 0, ISAR_WADR, 0); + cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg); + cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len); + cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0); if (msg && len) { - isar_write_reg(cs, 1, ISAR_MBOX, msg[0]); + cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]); for (i=1; iBC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]); #if DUMP_MBOXFRAME>1 if (cs->debug & L1_DEB_HSCX_FIFO) { char tmp[256], *t; @@ -92,23 +79,22 @@ sendmsg(struct IsdnCardState *cs, u8 his } #endif } - isar_write_reg(cs, 1, ISAR_HIS, his); - spin_unlock_irqrestore(&isar_lock, flags); + cs->BC_Write_Reg(cs, 1, ISAR_HIS, his); waitforHIA(cs, 10000); return(1); } /* Call only with IRQ disabled !!! */ inline void -rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u8 *msg) +rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg) { int i; - isar_write_reg(cs, 1, ISAR_RADR, 0); + cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0); if (msg && ireg->clsb) { - msg[0] = isar_read_reg(cs, 1, ISAR_MBOX); + msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX); for (i=1; i < ireg->clsb; i++) - msg[i] = isar_read_reg(cs, 2, ISAR_MBOX); + msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX); #if DUMP_MBOXFRAME>1 if (cs->debug & L1_DEB_HSCX_FIFO) { char tmp[256], *t; @@ -124,85 +110,90 @@ rcv_mbox(struct IsdnCardState *cs, struc } #endif } - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } /* Call only with IRQ disabled !!! */ inline void get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg) { - ireg->iis = isar_read_reg(cs, 1, ISAR_IIS); - ireg->cmsb = isar_read_reg(cs, 1, ISAR_CTRL_H); - ireg->clsb = isar_read_reg(cs, 1, ISAR_CTRL_L); + ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS); + ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H); + ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L); #if DUMP_MBOXFRAME if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb, + debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb, ireg->clsb); #endif } int -waitrecmsg(struct IsdnCardState *cs, u8 *len, - u8 *msg, int maxdelay) +waitrecmsg(struct IsdnCardState *cs, u_char *len, + u_char *msg, int maxdelay) { int timeout = 0; - unsigned long flags; struct isar_reg *ir = cs->bcs[0].hw.isar.reg; - while((!(isar_read_reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && + while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && (timeout++ < maxdelay)) udelay(1); if (timeout >= maxdelay) { printk(KERN_WARNING"isar recmsg IRQSTA timeout\n"); return(0); } - spin_lock_irqsave(&isar_lock, flags); get_irq_infos(cs, ir); rcv_mbox(cs, ir, msg); *len = ir->clsb; - spin_unlock_irqrestore(&isar_lock, flags); return(1); } -static int +int ISARVersion(struct IsdnCardState *cs, char *s) { int ver; - u8 msg[] = ISAR_MSG_HWVER; - u8 tmp[64]; - u8 len; + u_char msg[] = ISAR_MSG_HWVER; + u_char tmp[64]; + u_char len; + u_long flags; int debug; - cs->card_ops->reset(cs); + cs->cardmsg(cs, CARD_RESET, NULL); + spin_lock_irqsave(&cs->lock, flags); /* disable ISAR IRQ */ - isar_write_reg(cs, 0, ISAR_IRQBIT, 0); + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); debug = cs->debug; cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); - if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) + if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) { + spin_unlock_irqrestore(&cs->lock, flags); return(-1); - if (!waitrecmsg(cs, &len, tmp, 100000)) - return(-2); + } + if (!waitrecmsg(cs, &len, tmp, 100000)) { + spin_unlock_irqrestore(&cs->lock, flags); + return(-2); + } cs->debug = debug; if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) { if (len == 1) { ver = tmp[0] & 0xf; printk(KERN_INFO "%s ISAR version %d\n", s, ver); - return(ver); - } - return(-3); - } - return(-4); + } else + ver = -3; + } else + ver = -4; + spin_unlock_irqrestore(&cs->lock, flags); + return(ver); } int -isar_load_firmware(struct IsdnCardState *cs, u8 *buf) +isar_load_firmware(struct IsdnCardState *cs, u_char *buf) { int ret, size, cnt, debug; - u8 len, nom, noc; + u_char len, nom, noc; u_short sadr, left, *sp; - u8 *p = buf; - u8 *msg, *tmpmsg, *mp, tmp[64]; + u_char *p = buf; + u_char *msg, *tmpmsg, *mp, tmp[64]; + u_long flags; struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; struct {u_short sadr; @@ -219,16 +210,16 @@ isar_load_firmware(struct IsdnCardState #if DBG_LOADFIRM<2 cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); #endif - printk(KERN_DEBUG"isar_load_firmware buf %#lx\n", (u_long)buf); + if ((ret = copy_from_user(&size, p, sizeof(int)))) { printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - return -EFAULT; + return ret; } p += sizeof(int); printk(KERN_DEBUG"isar_load_firmware size: %d\n", size); cnt = 0; /* disable ISAR IRQ */ - isar_write_reg(cs, 0, ISAR_IRQBIT, 0); + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); if (!(msg = kmalloc(256, GFP_KERNEL))) { printk(KERN_ERR"isar_load_firmware no buffer\n"); return (1); @@ -238,10 +229,13 @@ isar_load_firmware(struct IsdnCardState kfree(msg); return (1); } + spin_lock_irqsave(&cs->lock, flags); + /* disable ISAR IRQ */ + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); + spin_unlock_irqrestore(&cs->lock, flags); while (cnt < size) { if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) { printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - ret = -EFAULT; goto reterror; } #ifdef __BIG_ENDIAN @@ -258,19 +252,21 @@ isar_load_firmware(struct IsdnCardState blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); sadr = blk_head.sadr; left = blk_head.len; + spin_lock_irqsave(&cs->lock, flags); if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) { printk(KERN_ERR"isar sendmsg dkey failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } if (!waitrecmsg(cs, &len, tmp, 100000)) { printk(KERN_ERR"isar waitrecmsg dkey failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) { printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n", ireg->iis, ireg->cmsb, len); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } + spin_unlock_irqrestore(&cs->lock, flags); while (left>0) { if (left > 126) noc = 126; @@ -284,7 +280,6 @@ isar_load_firmware(struct IsdnCardState *mp++ = noc; if ((ret = copy_from_user(tmpmsg, p, nom))) { printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - ret = -EFAULT; goto reterror; } p += nom; @@ -307,19 +302,21 @@ isar_load_firmware(struct IsdnCardState sp++; noc--; } + spin_lock_irqsave(&cs->lock, flags); if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) { printk(KERN_ERR"isar sendmsg prog failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } if (!waitrecmsg(cs, &len, tmp, 100000)) { printk(KERN_ERR"isar waitrecmsg prog failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) { printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n", ireg->iis, ireg->cmsb, len); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } + spin_unlock_irqrestore(&cs->lock, flags); } printk(KERN_DEBUG"isar firmware block %5d words loaded\n", blk_head.len); @@ -331,23 +328,25 @@ isar_load_firmware(struct IsdnCardState msg[0] = 0xff; msg[1] = 0xfe; ireg->bstat = 0; + spin_lock_irqsave(&cs->lock, flags); if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) { printk(KERN_ERR"isar sendmsg start dsp failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } if (!waitrecmsg(cs, &len, tmp, 100000)) { printk(KERN_ERR"isar waitrecmsg start dsp failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) { printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n", ireg->iis, ireg->cmsb, len); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } else printk(KERN_DEBUG"isar start dsp success\n"); /* NORMAL mode entered */ /* Enable IRQs of ISAR */ - isar_write_reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA); + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA); + spin_unlock_irqrestore(&cs->lock, flags); cnt = 1000; /* max 1s */ while ((!ireg->bstat) && cnt) { udelay(1000); @@ -364,12 +363,14 @@ isar_load_firmware(struct IsdnCardState cnt = 10; while (cnt--) udelay(1000); + spin_lock_irqsave(&cs->lock, flags); ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { printk(KERN_ERR"isar sendmsg self tst failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } cnt = 10000; /* max 100 ms */ + spin_unlock_irqrestore(&cs->lock, flags); while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; @@ -387,11 +388,13 @@ isar_load_firmware(struct IsdnCardState ireg->cmsb, ireg->clsb, ireg->par[0]); ret = 1;goto reterror; } + spin_lock_irqsave(&cs->lock, flags); ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { printk(KERN_ERR"isar RQST SVN failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterr_unlock; } + spin_unlock_irqrestore(&cs->lock, flags); cnt = 30000; /* max 300 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); @@ -411,26 +414,31 @@ isar_load_firmware(struct IsdnCardState ret = 1;goto reterror; } } + spin_lock_irqsave(&cs->lock, flags); cs->debug = debug; - __isar_setup(cs); + isar_setup(cs); + ret = 0; +reterr_unlock: + spin_unlock_irqrestore(&cs->lock, flags); reterror: cs->debug = debug; if (ret) /* disable ISAR IRQ */ - isar_write_reg(cs, 0, ISAR_IRQBIT, 0); + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); kfree(msg); kfree(tmpmsg); return(ret); } extern void BChannel_bh(struct BCState *); +#define B_LL_NOCARRIER 8 +#define B_LL_CONNECT 9 +#define B_LL_OK 10 static void -isar_bh(void *data) +isar_bh(struct BCState *bcs) { - struct BCState *bcs = data; - BChannel_bh(bcs); if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); @@ -440,16 +448,16 @@ isar_bh(void *data) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK); } -static inline void +static void send_DLE_ETX(struct BCState *bcs) { - u8 dleetx[2] = {DLE,ETX}; + u_char dleetx[2] = {DLE,ETX}; struct sk_buff *skb; if ((skb = dev_alloc_skb(2))) { memcpy(skb_put(skb, 2), dleetx, 2); skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); } else { printk(KERN_WARNING "HiSax: skb out of memory\n"); } @@ -476,16 +484,16 @@ insert_dle(unsigned char *dest, unsigned } } -static inline void +static void isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) { - u8 *ptr; + u_char *ptr; struct sk_buff *skb; struct isar_reg *ireg = bcs->hw.isar.reg; if (!ireg->clsb) { debugl1(cs, "isar zero len frame"); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); return; } switch (bcs->mode) { @@ -494,24 +502,24 @@ isar_rcv_frame(struct IsdnCardState *cs, ireg->iis, ireg->cmsb, ireg->clsb); printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n", ireg->iis, ireg->cmsb, ireg->clsb); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); break; case L1_MODE_TRANS: case L1_MODE_V32: if ((skb = dev_alloc_skb(ireg->clsb))) { - rcv_mbox(cs, ireg, (u8 *)skb_put(skb, ireg->clsb)); + rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb)); skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); } else { printk(KERN_WARNING "HiSax: skb out of memory\n"); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; case L1_MODE_HDLC: if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: incoming packet too large"); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; } else if (ireg->cmsb & HDLC_ERROR) { if (cs->debug & L1_DEB_WARN) @@ -524,7 +532,7 @@ isar_rcv_frame(struct IsdnCardState *cs, bcs->err_crc++; #endif bcs->hw.isar.rcvidx = 0; - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } else { if (ireg->cmsb & HDLC_FSD) bcs->hw.isar.rcvidx = 0; @@ -542,7 +550,7 @@ isar_rcv_frame(struct IsdnCardState *cs, memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2); skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); } bcs->hw.isar.rcvidx = 0; } @@ -552,7 +560,7 @@ isar_rcv_frame(struct IsdnCardState *cs, if (bcs->hw.isar.state != STFAX_ACTIV) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: not ACTIV"); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; break; } @@ -564,25 +572,23 @@ isar_rcv_frame(struct IsdnCardState *cs, debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)", ireg->clsb, bcs->hw.isar.rcvidx); if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { - insert_dle((u8 *)skb_put(skb, bcs->hw.isar.rcvidx), + insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx), bcs->hw.isar.rcvbuf, ireg->clsb); skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); if (ireg->cmsb & SART_NMD) { /* ABORT */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: no more data"); - isar_write_reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; send_DLE_ETX(bcs); sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); bcs->hw.isar.state = STFAX_ESCAPE; - sched_b_event(bcs, B_LL_NOCARRIER); + schedule_event(bcs, B_LL_NOCARRIER); } } else { printk(KERN_WARNING "HiSax: skb out of memory\n"); - isar_write_reg(cs, 1, ISAR_IIA, 0); } break; } @@ -590,7 +596,7 @@ isar_rcv_frame(struct IsdnCardState *cs, if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: unknown fax mode %x", bcs->hw.isar.cmd); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; break; } @@ -598,17 +604,18 @@ isar_rcv_frame(struct IsdnCardState *cs, if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: incoming packet too large"); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; } else if (ireg->cmsb & HDLC_ERROR) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar frame error %x len %d", ireg->cmsb, ireg->clsb); bcs->hw.isar.rcvidx = 0; - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } else { - if (ireg->cmsb & HDLC_FSD) + if (ireg->cmsb & HDLC_FSD) { bcs->hw.isar.rcvidx = 0; + } ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); @@ -619,16 +626,19 @@ isar_rcv_frame(struct IsdnCardState *cs, if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar frame to short %d", bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { + printk(KERN_WARNING "ISAR: frame to short %d\n", + bcs->hw.isar.rcvidx); + } else if (!(skb = dev_alloc_skb(len))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { - insert_dle((u8 *)skb_put(skb, len), + insert_dle((u_char *)skb_put(skb, len), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); + schedule_event(bcs, B_RCVBUFREADY); send_DLE_ETX(bcs); - sched_b_event(bcs, B_LL_OK); + schedule_event(bcs, B_LL_OK); + test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); } bcs->hw.isar.rcvidx = 0; } @@ -636,18 +646,19 @@ isar_rcv_frame(struct IsdnCardState *cs, if (ireg->cmsb & SART_NMD) { /* ABORT */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: no more data"); - isar_write_reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; - send_DLE_ETX(bcs); sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); bcs->hw.isar.state = STFAX_ESCAPE; - sched_b_event(bcs, B_LL_NOCARRIER); + if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) { + send_DLE_ETX(bcs); + schedule_event(bcs, B_LL_NOCARRIER); + } } break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); break; } } @@ -657,8 +668,8 @@ isar_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; int count; - u8 msb; - u8 *ptr; + u_char msb; + u_char *ptr; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "isar_fill_fifo"); @@ -669,7 +680,7 @@ isar_fill_fifo(struct BCState *bcs) if (!(bcs->hw.isar.reg->bstat & (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) return; - if (bcs->tx_skb->len > (u_int)bcs->hw.isar.mml) { + if (bcs->tx_skb->len > bcs->hw.isar.mml) { msb = 0; count = bcs->hw.isar.mml; } else { @@ -677,7 +688,7 @@ isar_fill_fifo(struct BCState *bcs) msb = HDLC_FED; } ptr = bcs->tx_skb->data; - if (!bcs->count) { + if (!bcs->hw.isar.txcnt) { msb |= HDLC_FST; if ((bcs->mode == L1_MODE_FAX) && (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) { @@ -691,7 +702,7 @@ isar_fill_fifo(struct BCState *bcs) } skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; - bcs->count += count; + bcs->hw.isar.txcnt += count; switch (bcs->mode) { case L1_MODE_NULL: printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); @@ -729,7 +740,7 @@ isar_fill_fifo(struct BCState *bcs) } inline -struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u8 dpath) +struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath) { if ((!dpath) || (dpath == 3)) return(NULL); @@ -740,7 +751,7 @@ struct BCState *sel_bcs_isar(struct Isdn return(NULL); } -inline void +void send_frames(struct BCState *bcs) { if (bcs->tx_skb) { @@ -748,7 +759,9 @@ send_frames(struct BCState *bcs) isar_fill_fifo(bcs); return; } else { - xmit_complete_b(bcs); + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt); if (bcs->mode == L1_MODE_FAX) { if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { @@ -761,33 +774,35 @@ send_frames(struct BCState *bcs) } } } - bcs->count = 0; + dev_kfree_skb_any(bcs->tx_skb); + bcs->hw.isar.txcnt = 0; + bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->count = 0; + bcs->hw.isar.txcnt = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); isar_fill_fifo(bcs); } else { if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) { if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) { if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) { - u8 dummy = 0; + u_char dummy = 0; sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, 0x01, 1, &dummy); } test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag); } else { - sched_b_event(bcs, B_LL_CONNECT); + schedule_event(bcs, B_LL_CONNECT); } } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - sched_b_event(bcs, B_XMTBUFREADY); + schedule_event(bcs, B_XMTBUFREADY); } } inline void -check_send(struct IsdnCardState *cs, u8 rdm) +check_send(struct IsdnCardState *cs, u_char rdm) { struct BCState *bcs; @@ -817,8 +832,8 @@ const char *dmrim[] = {"NO MOD", "NO DEF static void isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { struct IsdnCardState *cs = bcs->cs; - u8 ril = ireg->par[0]; - u8 rim; + u_char ril = ireg->par[0]; + u_char rim; if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags)) return; @@ -869,9 +884,9 @@ isar_pump_status_rsp(struct BCState *bcs } static void -isar_pump_statev_modem(struct BCState *bcs, u8 devt) { +isar_pump_statev_modem(struct BCState *bcs, u_char devt) { struct IsdnCardState *cs = bcs->cs; - u8 dps = SET_DPS(bcs->hw.isar.dpath); + u_char dps = SET_DPS(bcs->hw.isar.dpath); switch(devt) { case PSEV_10MS_TIMER: @@ -938,8 +953,8 @@ isar_pump_statev_modem(struct BCState *b } } -static inline void -ll_deliver_faxstat(struct BCState *bcs, u8 status) +static void +ll_deliver_faxstat(struct BCState *bcs, u_char status) { isdn_ctrl ic; struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; @@ -954,10 +969,10 @@ ll_deliver_faxstat(struct BCState *bcs, } static void -isar_pump_statev_fax(struct BCState *bcs, u8 devt) { +isar_pump_statev_fax(struct BCState *bcs, u_char devt) { struct IsdnCardState *cs = bcs->cs; - u8 dps = SET_DPS(bcs->hw.isar.dpath); - u8 p1; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char p1; switch(devt) { case PSEV_10MS_TIMER: @@ -1041,7 +1056,7 @@ isar_pump_statev_fax(struct BCState *bcs &bcs->Flag); add_timer(&bcs->hw.isar.ftimer); } else { - sched_b_event(bcs, B_LL_CONNECT); + schedule_event(bcs, B_LL_CONNECT); } } else { if (cs->debug & L1_DEB_WARN) @@ -1057,19 +1072,22 @@ isar_pump_statev_fax(struct BCState *bcs if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev RSP_DISC"); if (bcs->hw.isar.state == STFAX_ESCAPE) { + p1 = 5; switch(bcs->hw.isar.newcmd) { case 0: bcs->hw.isar.state = STFAX_READY; break; - case PCTRL_CMD_FTH: case PCTRL_CMD_FTM: - p1 = 10; + p1 = 2; + case PCTRL_CMD_FTH: sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_SILON, 1, &p1); bcs->hw.isar.state = STFAX_SILDET; break; - case PCTRL_CMD_FRH: case PCTRL_CMD_FRM: + if (frm_extra_delay) + mdelay(frm_extra_delay); + case PCTRL_CMD_FRH: p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; bcs->hw.isar.newmod = 0; bcs->hw.isar.cmd = bcs->hw.isar.newcmd; @@ -1086,10 +1104,10 @@ isar_pump_statev_fax(struct BCState *bcs } } else if (bcs->hw.isar.state == STFAX_ACTIV) { if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) { - sched_b_event(bcs, B_LL_OK); + schedule_event(bcs, B_LL_OK); } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { send_DLE_ETX(bcs); - sched_b_event(bcs, B_LL_NOCARRIER); + schedule_event(bcs, B_LL_NOCARRIER); } else { ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); } @@ -1156,11 +1174,11 @@ isar_int_main(struct IsdnCardState *cs) } else { debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; case ISAR_IIS_GSTEV: - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); ireg->bstat |= ireg->cmsb; check_send(cs, ireg->cmsb); break; @@ -1176,15 +1194,18 @@ isar_int_main(struct IsdnCardState *cs) if (cs->debug & L1_DEB_WARN) debugl1(cs, "Buffer STEV dpath%d msb(%x)", ireg->iis>>6, ireg->cmsb); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); break; case ISAR_IIS_PSTEV: if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - rcv_mbox(cs, ireg, (u8 *)ireg->par); + rcv_mbox(cs, ireg, (u_char *)ireg->par); if (bcs->mode == L1_MODE_V32) { isar_pump_statev_modem(bcs, ireg->cmsb); } else if (bcs->mode == L1_MODE_FAX) { isar_pump_statev_fax(bcs, ireg->cmsb); + } else if (ireg->cmsb == PSEV_10MS_TIMER) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev TIMER"); } else { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar IIS_PSTEV pmode %d stat %x", @@ -1193,30 +1214,30 @@ isar_int_main(struct IsdnCardState *cs) } else { debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; case ISAR_IIS_PSTRSP: if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - rcv_mbox(cs, ireg, (u8 *)ireg->par); + rcv_mbox(cs, ireg, (u_char *)ireg->par); isar_pump_status_rsp(bcs, ireg); } else { debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - isar_write_reg(cs, 1, ISAR_IIA, 0); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; case ISAR_IIS_DIAG: case ISAR_IIS_BSTRSP: case ISAR_IIS_IOM2RSP: - rcv_mbox(cs, ireg, (u8 *)ireg->par); + rcv_mbox(cs, ireg, (u_char *)ireg->par); if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO)) == L1_DEB_HSCX) { - u8 *tp=debbuf; + u_char *tp=debbuf; tp += sprintf(debbuf, "msg iis(%x) msb(%x)", ireg->iis, ireg->cmsb); - QuickHex(tp, (u8 *)ireg->par, ireg->clsb); + QuickHex(tp, (u_char *)ireg->par, ireg->clsb); debugl1(cs, debbuf); } break; @@ -1242,15 +1263,18 @@ ftimer_handler(struct BCState *bcs) { bcs->Flag); test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag); if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) { - sched_b_event(bcs, B_LL_CONNECT); + schedule_event(bcs, B_LL_CONNECT); + } + if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) { + schedule_event(bcs, B_LL_OK); } } static void setup_pump(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - u8 dps = SET_DPS(bcs->hw.isar.dpath); - u8 ctrl, param[6]; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char ctrl, param[6]; switch (bcs->mode) { case L1_MODE_NULL: @@ -1266,7 +1290,7 @@ setup_pump(struct BCState *bcs) { } else { param[5] = PV32P6_ATN; } - param[0] = 6; /* 6 db */ + param[0] = para_TOA; /* 6 db */ param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; @@ -1282,7 +1306,7 @@ setup_pump(struct BCState *bcs) { } else { param[1] = PFAXP2_ATN; } - param[0] = 6; /* 6 db */ + param[0] = para_TOA; /* 6 db */ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); bcs->hw.isar.state = STFAX_NULL; bcs->hw.isar.newcmd = 0; @@ -1298,8 +1322,8 @@ setup_pump(struct BCState *bcs) { static void setup_sart(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - u8 dps = SET_DPS(bcs->hw.isar.dpath); - u8 ctrl, param[2]; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char ctrl, param[2]; switch (bcs->mode) { case L1_MODE_NULL: @@ -1311,7 +1335,6 @@ setup_sart(struct BCState *bcs) { "\0\0"); break; case L1_MODE_HDLC: - case L1_MODE_FAX: param[0] = 0; sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param); @@ -1323,6 +1346,9 @@ setup_sart(struct BCState *bcs) { sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); break; + case L1_MODE_FAX: + /* SART must not configured with FAX */ + break; } udelay(1000); sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); @@ -1332,8 +1358,8 @@ setup_sart(struct BCState *bcs) { static void setup_iom2(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - u8 dps = SET_DPS(bcs->hw.isar.dpath); - u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0}; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0}; if (bcs->channel) msg[1] = msg[3] = 1; @@ -1418,14 +1444,15 @@ modeisar(struct BCState *bcs, int mode, } static void -isar_pump_cmd(struct BCState *bcs, u8 cmd, u8 para) +isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) { struct IsdnCardState *cs = bcs->cs; - u8 dps = SET_DPS(bcs->hw.isar.dpath); - u8 ctrl = 0, nom = 0, p1 = 0; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char ctrl = 0, nom = 0, p1 = 0; switch(cmd) { case ISDN_FAX_CLASS1_FTM: + test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); if (bcs->hw.isar.state == STFAX_READY) { p1 = para; ctrl = PCTRL_CMD_FTM; @@ -1449,6 +1476,7 @@ isar_pump_cmd(struct BCState *bcs, u8 cm } break; case ISDN_FAX_CLASS1_FTH: + test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); if (bcs->hw.isar.state == STFAX_READY) { p1 = para; ctrl = PCTRL_CMD_FTH; @@ -1472,6 +1500,7 @@ isar_pump_cmd(struct BCState *bcs, u8 cm } break; case ISDN_FAX_CLASS1_FRM: + test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); if (bcs->hw.isar.state == STFAX_READY) { p1 = para; ctrl = PCTRL_CMD_FRM; @@ -1495,6 +1524,7 @@ isar_pump_cmd(struct BCState *bcs, u8 cm } break; case ISDN_FAX_CLASS1_FRH: + test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag); if (bcs->hw.isar.state == STFAX_READY) { p1 = para; ctrl = PCTRL_CMD_FRH; @@ -1517,15 +1547,20 @@ isar_pump_cmd(struct BCState *bcs, u8 cm bcs->hw.isar.state = STFAX_ESCAPE; } break; + case ISDN_FAXPUMP_HALT: + bcs->hw.isar.state = STFAX_NULL; + nom = 0; + ctrl = PCTRL_CMD_HALT; + break; } if (ctrl) sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); } void -__isar_setup(struct IsdnCardState *cs) +isar_setup(struct IsdnCardState *cs) { - u8 msg; + u_char msg; int i; /* Dpath 1, 2 */ @@ -1538,57 +1573,105 @@ __isar_setup(struct IsdnCardState *cs) cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; modeisar(&cs->bcs[i], 0, 0); - INIT_WORK(&cs->bcs[i].work, isar_bh, &cs->bcs[i]); + INIT_WORK(&cs->bcs[i].tqueue, (void *)(void *) isar_bh, &cs->bcs[i]); } } void isar_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; + int ret; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "DRQ set BC_FLG_BUSY"); + bcs->hw.isar.txcnt = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n"); + } else { + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "PUI set BC_FLG_BUSY"); + bcs->tx_skb = skb; + bcs->hw.isar.txcnt = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - st->l1.bcs->hw.isar.conmsg[0] = 0; + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + bcs->hw.isar.conmsg[0] = 0; if (test_bit(FLG_ORIG, &st->l2.flag)) - test_and_set_bit(BC_FLG_ORIG, &st->l1.bcs->Flag); + test_and_set_bit(BC_FLG_ORIG, &bcs->Flag); else - test_and_clear_bit(BC_FLG_ORIG, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_ORIG, &bcs->Flag); switch(st->l1.mode) { case L1_MODE_TRANS: case L1_MODE_HDLC: - if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc)) + ret = modeisar(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + if (ret) l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); else l1_msg_b(st, PH_ACTIVATE | REQUEST, arg); break; case L1_MODE_V32: case L1_MODE_FAX: - if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc)) + ret = modeisar(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + if (ret) l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); break; + default: + spin_unlock_irqrestore(&bcs->cs->lock, flags); + break; } break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - if (st->l1.bcs->cs->debug & L1_DEB_HSCX) - debugl1(st->l1.bcs->cs, "PDAC clear BC_FLG_BUSY"); - modeisar(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + switch(st->l1.mode) { + case L1_MODE_TRANS: + case L1_MODE_HDLC: + case L1_MODE_V32: + break; + case L1_MODE_FAX: + isar_pump_cmd(bcs, ISDN_FAXPUMP_HALT, 0); + break; + } + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "PDAC clear BC_FLG_BUSY"); + modeisar(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -1634,9 +1717,6 @@ open_isarstate(struct IsdnCardState *cs, bcs->event = 0; bcs->hw.isar.rcvidx = 0; bcs->tx_cnt = 0; - bcs->hw.isar.ftimer.function = (void *) ftimer_handler; - bcs->hw.isar.ftimer.data = (long) bcs; - init_timer(&bcs->hw.isar.ftimer); return (0); } @@ -1647,7 +1727,7 @@ setstack_isar(struct PStack *st, struct if (open_isarstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = isar_l2l1; + st->l2.l2l1 = isar_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -1674,6 +1754,51 @@ isar_auxcmd(struct IsdnCardState *cs, is test_and_set_bit(BC_FLG_DLEETX, &bcs->Flag); break; + case ISDN_FAX_CLASS1_FTS: + if (ic->parm.aux.subcmd == AT_QUERY) { + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK; + cs->iif.statcallb(ic); + return(0); + } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { + strcpy(ic->parm.aux.para, "0-255"); + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; + cs->iif.statcallb(ic); + return(0); + } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_auxcmd %s=%d", + FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]); + if (bcs->hw.isar.state == STFAX_READY) { + if (! ic->parm.aux.para[0]) { + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK; + cs->iif.statcallb(ic); + return(0); + } + if (! test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) { + /* n*10 ms */ + bcs->hw.isar.ftimer.expires = + jiffies + ((ic->parm.aux.para[0] * 10 * HZ)/1000); + test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag); + add_timer(&bcs->hw.isar.ftimer); + return(0); + } else { + if (cs->debug) + debugl1(cs, "isar FTS=%d and FTI busy", + ic->parm.aux.para[0]); + } + } else { + if (cs->debug) + debugl1(cs, "isar FTS=%d and isar.state not ready(%x)", + ic->parm.aux.para[0],bcs->hw.isar.state); + } + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; + cs->iif.statcallb(ic); + } + break; case ISDN_FAX_CLASS1_FRM: case ISDN_FAX_CLASS1_FRH: case ISDN_FAX_CLASS1_FTM: @@ -1686,16 +1811,24 @@ isar_auxcmd(struct IsdnCardState *cs, is cs->iif.statcallb(ic); return(0); } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { - strcpy(ic->parm.aux.para, faxmodulation_s); + char *p = ic->parm.aux.para; + for(i=0;icommand = ISDN_STAT_FAXIND; ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; cs->iif.statcallb(ic); return(0); } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_auxcmd %s=%d", + FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]); for(i=0;iparm.aux.para[0]) break; - if ((FAXMODCNT > i) && + if ((i < FAXMODCNT) && ((1<Flag)) { isar_pump_cmd(bcs, ic->parm.aux.cmd, @@ -1713,16 +1846,36 @@ isar_auxcmd(struct IsdnCardState *cs, is break; case (ISDN_CMD_IOCTL): switch (ic->arg) { - case (9): /* load firmware */ + case 9: /* load firmware */ features = ISDN_FEATURE_L2_MODEM | ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_FCLASS1; memcpy(&adr, ic->parm.num, sizeof(ulong)); - if (isar_load_firmware(cs, (u8 *)adr)) + if (isar_load_firmware(cs, (u_char *)adr)) return(1); else ll_run(cs, features); break; + case 20: + features = *(unsigned int *) ic->parm.num; + printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n", + modmask, features); + modmask = features; + break; + case 21: + features = *(unsigned int *) ic->parm.num; + printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n", + frm_extra_delay, features); + if (features >= 0) + frm_extra_delay = features; + break; + case 22: + features = *(unsigned int *) ic->parm.num; + printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n", + para_TOA, features); + if (features >= 0 && features < 32) + para_TOA = features; + break; default: printk(KERN_DEBUG "HiSax: invalid ioctl %d\n", (int) ic->arg); @@ -1735,21 +1888,17 @@ isar_auxcmd(struct IsdnCardState *cs, is return(0); } -static struct bc_l1_ops isar_l1_ops = { - .fill_fifo = isar_fill_fifo, - .open = setstack_isar, - .close = close_isarstate, -}; - void __devinit initisar(struct IsdnCardState *cs) { - cs->bc_l1_ops = &isar_l1_ops; -} - -int -isar_setup(struct IsdnCardState *cs, struct bc_hw_ops *isar_ops) -{ - cs->bc_hw_ops = isar_ops; - return ISARVersion(cs, "HiSax:"); + cs->bcs[0].BC_SetStack = setstack_isar; + cs->bcs[1].BC_SetStack = setstack_isar; + cs->bcs[0].BC_Close = close_isarstate; + cs->bcs[1].BC_Close = close_isarstate; + cs->bcs[0].hw.isar.ftimer.function = (void *) ftimer_handler; + cs->bcs[0].hw.isar.ftimer.data = (long) &cs->bcs[0]; + init_timer(&cs->bcs[0].hw.isar.ftimer); + cs->bcs[1].hw.isar.ftimer.function = (void *) ftimer_handler; + cs->bcs[1].hw.isar.ftimer.data = (long) &cs->bcs[1]; + init_timer(&cs->bcs[1].hw.isar.ftimer); } diff -puN drivers/isdn/hisax/isar.h~i4l drivers/isdn/hisax/isar.h --- 25/drivers/isdn/hisax/isar.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isar.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isar.h,v 1.9.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $ * * ISAR (Siemens PSB 7110) specific defines * @@ -28,6 +28,8 @@ #define ISAR_HIS_FIRM 0x1e #define ISAR_HIS_STDSP 0x08 #define ISAR_HIS_DIAG 0x05 +#define ISAR_HIS_WAITSTATE 0x27 +#define ISAR_HIS_TIMERIRQ 0x25 #define ISAR_HIS_P0CFG 0x3c #define ISAR_HIS_P12CFG 0x24 #define ISAR_HIS_SARTCFG 0x25 @@ -43,6 +45,10 @@ #define ISAR_HIS_DPS2 0x80 #define SET_DPS(x) ((x<<6) & 0xc0) +#define ISAR_CMD_TIMERIRQ_OFF 0x20 +#define ISAR_CMD_TIMERIRQ_ON 0x21 + + #define ISAR_IIS_MSCMSD 0x3f #define ISAR_IIS_VNR 0x15 #define ISAR_IIS_DKEY 0x03 @@ -207,8 +213,10 @@ #define STFAX_ESCAPE 5 #define STFAX_SILDET 6 +#define ISDN_FAXPUMP_HALT 100 + +extern int ISARVersion(struct IsdnCardState *cs, char *s); extern void isar_int_main(struct IsdnCardState *cs); extern void initisar(struct IsdnCardState *cs); extern void isar_fill_fifo(struct BCState *bcs); extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic); -extern int isar_setup(struct IsdnCardState *cs, struct bc_hw_ops *isar_ops); diff -puN /dev/null drivers/isdn/hisax/isdnhdlc.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/isdn/hisax/isdnhdlc.c 2004-02-09 22:19:20.000000000 -0800 @@ -0,0 +1,669 @@ +/* + * isdnhdlc.c -- General purpose ISDN HDLC decoder. + * + *Copyright (C) 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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 of the License, 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. + */ + +#include +#include +#include "isdnhdlc.h" + +/*-------------------------------------------------------------------*/ + +MODULE_AUTHOR("Wolfgang Mües , " + "Frode Isaksen , " + "Kai Germaschewski "); +MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); +MODULE_LICENSE("GPL"); + +/*-------------------------------------------------------------------*/ + +/* bit swap table. + * Very handy for devices with different bit order, + * and neccessary for each transparent B-channel access for all + * devices which works with this HDLC decoder without bit reversal. + */ +const unsigned char isdnhdlc_bit_rev_tab[256] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF +}; + +/* Table for CRC16. Internal used only. */ +static const unsigned short int crc16_tab[] = { + 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, + 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, + 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, + 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, + 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, + 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, + 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, + 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, + 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, + 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, + 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, + 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, + 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, + 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, + 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, + 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, + 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, + 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, + 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, + 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, + 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, + 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, + 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, + 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, + 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, + 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, + 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, + 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, + 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, + 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, + 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, + 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 +}; + + +enum { + HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, + HDLC_GET_DATA,HDLC_FAST_FLAG +}; + +enum { + HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, + HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, + HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, + HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED +}; + +void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->state = HDLC_GET_DATA; + hdlc->do_adapt56 = do_adapt56; + hdlc->dchannel = 0; + hdlc->crc = 0; + hdlc->cbin = 0; + hdlc->shift_reg = 0; + hdlc->ffvalue = 0; + hdlc->dstpos = 0; +} + +void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->do_closing = 0; + hdlc->ffvalue = 0; + if (is_d_channel) { + hdlc->dchannel = 1; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + hdlc->dchannel = 0; + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->ffvalue = 0x7e; + } + hdlc->cbin = 0x7e; + hdlc->bit_shift = 0; + if(do_adapt56){ + hdlc->do_adapt56 = 1; + hdlc->data_bits = 0; + hdlc->state = HDLC_SENDFLAG_B0; + } else { + hdlc->do_adapt56 = 0; + hdlc->data_bits = 8; + } + hdlc->shift_reg = 0; +} + +/* + isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. + + The source buffer is scanned for valid HDLC frames looking for + flags (01111110) to indicate the start of a frame. If the start of + the frame is found, the bit stuffing is removed (0 after 5 1's). + When a new flag is found, the complete frame has been received + and the CRC is checked. + If a valid frame is found, the function returns the frame length + excluding the CRC with the bit HDLC_END_OF_FRAME set. + If the beginning of a valid frame is found, the function returns + the length. + If a framing error is found (too many 1s and not a flag) the function + returns the length with the bit HDLC_FRAMING_ERROR set. + If a CRC error is found the function returns the length with the + bit HDLC_CRC_ERROR set. + If the frame length exceeds the destination buffer size, the function + returns the length with the bit HDLC_LENGTH_ERROR set. + + src - source buffer + slen - source buffer length + count - number of bytes removed (decoded) from the source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of decoded bytes in the destination buffer and status + flag. + */ +int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, + int slen, int *count, unsigned char *dst, int dsize) +{ + int status=0; + + static const unsigned char fast_flag[]={ + 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + }; + + static const unsigned char fast_flag_value[]={ + 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + }; + + static const unsigned char fast_abort[]={ + 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + }; + + *count = slen; + + while(slen > 0){ + if(hdlc->bit_shift==0){ + hdlc->cbin = *src++; + slen--; + hdlc->bit_shift = 8; + if(hdlc->do_adapt56){ + hdlc->bit_shift --; + } + } + + switch(hdlc->state){ + case STOPPED: + return 0; + case HDLC_FAST_IDLE: + if(hdlc->cbin == 0xff){ + hdlc->bit_shift = 0; + break; + } + hdlc->state = HDLC_GET_FLAG_B0; + hdlc->hdlc_bits1 = 0; + hdlc->bit_shift = 8; + break; + case HDLC_GET_FLAG_B0: + if(!(hdlc->cbin & 0x80)) { + hdlc->state = HDLC_GETFLAG_B1A6; + hdlc->hdlc_bits1 = 0; + } else { + if(!hdlc->do_adapt56){ + if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + hdlc->state = HDLC_FAST_IDLE; + } + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B1A6: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + if(hdlc->hdlc_bits1==6){ + hdlc->state = HDLC_GETFLAG_B7; + } + } else { + hdlc->hdlc_bits1 = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B7: + if(hdlc->cbin & 0x80) { + hdlc->state = HDLC_GET_FLAG_B0; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->data_received = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GET_DATA: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + switch(hdlc->hdlc_bits1){ + case 6: + break; + case 7: + if(hdlc->data_received) { + // bad frame + status = -HDLC_FRAMING_ERROR; + } + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=1; + break; + } + } else { + hdlc->state = HDLC_GET_FLAG_B0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->shift_reg |= 0x80; + hdlc->data_bits++; + break; + } + } else { + switch(hdlc->hdlc_bits1){ + case 5: + break; + case 6: + if(hdlc->data_received){ + if (hdlc->dstpos < 2) { + status = -HDLC_FRAMING_ERROR; + } else if (hdlc->crc != 0xf0b8){ + // crc error + status = -HDLC_CRC_ERROR; + } else { + // remove CRC + hdlc->dstpos -= 2; + // good frame + status = hdlc->dstpos; + } + } + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->data_bits = 0; + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ + hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; + hdlc->state = HDLC_FAST_FLAG; + hdlc->ffbit_shift = hdlc->bit_shift; + hdlc->bit_shift = 1; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->data_bits++; + break; + } + hdlc->hdlc_bits1 = 0; + } + if (status) { + hdlc->dstpos = 0; + *count -= slen; + hdlc->cbin <<= 1; + hdlc->bit_shift--; + return status; + } + if(hdlc->data_bits==8){ + unsigned cval; + + hdlc->data_bits = 0; + hdlc->data_received = 1; + cval = (hdlc->crc^hdlc->shift_reg) & 0xff; + hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval]; + // good byte received + if (dsize--) { + dst[hdlc->dstpos++] = hdlc->shift_reg; + } else { + // frame too long + status = -HDLC_LENGTH_ERROR; + hdlc->dstpos = 0; + } + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_FAST_FLAG: + if(hdlc->cbin==hdlc->ffvalue){ + hdlc->bit_shift = 0; + break; + } else { + if(hdlc->cbin == 0xff){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=0; + } else if(hdlc->ffbit_shift==8){ + hdlc->state = HDLC_GETFLAG_B7; + break; + } else { + hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; + hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; + if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; + hdlc->data_bits = hdlc->ffbit_shift-1; + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } + break; + default: + break; + } + } + *count -= slen; + return 0; +} + +/* + isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. + + The bit stream starts with a beginning flag (01111110). After + that each byte is added to the bit stream with bit stuffing added + (0 after 5 1's). + When the last byte has been removed from the source buffer, the + CRC (2 bytes is added) and the frame terminates with the ending flag. + For the dchannel, the idle character (all 1's) is also added at the end. + If this function is called with empty source buffer (slen=0), flags or + idle character will be generated. + + src - source buffer + slen - source buffer length + count - number of bytes removed (encoded) from source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of encoded bytes in the destination buffer +*/ +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, + unsigned short slen, int *count, + unsigned char *dst, int dsize) +{ + static const unsigned char xfast_flag_value[] = { + 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + }; + + int len = 0; + + *count = slen; + + while (dsize > 0) { + if(hdlc->bit_shift==0){ + if(slen && !hdlc->do_closing){ + hdlc->shift_reg = *src++; + slen--; + if (slen == 0) + hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + hdlc->bit_shift = 8; + } else { + if(hdlc->state == HDLC_SEND_DATA){ + if(hdlc->data_received){ + hdlc->state = HDLC_SEND_CRC1; + hdlc->crc ^= 0xffff; + hdlc->bit_shift = 8; + hdlc->shift_reg = hdlc->crc & 0xff; + } else if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + } + } + + } + } + + switch(hdlc->state){ + case STOPPED: + while (dsize--) + *dst++ = 0xff; + + return dsize; + case HDLC_SEND_FAST_FLAG: + hdlc->do_closing = 0; + if(slen == 0){ + *dst++ = hdlc->ffvalue; + len++; + dsize--; + break; + } + if(hdlc->bit_shift==8){ + hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SENDFLAG_B0: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->hdlc_bits1 = 0; + hdlc->state = HDLC_SENDFLAG_B1A6; + break; + case HDLC_SENDFLAG_B1A6: + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->cbin++; + if(++hdlc->hdlc_bits1 == 6) + hdlc->state = HDLC_SENDFLAG_B7; + break; + case HDLC_SENDFLAG_B7: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(slen == 0){ + hdlc->state = HDLC_SENDFLAG_B0; + break; + } + if(hdlc->bit_shift==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SEND_FIRST_FLAG: + hdlc->data_received = 1; + if(hdlc->data_bits==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + break; + } + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->shift_reg & 0x01) + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + } + break; + case HDLC_SEND_DATA: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->bit_shift==8){ + unsigned cval; + + cval = (hdlc->crc^hdlc->shift_reg) & 0xff; + hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval]; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + break; + case HDLC_SEND_CRC1: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + hdlc->shift_reg = (hdlc->crc >> 8); + hdlc->state = HDLC_SEND_CRC2; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CRC2: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + hdlc->shift_reg = 0x7e; + hdlc->state = HDLC_SEND_CLOSING_FLAG; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CLOSING_FLAG: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->cbin++; + } + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; + if(hdlc->dchannel){ + hdlc->ffvalue = 0x7e; + hdlc->state = HDLC_SEND_IDLE1; + hdlc->bit_shift = 8-hdlc->data_bits; + if(hdlc->bit_shift==0) + hdlc->state = HDLC_SEND_FAST_IDLE; + } else { + if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->data_received = 0; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + hdlc->data_received = 0; + } + // Finished with this frame, send flags + if (dsize > 1) dsize = 1; + } + } + break; + case HDLC_SEND_IDLE1: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_FAST_IDLE; + hdlc->bit_shift = 0; + } + break; + case HDLC_SEND_FAST_IDLE: + hdlc->do_closing = 0; + hdlc->cbin = 0xff; + hdlc->data_bits = 8; + if(hdlc->bit_shift == 8){ + hdlc->cbin = 0x7e; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + *dst++ = hdlc->cbin; + hdlc->bit_shift = hdlc->data_bits = 0; + len++; + dsize = 0; + } + break; + default: + break; + } + if(hdlc->do_adapt56){ + if(hdlc->data_bits==7){ + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + } + } + if(hdlc->data_bits==8){ + *dst++ = hdlc->cbin; + hdlc->data_bits = 0; + len++; + dsize--; + } + } + *count -= slen; + + return len; +} + +EXPORT_SYMBOL(isdnhdlc_bit_rev_tab); +EXPORT_SYMBOL(isdnhdlc_rcv_init); +EXPORT_SYMBOL(isdnhdlc_decode); +EXPORT_SYMBOL(isdnhdlc_out_init); +EXPORT_SYMBOL(isdnhdlc_encode); diff -puN /dev/null drivers/isdn/hisax/isdnhdlc.h --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/isdn/hisax/isdnhdlc.h 2004-02-09 22:19:20.000000000 -0800 @@ -0,0 +1,72 @@ +/* + * isdnhdlc.h -- General purpose ISDN HDLC decoder. + * + * Implementation of a HDLC decoder/encoder in software. + * Neccessary because some ISDN devices don't have HDLC + * controllers. Also included: a bit reversal table. + * + *Copyright (C) 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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 of the License, 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. + */ + +#ifndef __ISDNHDLC_H__ +#define __ISDNHDLC_H__ + +struct isdnhdlc_vars { + int bit_shift; + int hdlc_bits1; + int data_bits; + int ffbit_shift; // encoding only + int state; + int dstpos; + + unsigned short crc; + + unsigned char cbin; + unsigned char shift_reg; + unsigned char ffvalue; + + int data_received:1; // set if transferring data + int dchannel:1; // set if D channel (send idle instead of flags) + int do_adapt56:1; // set if 56K adaptation + int do_closing:1; // set if in closing phase (need to send CRC + flag +}; + + +/* + The return value from isdnhdlc_decode is + the frame length, 0 if no complete frame was decoded, + or a negative error number +*/ +#define HDLC_FRAMING_ERROR 1 +#define HDLC_CRC_ERROR 2 +#define HDLC_LENGTH_ERROR 3 + +extern const unsigned char isdnhdlc_bit_rev_tab[256]; + +extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); + +extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, + unsigned char *dst, int dsize); + +extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); + +extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, + unsigned char *dst,int dsize); + +#endif /* __ISDNHDLC_H__ */ diff -puN drivers/isdn/hisax/isdnl1.c~i4l drivers/isdn/hisax/isdnl1.c --- 25/drivers/isdn/hisax/isdnl1.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isdnl1.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isdnl1.c,v 2.41.6.5 2001/09/23 22:24:49 kai Exp $ +/* $Id: isdnl1.c,v 2.46.2.4 2004/01/13 21:46:03 keil Exp $ * * common low level stuff for Siemens Chipsetbased isdn cards * @@ -18,7 +18,7 @@ * */ -const char *l1_revision = "$Revision: 2.41.6.5 $"; +const char *l1_revision = "$Revision: 2.46.2.4 $"; #include #include "hisax.h" @@ -126,7 +126,7 @@ static char *strL1Event[] = }; void -debugl1(struct IsdnCardState *cs, const char *fmt, ...) +debugl1(struct IsdnCardState *cs, char *fmt, ...) { va_list args; char tmp[8]; @@ -159,9 +159,9 @@ L1activated(struct IsdnCardState *cs) st = cs->stlist; while (st) { if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - L1L2(st, PH_ACTIVATE | CONFIRM, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else - L1L2(st, PH_ACTIVATE | INDICATION, NULL); + st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL); st = st->next; } } @@ -174,8 +174,8 @@ L1deactivated(struct IsdnCardState *cs) st = cs->stlist; while (st) { if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - L1L2(st, PH_PAUSE | CONFIRM, NULL); - L1L2(st, PH_DEACTIVATE | INDICATION, NULL); + st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); + st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL); st = st->next; } test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); @@ -190,12 +190,13 @@ DChannel_proc_xmt(struct IsdnCardState * return; stptr = cs->stlist; - while (stptr != NULL) + while (stptr != NULL) { if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) { - L1L2(stptr, PH_PULL | CONFIRM, NULL); + stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL); break; } else stptr = stptr->next; + } } void @@ -234,7 +235,7 @@ DChannel_proc_rcv(struct IsdnCardState * if (sapi == CTRL_SAPI) { /* sapi 0 */ while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) - L1L2(stptr, PH_DATA | INDICATION, nskb); + stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); stptr = stptr->next; @@ -253,7 +254,7 @@ DChannel_proc_rcv(struct IsdnCardState * found = 0; while (stptr != NULL) if (tei == stptr->l2.tei) { - L1L2(stptr, PH_DATA | INDICATION, skb); + stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); found = !0; break; } else @@ -276,10 +277,10 @@ BChannel_proc_xmt(struct BCState *bcs) } if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) - L1L2(st, PH_PULL | CONFIRM, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { - L2L1(st, PH_DEACTIVATE | CONFIRM, NULL); + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); } } } @@ -294,31 +295,19 @@ BChannel_proc_rcv(struct BCState *bcs) FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL); } while ((skb = skb_dequeue(&bcs->rqueue))) { - L1L2(bcs->st, PH_DATA | INDICATION, skb); - } -} - -static void -BChannel_proc_cmpl(struct BCState *bcs) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&bcs->cmpl_queue))) { - L1L2(bcs->st, PH_DATA | CONFIRM, skb); + bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb); } } void -BChannel_bh(void *data) +BChannel_bh(struct BCState *bcs) { - struct BCState *bcs = data; - + if (!bcs) + return; if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event)) BChannel_proc_rcv(bcs); if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event)) BChannel_proc_xmt(bcs); - if (test_and_clear_bit(B_CMPLREADY, &bcs->event)) - BChannel_proc_cmpl(bcs); } void @@ -350,21 +339,22 @@ HiSax_rmlist(struct IsdnCardState *cs, } void -init_bcstate(struct IsdnCardState *cs, - int bc) +init_bcstate(struct IsdnCardState *cs, int bc) { struct BCState *bcs = cs->bcs + bc; bcs->cs = cs; bcs->channel = bc; - INIT_WORK(&bcs->work, BChannel_bh, bcs); + INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs); + bcs->BC_SetStack = NULL; + bcs->BC_Close = NULL; bcs->Flag = 0; } #ifdef L2FRAME_DEBUG /* psa */ char * -l2cmd(u8 cmd) +l2cmd(u_char cmd) { switch (cmd & ~0x10) { case 1: @@ -398,7 +388,7 @@ l2cmd(u8 cmd) static char tmpdeb[32]; char * -l2frames(u8 * ptr) +l2frames(u_char * ptr) { switch (ptr[2] & ~0x10) { case 1: @@ -430,7 +420,7 @@ l2frames(u8 * ptr) void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir) { - u8 *ptr; + u_char *ptr; ptr = skb->data; @@ -724,7 +714,7 @@ l1b_timer_act(struct FsmInst *fi, int ev struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_ACTIV); - L1L2(st, PH_ACTIVATE | CONFIRM, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); } static void @@ -733,7 +723,7 @@ l1b_timer_deact(struct FsmInst *fi, int struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_NULL); - L2L1(st, PH_DEACTIVATE | CONFIRM, NULL); + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); } static struct FsmNode L1BFnList[] __initdata = @@ -808,7 +798,7 @@ dch_l2l1(struct PStack *st, int pr, void debugl1(cs, "PH_ACTIVATE_REQ %s", st->l1.l1m.fsm->strState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) - L1L2(st, PH_ACTIVATE | CONFIRM, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags); FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg); @@ -904,19 +894,9 @@ setstack_HiSax(struct PStack *st, struct setstack_tei(st); setstack_manager(st); st->l1.stlistp = &(cs->stlist); - st->l1.l2l1 = dch_l2l1; - if (cs->dc_l1_ops->open) - cs->dc_l1_ops->open(st, cs); -} - -void -dc_l1_init(struct IsdnCardState *cs, struct dc_l1_ops *ops) -{ - cs->dc_l1_ops = ops; - INIT_WORK(&cs->work, ops->bh_func, cs); - init_timer(&cs->dbusytimer); - cs->dbusytimer.function = (void *)(unsigned long) ops->dbusy_func; - cs->dbusytimer.data = (unsigned long) cs; + st->l2.l2l1 = dch_l2l1; + if (cs->setstack_d) + cs->setstack_d(st, cs); } void diff -puN drivers/isdn/hisax/isdnl1.h~i4l drivers/isdn/hisax/isdnl1.h --- 25/drivers/isdn/hisax/isdnl1.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isdnl1.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isdnl1.h,v 2.9.6.3 2001/09/23 22:24:49 kai Exp $ +/* $Id: isdnl1.h,v 2.12.2.2 2004/01/12 22:52:27 keil Exp $ * * Layer 1 defines * @@ -7,9 +7,6 @@ * */ -#ifndef __ISDNL1_H__ -#define __ISDNL1_H__ - #define D_RCVBUFREADY 0 #define D_XMTBUFREADY 1 #define D_L1STATECHANGE 2 @@ -20,578 +17,15 @@ #define D_TX_MON1 7 #define E_RCVBUFREADY 8 -#define B_RCVBUFREADY 0 -#define B_XMTBUFREADY 1 -#define B_CMPLREADY 2 - -#define B_LL_NOCARRIER 8 -#define B_LL_CONNECT 9 -#define B_LL_OK 10 +#define B_RCVBUFREADY 0 +#define B_XMTBUFREADY 1 -extern void debugl1(struct IsdnCardState *cs, const char *fmt, ...); +extern void debugl1(struct IsdnCardState *cs, char *fmt, ...); extern void DChannel_proc_xmt(struct IsdnCardState *cs); extern void DChannel_proc_rcv(struct IsdnCardState *cs); extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg); extern void l1_msg_b(struct PStack *st, int pr, void *arg); -void dc_l1_init(struct IsdnCardState *cs, struct dc_l1_ops *ops); - -static inline void -fill_fifo_b(struct BCState *bcs) -{ - bcs->cs->bc_l1_ops->fill_fifo(bcs); -} - -static inline void -fill_fifo_d(struct IsdnCardState *cs) -{ - cs->dc_l1_ops->fill_fifo(cs); -} - #ifdef L2FRAME_DEBUG extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); #endif - -static inline void -sched_b_event(struct BCState *bcs, int event) -{ - set_bit(event, &bcs->event); - schedule_work(&bcs->work); -} - -static inline void -sched_d_event(struct IsdnCardState *cs, int event) -{ - set_bit(event, &cs->event); - schedule_work(&cs->work); -} - -/* called with the card lock held */ -static inline void -xmit_complete_b(struct BCState *bcs) -{ - skb_queue_tail(&bcs->cmpl_queue, bcs->tx_skb); - sched_b_event(bcs, B_CMPLREADY); - bcs->tx_skb = NULL; -} - -/* called with the card lock held */ -static inline void -xmit_complete_d(struct IsdnCardState *cs) -{ - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_skb = NULL; -} - -/* called with the card lock held */ -static inline void -xmit_ready_b(struct BCState *bcs) -{ - bcs->tx_skb = skb_dequeue(&bcs->squeue); - if (bcs->tx_skb) { - bcs->count = 0; - set_bit(BC_FLG_BUSY, &bcs->Flag); - fill_fifo_b(bcs); - } else { - clear_bit(BC_FLG_BUSY, &bcs->Flag); - sched_b_event(bcs, B_XMTBUFREADY); - } -} - -/* called with the card lock held */ -static inline void -xmit_ready_d(struct IsdnCardState *cs) -{ - cs->tx_skb = skb_dequeue(&cs->sq); - if (cs->tx_skb) { - cs->tx_cnt = 0; - fill_fifo_d(cs); - } else { - sched_d_event(cs, D_XMTBUFREADY); - } -} - -static inline void -xmit_data_req_b(struct BCState *bcs, struct sk_buff *skb) -{ - struct IsdnCardState *cs = bcs->cs; - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->count = 0; - fill_fifo_b(bcs); - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -static inline void -xmit_data_req_d(struct IsdnCardState *cs, struct sk_buff *skb) -{ - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - fill_fifo_d(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -static inline void -xmit_pull_ind_b(struct BCState *bcs, struct sk_buff *skb) -{ - struct IsdnCardState *cs = bcs->cs; - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (bcs->tx_skb) { - WARN_ON(1); - } else { - set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->count = 0; - fill_fifo_b(bcs); - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -static inline void -xmit_pull_ind_d(struct IsdnCardState *cs, struct sk_buff *skb) -{ - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - WARN_ON(1); - } else { - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - cs->tx_skb = skb; - cs->tx_cnt = 0; - fill_fifo_d(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -/* If busy, the PH_PULL | CONFIRM scheduling is handled under - * the card lock by xmit_ready_b() above, so no race */ -static inline void -xmit_pull_req_b(struct PStack *st) -{ - struct BCState *bcs = st->l1.bcs; - struct IsdnCardState *cs = bcs->cs; - unsigned long flags; - int busy = 0; - - spin_lock_irqsave(&cs->lock, flags); - if (bcs->tx_skb) { - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - busy = 1; - } - spin_unlock_irqrestore(&cs->lock, flags); - if (!busy) - L1L2(st, PH_PULL | CONFIRM, NULL); -} - -/* If busy, the PH_PULL | CONFIRM scheduling is handled under - * the card lock by xmit_ready_d() above, so no race */ -static inline void -xmit_pull_req_d(struct PStack *st) -{ - struct IsdnCardState *cs = st->l1.hardware; - unsigned long flags; - int busy = 0; - -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - busy = 1; - } - spin_unlock_irqrestore(&cs->lock, flags); - if (!busy) - L1L2(st, PH_PULL | CONFIRM, NULL); -} - -/* called with the card lock held */ -static inline void -xmit_restart_b(struct BCState *bcs) -{ -#ifdef ERROR_STATISTIC - bcs->err_tx++; -#endif - if (!bcs->tx_skb) { - WARN_ON(1); - return; - } - skb_push(bcs->tx_skb, bcs->count); - bcs->tx_cnt += bcs->count; - bcs->count = 0; -} - -/* called with the card lock held */ -static inline void -xmit_restart_d(struct IsdnCardState *cs) -{ -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - if (!cs->tx_skb) { - WARN_ON(1); - return; - } - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; -} - -/* Useful for HSCX/ISAC work-alike's */ -/* ---------------------------------------------------------------------- */ - -/* XPR - transmit pool ready */ -/* called with the card lock held */ -static inline void -xmit_xpr_b(struct BCState *bcs) -{ - /* current frame? */ - if (bcs->tx_skb) { - /* last frame not done yet? */ - if (bcs->tx_skb->len) { - fill_fifo_b(bcs); - return; - } - xmit_complete_b(bcs); - bcs->count = 0; - } - xmit_ready_b(bcs); -} - -/* XPR - transmit pool ready */ -/* called with the card lock held */ -static inline void -xmit_xpr_d(struct IsdnCardState *cs) -{ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); - /* current frame? */ - if (cs->tx_skb) { - /* last frame not done yet? */ - if (cs->tx_skb->len) { - fill_fifo_d(cs); - return; - } - xmit_complete_d(cs); - cs->tx_cnt = 0; - } - xmit_ready_d(cs); -} - -/* XDU - transmit data underrun */ -/* called with the card lock held */ -static inline void -xmit_xdu_b(struct BCState *bcs, void (*reset_xmit)(struct BCState *bcs)) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX %c EXIR XDU", 'A' + bcs->channel); - - if (bcs->mode == L1_MODE_TRANS) { - fill_fifo_b(bcs); - } else { - xmit_restart_b(bcs); - reset_xmit(bcs); - } -} - -/* XDU - transmit data underrun */ -/* called with the card lock held */ -static inline void -xmit_xdu_d(struct IsdnCardState *cs, void (*reset_xmit)(struct IsdnCardState *cs)) -{ - printk(KERN_WARNING "HiSax: D XDU\n"); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "D XDU"); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); - - xmit_restart_d(cs); - if (reset_xmit) - reset_xmit(cs); -} - -static inline unsigned char * -xmit_fill_fifo_b(struct BCState *bcs, u_int fifo_size, int *count, int *more) -{ - struct IsdnCardState *cs = bcs->cs; - unsigned char *p; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, __FUNCTION__); - - if (!bcs->tx_skb || bcs->tx_skb->len <= 0) { - WARN_ON(1); - return NULL; - } - - *more = (bcs->mode == L1_MODE_TRANS); - if (bcs->tx_skb->len > fifo_size) { - *more = 1; - *count = fifo_size; - } else { - *count = bcs->tx_skb->len; - } - p = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, *count); - bcs->tx_cnt -= *count; - bcs->count += *count; - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "%s %c cnt %d", __FUNCTION__, - bcs->unit ? 'B' : 'A', *count); - QuickHex(t, p, *count); - debugl1(cs, bcs->blog); - } - return p; -} - -static inline unsigned char * -xmit_fill_fifo_d(struct IsdnCardState *cs, u_int fifo_size, int *count, int *more) -{ - unsigned char *p; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, __FUNCTION__); - - if (!cs->tx_skb || cs->tx_skb->len <= 0) { - WARN_ON(1); - return NULL; - } - - *more = 0; - if (cs->tx_skb->len > fifo_size) { - *more = 1; - *count = fifo_size; - } else { - *count = cs->tx_skb->len; - } - - p = cs->tx_skb->data; - skb_pull(cs->tx_skb, *count); - cs->tx_cnt += *count; - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "%s cnt %d", __FUNCTION__, *count); - QuickHex(t, p, *count); - debugl1(cs, cs->dlog); - } - return p; -} - -static inline void -recv_empty_fifo_d(struct IsdnCardState *cs, int count) -{ - u8 *p; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, __FUNCTION__); - - if (cs->rcvidx + count > MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "%s: incoming packet too large", __FUNCTION__); - cs->rcvidx = 0; - return; - } - p = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->dc_hw_ops->read_fifo(cs, p, count); - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "%s cnt %d", __FUNCTION__, count); - QuickHex(t, p, count); - debugl1(cs, cs->dlog); - } -} - -static inline void -recv_empty_fifo_b(struct BCState *bcs, int count) -{ - u8 *p; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, __FUNCTION__); - - if (bcs->rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "%s: incoming packet too large", __FUNCTION__); - bcs->rcvidx = 0; - return; - } - p = bcs->rcvbuf + bcs->rcvidx; - bcs->rcvidx += count; - cs->bc_hw_ops->read_fifo(cs, bcs->unit, p, count); - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "%s %c cnt %d", __FUNCTION__, - bcs->unit ? 'B' : 'A', count); - QuickHex(t, p, count); - debugl1(cs, bcs->blog); - } -} - -/* RME - receive message end */ -static inline void -recv_rme_d(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int count; - - count = cs->rcvidx - 1; - cs->rcvidx = 0; - if (count == 0) - return; - - skb = dev_alloc_skb(count); - if (!skb) { - printk(KERN_WARNING "HiSax: %s: out of memory\n", __FUNCTION__); - return; - } - memcpy(skb_put(skb, count), cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - sched_d_event(cs, D_RCVBUFREADY); -} - -static inline void -recv_rme_b(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - struct sk_buff *skb; - int count; - - count = bcs->rcvidx - 1; - bcs->rcvidx = 0; - if (count == 0) - return; - - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - - skb = dev_alloc_skb(count); - if (!skb) { - printk(KERN_WARNING "HiSax: %s: out of memory\n", __FUNCTION__); - return; - } - memcpy(skb_put(skb, count), bcs->rcvbuf, count); - skb_queue_tail(&bcs->rqueue, skb); - sched_b_event(bcs, B_RCVBUFREADY); -} - -/* RPF - receive pull full */ -static inline void -recv_rpf_b(struct BCState *bcs) -{ - if (bcs->mode != L1_MODE_TRANS) - return; - - recv_rme_b(bcs); -} - -static inline int -bc_open(struct BCState *bcs) -{ - if (test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) - return 0; - - bcs->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC); - if (!bcs->rcvbuf) - goto err; - - bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC); - if (!bcs->blog) - goto err_rcvbuf; - - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - skb_queue_head_init(&bcs->cmpl_queue); - - clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = NULL; - bcs->rcvidx = 0; - bcs->tx_cnt = 0; - bcs->event = 0; - - return 0; - - err_rcvbuf: - kfree(bcs->rcvbuf); - err: - clear_bit(BC_FLG_INIT, &bcs->Flag); - printk(KERN_WARNING "HiSax: %s: out of memory\n", __FUNCTION__); - return -ENOMEM;; -} - -static inline void -bc_close(struct BCState *bcs) -{ - if (!test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - kfree(bcs->rcvbuf); - bcs->rcvbuf = NULL; - - kfree(bcs->blog); - bcs->blog = NULL; - - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - skb_queue_purge(&bcs->cmpl_queue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - clear_bit(BC_FLG_BUSY, &bcs->Flag); - } -} - -#endif diff -puN drivers/isdn/hisax/isdnl2.c~i4l drivers/isdn/hisax/isdnl2.c --- 25/drivers/isdn/hisax/isdnl2.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isdnl2.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 2.25.6.4 2001/09/23 22:24:49 kai Exp $ +/* $Id: isdnl2.c,v 2.30.2.3 2004/01/13 14:31:25 keil Exp $ * * Author Karsten Keil * based on the teles driver from Jan den Ouden @@ -19,21 +19,21 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.25.6.4 $"; -static spinlock_t isdnl2_lock = SPIN_LOCK_UNLOCKED; +const char *l2_revision = "$Revision: 2.30.2.3 $"; + static void l2m_debug(struct FsmInst *fi, char *fmt, ...); static struct Fsm l2fsm; enum { - ST_L2_1, /* TEI unassigned */ - ST_L2_2, /* Assign awaiting TEI */ - ST_L2_3, /* Establish awaiting TEI */ - ST_L2_4, /* TEI assigned */ - ST_L2_5, /* Awaiting establishment */ - ST_L2_6, /* Awaiting release */ - ST_L2_7, /* Multiple frame established */ - ST_L2_8, /* Timer recovery */ + ST_L2_1, + ST_L2_2, + ST_L2_3, + ST_L2_4, + ST_L2_5, + ST_L2_6, + ST_L2_7, + ST_L2_8, }; #define L2_STATE_COUNT (ST_L2_8+1) @@ -103,7 +103,7 @@ static char *strL2Event[] = "EV_L2_FRAME_ERROR", }; -static u_int l2addrsize(struct Layer2 *l2); +static int l2addrsize(struct Layer2 *l2); static void set_peer_busy(struct Layer2 *l2) { @@ -178,23 +178,23 @@ clear_exception(struct Layer2 *l2) clear_peer_busy(l2); } -inline u_int +inline int l2headersize(struct Layer2 *l2, int ui) { return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1)); } -inline u_int +inline int l2addrsize(struct Layer2 *l2) { return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); } static int -sethdraddr(struct Layer2 *l2, u8 * header, int rsp) +sethdraddr(struct Layer2 *l2, u_char * header, int rsp) { - u8 *ptr = header; + u_char *ptr = header; int crbit = rsp; if (test_bit(FLG_LAPD, &l2->flag)) { @@ -218,37 +218,37 @@ enqueue_super(struct PStack *st, { if (test_bit(FLG_LAPB, &st->l2.flag)) st->l1.bcs->tx_cnt += skb->len; - L2L1(st, PH_DATA | REQUEST, skb); + st->l2.l2l1(st, PH_DATA | REQUEST, skb); } #define enqueue_ui(a, b) enqueue_super(a, b) inline int -IsUI(u8 * data) +IsUI(u_char * data) { return ((data[0] & 0xef) == UI); } inline int -IsUA(u8 * data) +IsUA(u_char * data) { return ((data[0] & 0xef) == UA); } inline int -IsDM(u8 * data) +IsDM(u_char * data) { return ((data[0] & 0xef) == DM); } inline int -IsDISC(u8 * data) +IsDISC(u_char * data) { return ((data[0] & 0xef) == DISC); } inline int -IsRR(u8 * data, struct PStack *st) +IsRR(u_char * data, struct PStack *st) { if (test_bit(FLG_MOD128, &st->l2.flag)) return (data[0] == RR); @@ -257,9 +257,9 @@ IsRR(u8 * data, struct PStack *st) } inline int -IsSFrame(u8 * data, struct PStack *st) +IsSFrame(u_char * data, struct PStack *st) { - register u8 d = *data; + register u_char d = *data; if (!test_bit(FLG_MOD128, &st->l2.flag)) d &= 0xf; @@ -267,27 +267,27 @@ IsSFrame(u8 * data, struct PStack *st) } inline int -IsSABME(u8 * data, struct PStack *st) +IsSABME(u_char * data, struct PStack *st) { - u8 d = data[0] & ~0x10; + u_char d = data[0] & ~0x10; return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM); } inline int -IsREJ(u8 * data, struct PStack *st) +IsREJ(u_char * data, struct PStack *st) { return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ); } inline int -IsFRMR(u8 * data) +IsFRMR(u_char * data) { return ((data[0] & 0xef) == FRMR); } inline int -IsRNR(u8 * data, struct PStack *st) +IsRNR(u_char * data, struct PStack *st) { return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR); } @@ -295,7 +295,7 @@ IsRNR(u8 * data, struct PStack *st) int iframe_error(struct PStack *st, struct sk_buff *skb) { - u_int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); + int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); int rsp = *skb->data & 0x2; if (test_bit(FLG_ORIG, &st->l2.flag)) @@ -360,8 +360,8 @@ UI_error(struct PStack *st, struct sk_bu int FRMR_error(struct PStack *st, struct sk_buff *skb) { - u_int headers = l2addrsize(&st->l2) + 1; - u8 *datap = skb->data + headers; + int headers = l2addrsize(&st->l2) + 1; + u_char *datap = skb->data + headers; int rsp = *skb->data & 0x2; if (test_bit(FLG_ORIG, &st->l2.flag)) @@ -403,27 +403,35 @@ static void setva(struct PStack *st, unsigned int nr) { struct Layer2 *l2 = &st->l2; - struct sk_buff *skb; + int len; + u_long flags; + spin_lock_irqsave(&l2->lock, flags); while (l2->va != nr) { (l2->va)++; if(test_bit(FLG_MOD128, &l2->flag)) l2->va %= 128; else l2->va %= 8; - skb = l2->windowar[l2->sow]; + len = l2->windowar[l2->sow]->len; + if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type) + len = -1; + dev_kfree_skb(l2->windowar[l2->sow]); l2->windowar[l2->sow] = NULL; l2->sow = (l2->sow + 1) % l2->window; - - L2L3(st, DL_DATA | CONFIRM, skb); + spin_unlock_irqrestore(&l2->lock, flags); + if (st->lli.l2writewakeup && (len >=0)) + st->lli.l2writewakeup(st, len); + spin_lock_irqsave(&l2->lock, flags); } + spin_unlock_irqrestore(&l2->lock, flags); } static void -send_uframe(struct PStack *st, u8 cmd, u8 cr) +send_uframe(struct PStack *st, u_char cmd, u_char cr) { struct sk_buff *skb; - u8 tmp[MAX_HEADER_LEN]; + u_char tmp[MAX_HEADER_LEN]; int i; i = sethdraddr(&st->l2, tmp, cr); @@ -436,7 +444,7 @@ send_uframe(struct PStack *st, u8 cmd, u enqueue_super(st, skb); } -inline u8 +inline u_char get_PollFlag(struct PStack * st, struct sk_buff * skb) { return (skb->data[l2addrsize(&(st->l2))] & 0x10); @@ -449,10 +457,10 @@ FreeSkb(struct sk_buff *skb) } -inline u8 +inline u_char get_PollFlagFree(struct PStack *st, struct sk_buff *skb) { - u8 PF; + u_char PF; PF = get_PollFlag(st, skb); FreeSkb(skb); @@ -490,22 +498,22 @@ st5_dl_release_l2l3(struct PStack *st) else pr = DL_RELEASE | INDICATION; - L2L3(st, pr, NULL); + st->l2.l2l3(st, pr, NULL); } inline void lapb_dl_release_l2l3(struct PStack *st, int f) { if (test_bit(FLG_LAPB, &st->l2.flag)) - L2L1(st, PH_DEACTIVATE | REQUEST, NULL); - L2L3(st, DL_RELEASE | f, NULL); + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | f, NULL); } static void establishlink(struct FsmInst *fi) { struct PStack *st = fi->userdata; - u8 cmd; + u_char cmd; clear_exception(&st->l2); st->l2.rc = 0; @@ -599,7 +607,7 @@ static void tx_ui(struct PStack *st) { struct sk_buff *skb; - u8 header[MAX_HEADER_LEN]; + u_char header[MAX_HEADER_LEN]; int i; i = sethdraddr(&(st->l2), header, CMD); @@ -627,7 +635,7 @@ l2_got_ui(struct FsmInst *fi, int event, struct sk_buff *skb = arg; skb_pull(skb, l2headersize(&st->l2, 1)); - L2L3(st, DL_UNIT_DATA | INDICATION, skb); + st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb); /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * in states 1-3 for broadcast */ @@ -669,7 +677,7 @@ l2_release(struct FsmInst *fi, int event { struct PStack *st = fi->userdata; - L2L3(st, DL_RELEASE | CONFIRM, NULL); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); } static void @@ -710,7 +718,7 @@ l2_start_multi(struct FsmInst *fi, int e FsmChangeState(fi, ST_L2_7); FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); - L2L3(st, DL_ESTABLISH | INDICATION, NULL); + st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); } static void @@ -759,11 +767,11 @@ l2_restart_multi(struct FsmInst *fi, int FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); if (est) - L2L3(st, DL_ESTABLISH | INDICATION, NULL); + st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); if ((ST_L2_7==state) || (ST_L2_8 == state)) if (skb_queue_len(&st->l2.i_queue) && cansend(st)) - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -816,10 +824,10 @@ l2_connected(struct FsmInst *fi, int eve FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4); if (pr != -1) - L2L3(st, pr, NULL); + st->l2.l2l3(st, pr, NULL); if (skb_queue_len(&st->l2.i_queue) && cansend(st)) - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -862,7 +870,7 @@ l2_st5_dm_release(struct FsmInst *fi, in if (!test_bit(FLG_L3_INIT, &st->l2.flag)) skb_queue_purge(&st->l2.i_queue); if (test_bit(FLG_LAPB, &st->l2.flag)) - L2L1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); st5_dl_release_l2l3(st); FsmChangeState(fi, ST_L2_4); } @@ -882,11 +890,11 @@ l2_st6_dm_release(struct FsmInst *fi, in } inline void -enquiry_cr(struct PStack *st, u8 typ, u8 cr, u8 pf) +enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) { struct sk_buff *skb; struct Layer2 *l2; - u8 tmp[MAX_HEADER_LEN]; + u_char tmp[MAX_HEADER_LEN]; int i; l2 = &st->l2; @@ -940,8 +948,10 @@ static void invoke_retransmission(struct PStack *st, unsigned int nr) { struct Layer2 *l2 = &st->l2; - unsigned int p1; + u_int p1; + u_long flags; + spin_lock_irqsave(&l2->lock, flags); if (l2->vs != nr) { while (l2->vs != nr) { (l2->vs)--; @@ -958,8 +968,11 @@ invoke_retransmission(struct PStack *st, skb_queue_head(&l2->i_queue, l2->windowar[p1]); l2->windowar[p1] = NULL; } - L2L1(st, PH_PULL | REQUEST, NULL); + spin_unlock_irqrestore(&l2->lock, flags); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); + return; } + spin_unlock_irqrestore(&l2->lock, flags); } static void @@ -1018,7 +1031,7 @@ l2_st7_got_super(struct FsmInst *fi, int restart_t200(st, 12); } if (skb_queue_len(&st->l2.i_queue) && (typ == RR)) - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); } @@ -1046,7 +1059,7 @@ l2_feed_i_pull(struct FsmInst *fi, int e if (test_bit(FLG_LAPB, &st->l2.flag)) st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); skb_queue_tail(&st->l2.i_queue, skb); - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -1066,8 +1079,8 @@ l2_got_iframe(struct FsmInst *fi, int ev struct PStack *st = fi->userdata; struct sk_buff *skb = arg; struct Layer2 *l2 = &(st->l2); - int PollFlag, i; - unsigned int nr, ns; + int PollFlag, ns, i; + unsigned int nr; i = l2addrsize(l2); if (test_bit(FLG_MOD128, &l2->flag)) { @@ -1095,7 +1108,7 @@ l2_got_iframe(struct FsmInst *fi, int ev else test_and_set_bit(FLG_ACK_PEND, &l2->flag); skb_pull(skb, l2headersize(l2, 0)); - L2L3(st, DL_DATA | INDICATION, skb); + st->l2.l2l3(st, DL_DATA | INDICATION, skb); } else { /* n(s)!=v(r) */ FreeSkb(skb); @@ -1124,7 +1137,7 @@ l2_got_iframe(struct FsmInst *fi, int ev } if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7)) - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) enquiry_cr(st, RR, RSP, 0); } @@ -1159,7 +1172,7 @@ l2_st5_tout_200(struct FsmInst *fi, int skb_queue_purge(&st->l2.i_queue); st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G'); if (test_bit(FLG_LAPB, &st->l2.flag)) - L2L1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); st5_dl_release_l2l3(st); } else { st->l2.rc++; @@ -1250,9 +1263,10 @@ l2_pull_iqueue(struct FsmInst *fi, int e struct PStack *st = fi->userdata; struct sk_buff *skb, *oskb; struct Layer2 *l2 = &st->l2; - u8 header[MAX_HEADER_LEN]; - int unsigned p1, i; - unsigned long flags; + u_char header[MAX_HEADER_LEN]; + int i; + int unsigned p1; + u_long flags; if (!cansend(st)) return; @@ -1261,7 +1275,7 @@ l2_pull_iqueue(struct FsmInst *fi, int e if (!skb) return; - spin_lock_irqsave(&isdnl2_lock, flags); + spin_lock_irqsave(&l2->lock, flags); if(test_bit(FLG_MOD128, &l2->flag)) p1 = (l2->vs - l2->va) % 128; else @@ -1284,8 +1298,7 @@ l2_pull_iqueue(struct FsmInst *fi, int e header[i++] = (l2->vr << 5) | (l2->vs << 1); l2->vs = (l2->vs + 1) % 8; } - spin_unlock_irqrestore(&isdnl2_lock, flags); - + spin_unlock_irqrestore(&l2->lock, flags); p1 = skb->data - skb->head; if (p1 >= i) memcpy(skb_push(skb, i), header, i); @@ -1298,14 +1311,14 @@ l2_pull_iqueue(struct FsmInst *fi, int e memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len); FreeSkb(oskb); } - L2L1(st, PH_PULL | INDICATION, skb); + st->l2.l2l1(st, PH_PULL | INDICATION, skb); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { FsmDelTimer(&st->l2.t203, 13); FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); } if (skb_queue_len(&l2->i_queue) && cansend(st)) - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -1351,7 +1364,7 @@ l2_st8_got_super(struct FsmInst *fi, int invoke_retransmission(st, nr); FsmChangeState(fi, ST_L2_7); if (skb_queue_len(&l2->i_queue) && cansend(st)) - L2L1(st, PH_PULL | REQUEST, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); } else { @@ -1398,7 +1411,7 @@ l2_st3_tei_remove(struct FsmInst *fi, in skb_queue_purge(&st->l2.ui_queue); st->l2.tei = -1; - L2L3(st, DL_RELEASE | INDICATION, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); FsmChangeState(fi, ST_L2_1); } @@ -1424,7 +1437,7 @@ l2_st6_tei_remove(struct FsmInst *fi, in skb_queue_purge(&st->l2.ui_queue); st->l2.tei = -1; stop_t200(st, 18); - L2L3(st, DL_RELEASE | CONFIRM, NULL); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); FsmChangeState(fi, ST_L2_1); } @@ -1439,23 +1452,23 @@ l2_tei_remove(struct FsmInst *fi, int ev st->l2.tei = -1; stop_t200(st, 17); FsmDelTimer(&st->l2.t203, 19); - L2L3(st, DL_RELEASE | INDICATION, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); FsmChangeState(fi, ST_L2_1); } static void -l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) +l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; skb_queue_purge(&st->l2.i_queue); skb_queue_purge(&st->l2.ui_queue); if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) - L2L3(st, DL_RELEASE | INDICATION, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); } static void -l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) +l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1468,18 +1481,18 @@ l2_st5_persistent_da(struct FsmInst *fi, } static void -l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) +l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; skb_queue_purge(&st->l2.ui_queue); stop_t200(st, 20); - L2L3(st, DL_RELEASE | CONFIRM, NULL); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); FsmChangeState(fi, ST_L2_4); } static void -l2_persistent_da(struct FsmInst *fi, int event, void *arg) +l2_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1488,7 +1501,7 @@ l2_persistent_da(struct FsmInst *fi, int freewin(st); stop_t200(st, 19); FsmDelTimer(&st->l2.t203, 19); - L2L3(st, DL_RELEASE | INDICATION, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); FsmChangeState(fi, ST_L2_4); } @@ -1614,14 +1627,14 @@ static struct FsmNode L2FnList[] __initd {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, + {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, + {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, + {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, + {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, + {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, + {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, }; #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) @@ -1630,8 +1643,8 @@ static void isdnl2_l1l2(struct PStack *st, int pr, void *arg) { struct sk_buff *skb = arg; - u8 *datap; - u_int ret = 1, len; + u_char *datap; + int ret = 1, len; int c = 0; switch (pr) { @@ -1682,9 +1695,6 @@ isdnl2_l1l2(struct PStack *st, int pr, v if (ret) FreeSkb(skb); break; - case (PH_DATA | CONFIRM): - dev_kfree_skb(skb); - break; case (PH_PULL | CONFIRM): FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); break; @@ -1736,12 +1746,12 @@ isdnl2_l3l2(struct PStack *st, int pr, v test_bit(FLG_ORIG, &st->l2.flag)) { test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag); } - L2L1(st, PH_ACTIVATE, NULL); + st->l2.l2l1(st, PH_ACTIVATE, NULL); } break; case (DL_RELEASE | REQUEST): if (test_bit(FLG_LAPB, &st->l2.flag)) { - L2L1(st, PH_DEACTIVATE, NULL); + st->l2.l2l1(st, PH_DEACTIVATE, NULL); } FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg); break; @@ -1781,8 +1791,9 @@ l2m_debug(struct FsmInst *fi, char *fmt, void setstack_isdnl2(struct PStack *st, char *debug_id) { - st->l2.l1l2 = isdnl2_l1l2; - st->l2.l3l2 = isdnl2_l3l2; + spin_lock_init(&st->l2.lock); + st->l1.l1l2 = isdnl2_l1l2; + st->l3.l3l2 = isdnl2_l3l2; skb_queue_head_init(&st->l2.i_queue); skb_queue_head_init(&st->l2.ui_queue); @@ -1810,13 +1821,13 @@ transl2_l3l2(struct PStack *st, int pr, switch (pr) { case (DL_DATA | REQUEST): case (DL_UNIT_DATA | REQUEST): - L2L1(st, PH_DATA | REQUEST, arg); + st->l2.l2l1(st, PH_DATA | REQUEST, arg); break; case (DL_ESTABLISH | REQUEST): - L2L1(st, PH_ACTIVATE | REQUEST, NULL); + st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); break; case (DL_RELEASE | REQUEST): - L2L1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); break; } } @@ -1824,7 +1835,7 @@ transl2_l3l2(struct PStack *st, int pr, void setstack_transl2(struct PStack *st) { - st->l2.l3l2 = transl2_l3l2; + st->l3.l3l2 = transl2_l3l2; } void diff -puN drivers/isdn/hisax/isdnl3.c~i4l drivers/isdn/hisax/isdnl3.c --- 25/drivers/isdn/hisax/isdnl3.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isdnl3.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isdnl3.c,v 2.17.6.5 2001/09/23 22:24:49 kai Exp $ +/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $ * * Author Karsten Keil * based on the teles driver from Jan den Ouden @@ -20,7 +20,7 @@ #include "isdnl3.h" #include -const char *l3_revision = "$Revision: 2.17.6.5 $"; +const char *l3_revision = "$Revision: 2.22.2.3 $"; static struct Fsm l3fsm; @@ -77,11 +77,11 @@ l3m_debug(struct FsmInst *fi, char *fmt, va_end(args); } -u8 * -findie(u8 * p, int size, u8 ie, int wanted_set) +u_char * +findie(u_char * p, int size, u_char ie, int wanted_set) { int l, codeset, maincodeset; - u8 *pend = p + size; + u_char *pend = p + size; /* skip protocol discriminator, callref and message type */ p++; @@ -123,7 +123,7 @@ findie(u8 * p, int size, u8 ie, int want } int -getcallref(u8 * p) +getcallref(u_char * p) { int l, cr = 0; @@ -162,7 +162,7 @@ newl3state(struct l3_process *pc, int st static void L3ExpireTimer(struct L3Timer *t) { - t->pc->st->l3.l4l3(t->pc->st, t->event, t->pc); + t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc); } void @@ -354,7 +354,7 @@ setstack_l3dc(struct PStack *st, struct st->l3.l3m.printdebug = l3m_debug; FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer); strcpy(st->l3.debug_id, "L3DC "); - st->l3.l4l3_proto = no_l3_proto_spec; + st->lli.l4l3_proto = no_l3_proto_spec; #ifdef CONFIG_HISAX_EURO if (st->protocol == ISDN_PTYPE_EURO) { @@ -372,13 +372,13 @@ setstack_l3dc(struct PStack *st, struct } else #endif if (st->protocol == ISDN_PTYPE_LEASED) { - st->l3.l4l3 = no_l3_proto; - st->l3.l2l3 = no_l3_proto; + st->lli.l4l3 = no_l3_proto; + st->l2.l2l3 = no_l3_proto; st->l3.l3ml3 = no_l3_proto; printk(KERN_INFO "HiSax: Leased line mode\n"); } else { - st->l3.l4l3 = no_l3_proto; - st->l3.l2l3 = no_l3_proto; + st->lli.l4l3 = no_l3_proto; + st->l2.l2l3 = no_l3_proto; st->l3.l3ml3 = no_l3_proto; sprintf(tmp, "protocol %s not supported", (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : @@ -392,7 +392,7 @@ setstack_l3dc(struct PStack *st, struct void isdnl3_trans(struct PStack *st, int pr, void *arg) { - L3L2(st, pr, arg); + st->l3.l3l2(st, pr, arg); } void @@ -423,7 +423,7 @@ setstack_l3bc(struct PStack *st, struct st->l3.l3m.userint = 0; st->l3.l3m.printdebug = l3m_debug; strcpy(st->l3.debug_id, "L3BC "); - st->l3.l4l3 = isdnl3_trans; + st->lli.l4l3 = isdnl3_trans; } #define DREL_TIMER_VALUE 40000 @@ -434,7 +434,7 @@ lc_activate(struct FsmInst *fi, int even struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT); - L3L2(st, DL_ESTABLISH | REQUEST, NULL); + st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -446,7 +446,7 @@ lc_connect(struct FsmInst *fi, int event FsmChangeState(fi, ST_L3_LC_ESTAB); while ((skb = skb_dequeue(&st->l3.squeue))) { - L3L2(st, DL_DATA | REQUEST, skb); + st->l3.l3l2(st, DL_DATA | REQUEST, skb); dequeued++; } if ((!st->l3.proc) && dequeued) { @@ -467,7 +467,7 @@ lc_connected(struct FsmInst *fi, int eve FsmDelTimer(&st->l3.l3m_timer, 51); FsmChangeState(fi, ST_L3_LC_ESTAB); while ((skb = skb_dequeue(&st->l3.squeue))) { - L3L2(st, DL_DATA | REQUEST, skb); + st->l3.l3l2(st, DL_DATA | REQUEST, skb); dequeued++; } if ((!st->l3.proc) && dequeued) { @@ -511,7 +511,7 @@ lc_release_req(struct FsmInst *fi, int e FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51); } else { FsmChangeState(fi, ST_L3_LC_REL_WAIT); - L3L2(st, DL_RELEASE | REQUEST, NULL); + st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL); } } @@ -564,7 +564,7 @@ l3_msg(struct PStack *st, int pr, void * switch (pr) { case (DL_DATA | REQUEST): if (st->l3.l3m.state == ST_L3_LC_ESTAB) { - L3L2(st, pr, arg); + st->l3.l3l2(st, pr, arg); } else { struct sk_buff *skb = arg; diff -puN drivers/isdn/hisax/isurf.c~i4l drivers/isdn/hisax/isurf.c --- 25/drivers/isdn/hisax/isurf.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/isurf.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isurf.c,v 1.10.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $ * * low level stuff for Siemens I-Surf/I-Talk cards * @@ -19,7 +19,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.10.6.2 $"; +static const char *ISurf_revision = "$Revision: 1.12.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -35,20 +35,20 @@ static const char *ISurf_revision = "$Re #define ISURF_IOMEM_SIZE 0x400 /* Interface functions */ -static u8 -ReadISAC(struct IsdnCardState *cs, u8 offset) +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { return (readb(cs->hw.isurf.isac + offset)); } static void -WriteISAC(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writeb(value, cs->hw.isurf.isac + offset); mb(); } static void -ReadISACfifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { register int i; for (i = 0; i < size; i++) @@ -56,7 +56,7 @@ ReadISACfifo(struct IsdnCardState *cs, u } static void -WriteISACfifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { register int i; for (i = 0; i < size; i++){ @@ -64,44 +64,33 @@ WriteISACfifo(struct IsdnCardState *cs, } } -static struct dc_hw_ops isac_ops = { - .read_reg = ReadISAC, - .write_reg = WriteISAC, - .read_fifo = ReadISACfifo, - .write_fifo = WriteISACfifo, -}; - /* ISAR access routines * mode = 0 access with IRQ on * mode = 1 access with IRQ off * mode = 2 access with IRQ off and using last offset */ -static u8 -ReadISAR(struct IsdnCardState *cs, int mode, u8 offset) +static u_char +ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) { return(readb(cs->hw.isurf.isar + offset)); } static void -WriteISAR(struct IsdnCardState *cs, int mode, u8 offset, u8 value) +WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) { writeb(value, cs->hw.isurf.isar + offset);mb(); } -static struct bc_hw_ops isar_ops = { - .read_reg = ReadISAR, - .write_reg = WriteISAR, -}; - static irqreturn_t isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; + u_char val; int cnt = 5; + u_long flags; - spin_lock(&cs->lock); + spin_lock_irqsave(&cs->lock, flags); val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); Start_ISAR: if (val & ISAR_IRQSTA) @@ -129,151 +118,190 @@ isurf_interrupt(int intno, void *dev_id, writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb(); writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb(); writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - spin_unlock(&cs->lock); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } +void +release_io_isurf(struct IsdnCardState *cs) +{ + release_region(cs->hw.isurf.reset, 1); + iounmap((unsigned char *)cs->hw.isurf.isar); + release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); +} + static void -reset_isurf(struct IsdnCardState *cs, u8 chips) +reset_isurf(struct IsdnCardState *cs, u_char chips) { printk(KERN_INFO "ISurf: resetting card\n"); byteout(cs->hw.isurf.reset, chips); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); + mdelay(10); byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); + mdelay(10); +} + +static int +ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + u_long flags; + + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_isurf(cs, ISURF_RESET); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_isurf(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + reset_isurf(cs, ISURF_RESET); + clear_pending_isac_ints(cs); + writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb(); + initisac(cs); + initisar(cs); + /* Reenable ISAC IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } static int isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { int ret; + u_long flags; if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) { ret = isar_auxcmd(cs, ic); + spin_lock_irqsave(&cs->lock, flags); if (!ret) { reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET); initisac(cs); + cs->writeisac(cs, ISAC_MASK, 0); + cs->writeisac(cs, ISAC_CMDR, 0x41); } + spin_unlock_irqrestore(&cs->lock, flags); return(ret); } return(isar_auxcmd(cs, ic)); } -static void -isurf_init(struct IsdnCardState *cs) -{ - writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); - initisac(cs); - initisar(cs); -} - -static int -isurf_reset(struct IsdnCardState *cs) -{ - reset_isurf(cs, ISURF_RESET); - return 0; -} - -static struct card_ops isurf_ops = { - .init = isurf_init, - .reset = isurf_reset, - .release = hisax_release_resources, - .irq_func = isurf_interrupt, -}; - #ifdef __ISAPNP__ -static struct pnp_card *pnp_surf __devinitdata = NULL; +static struct pnp_card *pnp_c __initdata = NULL; #endif -static int __init -isurf_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - unsigned long phymem; - - phymem = card->para[2]; - cs->hw.isurf.reset = card->para[1]; - cs->irq = card->para[0]; - - if (!request_io(&cs->rs, cs->hw.isurf.reset, 1, "isurf isdn")) - goto err; - - cs->hw.isurf.isar = request_mmio(&cs->rs, phymem, ISURF_IOMEM_SIZE, - "isurf iomem"); - if (!cs->hw.isurf.isar) - goto err; - - cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; - printk(KERN_INFO "ISurf: defined at 0x%x 0x%lx IRQ %d\n", - cs->hw.isurf.reset, phymem, cs->irq); - - cs->auxcmd = &isurf_auxcmd; - cs->card_ops = &isurf_ops; - cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; - cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; - reset_isurf(cs, ISURF_RESET); - __set_bit(HW_ISAR, &cs->HW_Flags); - isac_setup(cs, &isac_ops); - if (isar_setup(cs, &isar_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - int __init setup_isurf(struct IsdnCard *card) { + int ver; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, ISurf_revision); printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_ISURF) + return(0); + if (card->para[1] && card->para[2]) { + cs->hw.isurf.reset = card->para[1]; + cs->hw.isurf.phymem = card->para[2]; + cs->irq = card->para[0]; + } else { #ifdef __ISAPNP__ - if (!card->para[1] || !card->para[2]) { - struct pnp_card *pb; - struct pnp_dev *pd; - - card->cs->subtyp = 0; - if ((pb = pnp_find_card( - ISAPNP_VENDOR('S', 'I', 'E'), - ISAPNP_FUNCTION(0x0010), pnp_surf))) { - pnp_surf = pb; - pd = NULL; - if (!(pd = pnp_find_dev(pnp_surf, - ISAPNP_VENDOR('S', 'I', 'E'), - ISAPNP_FUNCTION(0x0010), pd))) { - printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n"); - return (0); - } - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "ISurfPnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "ISurfPnP: activate failed\n"); - pnp_device_detach(pd); - return 0; - } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0) || !pnp_port_valid(pd, 1)) { - printk(KERN_ERR "ISurfPnP:some resources are missing %ld/%lx/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0), pnp_port_start(pd, 1)); - pnp_device_detach(pd); + if (isapnp_present()) { + struct pnp_dev *pnp_d = NULL; + int err; + + cs->subtyp = 0; + if ((pnp_c = pnp_find_card( + ISAPNP_VENDOR('S', 'I', 'E'), + ISAPNP_FUNCTION(0x0010), pnp_c))) { + if (!(pnp_d = pnp_find_dev(pnp_c, + ISAPNP_VENDOR('S', 'I', 'E'), + ISAPNP_FUNCTION(0x0010), pnp_d))) { + printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n"); + return (0); + } + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + cs->hw.isurf.reset = pnp_port_start(pnp_d, 0); + cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1); + cs->irq = pnp_irq(pnp_d, 0); + if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) { + printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n", + cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem); + pnp_disable_dev(pnp_d); + return(0); + } + } else { + printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n"); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[2] = pnp_port_start(pd, 1); - card->para[0] = pnp_irq(pd, 0); } else { - printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n"); - return 0; + printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n"); + return(0); } - } +#else + printk(KERN_WARNING "HiSax: %s port/mem not set\n", + CardType[card->typ]); + return (0); #endif - if (isurf_probe(card->cs, card) < 0) - return 0; - return 1; + } + if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %x already in use\n", + CardType[card->typ], + cs->hw.isurf.reset); + return (0); + } + if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) { + printk(KERN_WARNING + "HiSax: %s memory region %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.isurf.phymem, + cs->hw.isurf.phymem + ISURF_IOMEM_SIZE); + release_region(cs->hw.isurf.reset, 1); + return (0); + } + cs->hw.isurf.isar = + (unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); + cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; + printk(KERN_INFO + "ISurf: defined at 0x%x 0x%lx IRQ %d\n", + cs->hw.isurf.reset, + cs->hw.isurf.phymem, + cs->irq); + + setup_isac(cs); + cs->cardmsg = &ISurf_card_msg; + cs->irq_func = &isurf_interrupt; + cs->auxcmd = &isurf_auxcmd; + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; + cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; + test_and_set_bit(HW_ISAR, &cs->HW_Flags); + ISACVersion(cs, "ISurf:"); + cs->BC_Read_Reg = &ReadISAR; + cs->BC_Write_Reg = &WriteISAR; + cs->BC_Send_Data = &isar_fill_fifo; + ver = ISARVersion(cs, "ISurf:"); + if (ver < 0) { + printk(KERN_WARNING + "ISurf: wrong ISAR version (ret = %d)\n", ver); + release_io_isurf(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/ix1_micro.c~i4l drivers/isdn/hisax/ix1_micro.c --- 25/drivers/isdn/hisax/ix1_micro.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/ix1_micro.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: ix1_micro.c,v 2.10.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for ITK ix1-micro Rev.2 isdn cards * derived from the original file teles3.c from Karsten Keil @@ -25,8 +25,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *ix1_revision = "$Revision: 2.10.6.2 $"; -static spinlock_t ix1_micro_lock = SPIN_LOCK_UNLOCKED; +const char *ix1_revision = "$Revision: 2.12.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -40,107 +39,137 @@ static spinlock_t ix1_micro_lock = SPIN_ #define TIMEOUT 50 -static inline u8 -readreg(struct IsdnCardState *cs, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&ix1_micro_lock, flags); - byteout(cs->hw.ix1.isac_ale, off); + byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&ix1_micro_lock, flags); return (ret); } static inline void -writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&ix1_micro_lock, flags); - byteout(cs->hw.ix1.isac_ale, off); - byteout(adr, data); - spin_unlock_irqrestore(&ix1_micro_lock, flags); + byteout(ale, off); + insb(adr, data, size); } + static inline void -readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - byteout(cs->hw.ix1.isac_ale, off); - insb(adr, data, size); + byteout(ale, off); + byteout(adr, data); } static inline void -writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - byteout(cs->hw.ix1.isac_ale, off); + byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.ix1.isac, offset); + return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.ix1.isac, offset, value); + writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.ix1.isac, 0, data, size); + readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.ix1.isac, 0, data, size); + writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs, cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.ix1.hscx_ale, + cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0))); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writereg(cs, cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); + writereg(cs->hw.ix1.hscx_ale, + cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - readfifo(cs, cs->hw.ix1.hscx, hscx ? 0x40 : 0, data, size); +#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \ + cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \ + cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data) + +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \ + cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \ + cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +void +release_io_ix1micro(struct IsdnCardState *cs) { - writefifo(cs, cs->hw.ix1.hscx, hscx ? 0x40 : 0, data, size); + if (cs->hw.ix1.cfg_reg) + release_region(cs->hw.ix1.cfg_reg, 4); } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static int +static void ix1_reset(struct IsdnCardState *cs) { int cnt; @@ -152,37 +181,32 @@ ix1_reset(struct IsdnCardState *cs) HZDELAY(1); /* wait >=10 ms */ } byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0); - return 0; } -static struct card_ops ix1_ops = { - .init = inithscxisac, - .reset = ix1_reset, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - -static int __init -ix1_probe(struct IsdnCardState *cs, struct IsdnCard *card) +static int +ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - cs->irq = card->para[0]; - cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; - cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; - cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; - cs->hw.ix1.cfg_reg = card->para[1]; - if (!request_io(&cs->rs, cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) - goto err; - - printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n", - CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg); - ix1_reset(cs); - cs->card_ops = &ix1_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + u_long flags; + + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + ix1_reset(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_ix1micro(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + ix1_reset(cs); + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } #ifdef __ISAPNP__ @@ -196,7 +220,7 @@ static struct isapnp_device_id itk_ids[] { 0, } }; -static struct isapnp_device_id *idev = &itk_ids[0]; +static struct isapnp_device_id *ipid __initdata = &itk_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif @@ -204,64 +228,91 @@ static struct pnp_card *pnp_c __devinitd int __init setup_ix1micro(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, ix1_revision); printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_IX1MICROR2) + return (0); - if (card->para[1]) { - if (ix1_probe(card->cs, card)) - return 0; - return 1; - } #ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; - - while(idev->card_vendor) { - if ((pb = pnp_find_card(idev->card_vendor, - idev->card_device, - pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - idev->vendor, - idev->function, - pd))) { + if (!card->para[1] && isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + printk(KERN_INFO "HiSax: %s detected\n", - (char *)idev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "ITK PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "ITK PnP: activate failed\n"); - pnp_device_detach(pd); - return 0; + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_port_valid(pd, 0) || !pnp_irq_valid(pd, 0)) { + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); - if (ix1_probe(card->cs, card)) - return 0; - return 1; + break; } else { printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); } } - idev++; - pnp_c=NULL; + ipid++; + pnp_c = NULL; } - if (!idev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); + return(0); } } #endif - return 0; + /* IO-Ports */ + cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; + cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; + cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; + cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; + cs->hw.ix1.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (cs->hw.ix1.cfg_reg) { + if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.ix1.cfg_reg, + cs->hw.ix1.cfg_reg + 4); + return (0); + } + } + printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n", + CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg); + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &ix1_card_msg; + cs->irq_func = &ix1micro_interrupt; + ISACVersion(cs, "ix1-Micro:"); + if (HscxVersion(cs, "ix1-Micro:")) { + printk(KERN_WARNING + "ix1-Micro: wrong HSCX versions check IO address\n"); + release_io_ix1micro(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/jade.c~i4l drivers/isdn/hisax/jade.c --- 25/drivers/isdn/hisax/jade.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/jade.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: jade.c,v 1.6.6.3 2001/09/23 22:24:49 kai Exp $ +/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $ * * JADE stuff (derived from original hscx.c) * @@ -18,38 +18,17 @@ #include "isdnl1.h" #include -static spinlock_t jade_lock = SPIN_LOCK_UNLOCKED; -static inline u8 -jade_read_reg(struct IsdnCardState *cs, int jade, u8 addr) -{ - return cs->bc_hw_ops->read_reg(cs, jade, addr); -} - -static inline void -jade_write_reg(struct IsdnCardState *cs, int jade, u8 addr, u8 val) -{ - cs->bc_hw_ops->write_reg(cs, jade, addr, val); -} - -static inline void -jade_write_fifo(struct BCState *bcs, u8 *p, int len) -{ - struct IsdnCardState *cs = bcs->cs; - - cs->bc_hw_ops->write_fifo(cs, bcs->unit, p, len); -} - -static int +int __init JadeVersion(struct IsdnCardState *cs, char *s) { int ver,i; int to = 50; - jade_write_reg(cs, -1, 0x50, 0x19); + cs->BC_Write_Reg(cs, -1, 0x50, 0x19); i=0; while (to) { udelay(1); - ver = jade_read_reg(cs, -1, 0x60); + ver = cs->BC_Read_Reg(cs, -1, 0x60); to--; if (ver) break; @@ -61,39 +40,36 @@ JadeVersion(struct IsdnCardState *cs, ch /* Wait for the JADE */ udelay(10); /* Read version */ - ver = jade_read_reg(cs, -1, 0x60); + ver = cs->BC_Read_Reg(cs, -1, 0x60); printk(KERN_INFO "%s JADE version: %d\n", s, ver); return (1); } /* Write to indirect accessible jade register set */ static void -jade_write_indirect(struct IsdnCardState *cs, u8 reg, u8 value) +jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value) { int to = 50; - unsigned long flags; - u8 ret; - spin_lock_irqsave(&jade_lock, flags); + u_char ret; + /* Write the data */ - jade_write_reg(cs, -1, COMM_JADE+1, value); + cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value); /* Say JADE we wanna write indirect reg 'reg' */ - jade_write_reg(cs, -1, COMM_JADE, reg); + cs->BC_Write_Reg(cs, -1, COMM_JADE, reg); to = 50; /* Wait for RDY goes high */ while (to) { udelay(1); - ret = jade_read_reg(cs, -1, COMM_JADE); + ret = cs->BC_Read_Reg(cs, -1, COMM_JADE); to--; if (ret & 1) /* Got acknowledge */ break; if (!to) { - spin_unlock_irqrestore(&jade_lock, flags); printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value); return; } } - spin_unlock_irqrestore(&jade_lock, flags); } @@ -102,7 +78,7 @@ void modejade(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - int jade = bcs->unit; + int jade = bcs->hw.hscx.hscx; if (cs->debug & L1_DEB_HSCX) { char tmp[40]; @@ -113,75 +89,103 @@ modejade(struct BCState *bcs, int mode, bcs->mode = mode; bcs->channel = bc; - jade_write_reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00)); - jade_write_reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF)); - jade_write_reg(cs, jade, jade_HDLC_CCR1, 0x00); + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00); jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08); jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08); jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00); jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00); - jade_write_reg(cs, jade, jade_HDLC_XCCR, 0x07); - jade_write_reg(cs, jade, jade_HDLC_RCCR, 0x07); + cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07); + cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07); if (bc == 0) { - jade_write_reg(cs, jade, jade_HDLC_TSAX, 0x00); - jade_write_reg(cs, jade, jade_HDLC_TSAR, 0x00); + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00); + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00); } else { - jade_write_reg(cs, jade, jade_HDLC_TSAX, 0x04); - jade_write_reg(cs, jade, jade_HDLC_TSAR, 0x04); + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04); + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04); } switch (mode) { case (L1_MODE_NULL): - jade_write_reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO); + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO); break; case (L1_MODE_TRANS): - jade_write_reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC)); break; case (L1_MODE_HDLC): - jade_write_reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC)); break; } if (mode) { - jade_write_reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC)); - jade_write_reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES); + cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES); /* Unmask ints */ - jade_write_reg(cs, jade, jade_HDLC_IMR, 0xF8); + cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8); } else /* Mask ints */ - jade_write_reg(cs, jade, jade_HDLC_IMR, 0x00); + cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00); } static void jade_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->hw.hscx.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n"); + } else { + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->hw.hscx.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - modejade(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + modejade(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - modejade(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + modejade(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -189,14 +193,53 @@ jade_l2l1(struct PStack *st, int pr, voi void close_jadestate(struct BCState *bcs) { - modejade(bcs, 0, bcs->channel); - bc_close(bcs); + modejade(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } } static int open_jadestate(struct IsdnCardState *cs, struct BCState *bcs) { - return bc_open(bcs);; + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hscx.rcvbuf\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hscx.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); } @@ -207,74 +250,69 @@ setstack_jade(struct PStack *st, struct if (open_jadestate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = jade_l2l1; + st->l2.l2l1 = jade_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); return (0); } -static void jade_fill_fifo(struct BCState *bcs); - -static struct bc_l1_ops jade_l1_ops = { - .fill_fifo = jade_fill_fifo, - .open = setstack_jade, - .close = close_jadestate, -}; - void __init -initjade(struct IsdnCardState *cs) +clear_pending_jade_ints(struct IsdnCardState *cs) { int val; + char tmp[64]; - cs->bc_l1_ops = &jade_l1_ops; - cs->bcs[0].unit = 0; - cs->bcs[1].unit = 1; - - jade_write_reg(cs, 0, jade_HDLC_IMR, 0x00); - jade_write_reg(cs, 1, jade_HDLC_IMR, 0x00); - - val = jade_read_reg(cs, 1, jade_HDLC_ISR); - debugl1(cs, "jade B ISTA %x", val); - val = jade_read_reg(cs, 0, jade_HDLC_ISR); - debugl1(cs, "jade A ISTA %x", val); - val = jade_read_reg(cs, 1, jade_HDLC_STAR); - debugl1(cs, "jade B STAR %x", val); - val = jade_read_reg(cs, 0, jade_HDLC_STAR); - debugl1(cs, "jade A STAR %x", val); + cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); + cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); + val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR); + sprintf(tmp, "jade B ISTA %x", val); + debugl1(cs, tmp); + val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR); + sprintf(tmp, "jade A ISTA %x", val); + debugl1(cs, tmp); + val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR); + sprintf(tmp, "jade B STAR %x", val); + debugl1(cs, tmp); + val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR); + sprintf(tmp, "jade A STAR %x", val); + debugl1(cs, tmp); /* Unmask ints */ - jade_write_reg(cs, 0, jade_HDLC_IMR, 0xF8); - jade_write_reg(cs, 1, jade_HDLC_IMR, 0xF8); + cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8); + cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8); +} + +void __init +initjade(struct IsdnCardState *cs) +{ + cs->bcs[0].BC_SetStack = setstack_jade; + cs->bcs[1].BC_SetStack = setstack_jade; + cs->bcs[0].BC_Close = close_jadestate; + cs->bcs[1].BC_Close = close_jadestate; + cs->bcs[0].hw.hscx.hscx = 0; + cs->bcs[1].hw.hscx.hscx = 1; /* Stop DSP audio tx/rx */ jade_write_indirect(cs, 0x11, 0x0f); jade_write_indirect(cs, 0x17, 0x2f); /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */ - jade_write_reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO); - jade_write_reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO); + cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO); + cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO); /* Power down, 1-Idle, RxTx least significant bit first */ - jade_write_reg(cs, 0, jade_HDLC_CCR0, 0x00); - jade_write_reg(cs, 1, jade_HDLC_CCR0, 0x00); + cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00); + cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00); /* Mask all interrupts */ - jade_write_reg(cs, 0, jade_HDLC_IMR, 0x00); - jade_write_reg(cs, 1, jade_HDLC_IMR, 0x00); + cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); + cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); /* Setup host access to hdlc controller */ jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2)); /* Unmask HDLC int (don´t forget DSP int later on)*/ - jade_write_reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2)); + cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2)); /* once again TRANSPARENT */ modejade(cs->bcs, 0, 0); modejade(cs->bcs + 1, 0, 0); } -int -jade_setup(struct IsdnCardState *cs, struct bc_hw_ops *jade_ops) -{ - cs->bc_hw_ops = jade_ops; - return JadeVersion(cs, "HiSax:"); -} - -#include "jade_irq.c" diff -puN drivers/isdn/hisax/jade.h~i4l drivers/isdn/hisax/jade.h --- 25/drivers/isdn/hisax/jade.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/jade.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: jade.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $ * * JADE specific defines * @@ -127,10 +127,9 @@ #define jade_TXAUDIOCH1CFG 0x17 #define jade_TXAUDIOCH2CFG 0x1A -extern void jade_sched_event(struct BCState *bcs, int event); +extern int JadeVersion(struct IsdnCardState *cs, char *s); extern void modejade(struct BCState *bcs, int mode, int bc); +extern void clear_pending_jade_ints(struct IsdnCardState *cs); extern void initjade(struct IsdnCardState *cs); -extern void jade_int_main(struct IsdnCardState *cs, u8 val, int jade); -extern int jade_setup(struct IsdnCardState *cs, struct bc_hw_ops *jade_ops); #endif /* __JADE_H__ */ diff -puN drivers/isdn/hisax/jade_irq.c~i4l drivers/isdn/hisax/jade_irq.c --- 25/drivers/isdn/hisax/jade_irq.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/jade_irq.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: jade_irq.c,v 1.5.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: jade_irq.c,v 1.7.2.3 2004/01/14 16:04:48 keil Exp $ * * Low level JADE IRQ stuff (derived from original hscx_irq.c) * @@ -15,7 +15,7 @@ waitforCEC(struct IsdnCardState *cs, int { int to = 50; int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC); - while ((jade_read_reg(cs, jade, jade_HDLC_STAR) & mask) && to) { + while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) { udelay(1); to--; } @@ -25,17 +25,16 @@ waitforCEC(struct IsdnCardState *cs, int static inline void -waitforXFW(struct BCState *bcs) +waitforXFW(struct IsdnCardState *cs, int jade) { + /* Does not work on older jade versions, don't care */ } static inline void -WriteJADECMDR(struct BCState *bcs, int reg, u8 data) +WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data) { - int jade = bcs->unit; - - waitforCEC(bcs->cs, jade, reg); - jade_write_reg(bcs->cs, jade, reg, data); + waitforCEC(cs, jade, reg); + WRITEJADE(cs, jade, reg, data); } @@ -43,33 +42,80 @@ WriteJADECMDR(struct BCState *bcs, int r static void jade_empty_fifo(struct BCState *bcs, int count) { - recv_empty_fifo_b(bcs, count); - WriteJADECMDR(bcs, jade_HDLC_RCMD, jadeRCMD_RMC); + u_char *ptr; + struct IsdnCardState *cs = bcs->cs; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "jade_empty_fifo"); + + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "jade_empty_fifo: incoming packet too large"); + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); + bcs->hw.hscx.rcvidx = 0; + return; + } + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "jade_empty_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static void jade_fill_fifo(struct BCState *bcs) { + struct IsdnCardState *cs = bcs->cs; int more, count; int fifo_size = 32; - unsigned char *p; + u_char *ptr; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "jade_fill_fifo"); - p = xmit_fill_fifo_b(bcs, fifo_size, &count, &more); - if (!p) + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) return; - waitforXFW(bcs); - jade_write_fifo(bcs, p, count); - WriteJADECMDR(bcs, jade_HDLC_XCMD, - more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME)); + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > fifo_size) { + more = !0; + count = fifo_size; + } else + count = bcs->tx_skb->len; + + waitforXFW(cs, bcs->hw.hscx.hscx); + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME)); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "jade_fill_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static inline void -jade_interrupt(struct IsdnCardState *cs, u8 val, u8 jade) +jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) { - u8 r; + u_char r; struct BCState *bcs = cs->bcs + jade; + struct sk_buff *skb; int fifo_size = 32; int count; int i_jade = (int) jade; /* To satisfy the compiler */ @@ -78,7 +124,7 @@ jade_interrupt(struct IsdnCardState *cs, return; if (val & 0x80) { /* RME */ - r = jade_read_reg(cs, i_jade, jade_HDLC_RSTA); + r = READJADE(cs, i_jade, jade_HDLC_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) if (cs->debug & L1_DEB_WARN) @@ -89,34 +135,67 @@ jade_interrupt(struct IsdnCardState *cs, if (!(r & 0x20)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "JADE %c CRC error", 'A'+jade); - WriteJADECMDR(bcs, jade_HDLC_RCMD, jadeRCMD_RMC); - bcs->rcvidx = 0; + WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC); } else { - count = jade_read_reg(cs, i_jade, jade_HDLC_RBCL) & 0x1F; + count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F; if (count == 0) count = fifo_size; - jade_empty_fifo(bcs, count); - recv_rme_b(bcs); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A")); + else { + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); } if (val & 0x40) { /* RPF */ jade_empty_fifo(bcs, fifo_size); - recv_rpf_b(bcs); + if (bcs->mode == L1_MODE_TRANS) { + /* receive audio data */ + if (!(skb = dev_alloc_skb(fifo_size))) + printk(KERN_WARNING "HiSax: receive out of memory\n"); + else { + memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); + } } if (val & 0x10) { /* XPR */ - xmit_xpr_b(bcs); + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + jade_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + jade_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } } } -static void -reset_xmit(struct BCState *bcs) -{ - WriteJADECMDR(bcs, jade_HDLC_XCMD, jadeXCMD_XRES); -} - -void -jade_int_main(struct IsdnCardState *cs, u8 val, int jade) +static inline void +jade_int_main(struct IsdnCardState *cs, u_char val, int jade) { struct BCState *bcs; bcs = cs->bcs + jade; @@ -126,7 +205,23 @@ jade_int_main(struct IsdnCardState *cs, val &= ~jadeISR_RFO; } if (val & jadeISR_XDU) { - xmit_xdu_b(bcs, reset_xmit); + /* relevant in HDLC mode only */ + /* don't reset XPR here */ + if (bcs->mode == 1) + jade_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val); + } } if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) { if (cs->debug & L1_DEB_HSCX) diff -puN drivers/isdn/hisax/Kconfig~i4l drivers/isdn/hisax/Kconfig --- 25/drivers/isdn/hisax/Kconfig~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -1,6 +1,6 @@ menu "Passive cards" - depends on ISDN + depends on ISDN_I4L config ISDN_DRV_HISAX tristate "HiSax SiemensChipSet driver support" @@ -341,8 +341,8 @@ config HISAX_HFC_SX # bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU config HISAX_ENTERNOW_PCI - bool "Formula-n enter:now PCI card (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + bool "Formula-n enter:now PCI card" + depends on PCI help This enables HiSax support for the Formula-n enter:now PCI ISDN card. @@ -365,6 +365,8 @@ config HISAX_DEBUG the ST5481 USB driver currently. If in doubt, say yes. +comment "HiSax PCMCIA card service modules" + config HISAX_SEDLBAUER_CS tristate "Sedlbauer PCMCIA cards" depends on PCMCIA && HISAX_SEDLBAUER @@ -374,18 +376,26 @@ config HISAX_SEDLBAUER_CS config HISAX_ELSA_CS tristate "ELSA PCMCIA MicroLink cards" - depends on PCMCIA + depends on PCMCIA && HISAX_ELSA help This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink card. config HISAX_AVM_A1_CS tristate "AVM A1 PCMCIA cards" - depends on PCMCIA + depends on PCMCIA && ISDN_DRV_HISAX help This enables the PCMCIA client driver for the AVM A1 / Fritz!Card PCMCIA cards. +config HISAX_TELES_CS + tristate "TELES PCMCIA cards" + depends on PCMCIA && HISAX_16_3 + help + This enables the PCMCIA client driver for the Teles PCMCIA cards. + +comment "HiSax sub driver modules" + config HISAX_ST5481 tristate "ST5481 USB ISDN modem (EXPERIMENTAL)" depends on USB && EXPERIMENTAL @@ -393,6 +403,12 @@ config HISAX_ST5481 This enables the driver for ST5481 based USB ISDN adapters, e.g. the BeWan Gazel 128 USB +config HISAX_HFCUSB + tristate "HFC USB based ISDN modems (EXPERIMENTAL)" + depends on USB && EXPERIMENTAL + help + This enables the driver for HFC USB based ISDN modems. + config HISAX_FRITZ_PCIPNP tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -402,18 +418,15 @@ config HISAX_FRITZ_PCIPNP (the latter also needs you to select "ISA Plug and Play support" from the menu "Plug and Play configuration") -config HISAX_FRITZ_CLASSIC - tristate "AVM Fritz!Card classic support (EXPERIMENTAL)" - depends on ISA && EXPERIMENTAL - help - This enables the driver for the AVM Fritz!Card classic, formerly - known as AVM A1. - -config HISAX_HFCPCI - tristate "HFC PCI support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL - help - This enables the driver for CCD HFC PCI based cards. +config HISAX_HDLC + bool + depends on HISAX_ST5481 + default y + +config HISAX_AVM_A1_PCMCIA + bool + depends on HISAX_AVM_A1_CS + default y endif diff -puN drivers/isdn/hisax/l3_1tr6.c~i4l drivers/isdn/hisax/l3_1tr6.c --- 25/drivers/isdn/hisax/l3_1tr6.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/l3_1tr6.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: l3_1tr6.c,v 2.13.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $ * * German 1TR6 D-channel protocol * @@ -19,7 +19,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.13.6.2 $"; +const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -28,10 +28,10 @@ const char *l3_1tr6_revision = "$Revisio *ptr++ = mty static void -l3_1TR6_message(struct l3_process *pc, u8 mt, u8 pd) +l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd) { struct sk_buff *skb; - u8 *p; + u_char *p; if (!(skb = l3_alloc_skb(4))) return; @@ -41,7 +41,7 @@ l3_1TR6_message(struct l3_process *pc, u } static void -l3_1tr6_release_req(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) { StopAllL3Timer(pc); newl3state(pc, 19); @@ -50,7 +50,7 @@ l3_1tr6_release_req(struct l3_process *p } static void -l3_1tr6_invalid(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; @@ -59,7 +59,7 @@ l3_1tr6_invalid(struct l3_process *pc, u } static void -l3_1tr6_error(struct l3_process *pc, u8 *msg, struct sk_buff *skb) +l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb) { dev_kfree_skb(skb); if (pc->st->l3.debug & L3_DEB_WARN) @@ -68,14 +68,14 @@ l3_1tr6_error(struct l3_process *pc, u8 } static void -l3_1tr6_setup_req(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[128]; - u8 *p = tmp; - u8 *teln; - u8 *eaz; - u8 channel = 0; + u_char tmp[128]; + u_char *p = tmp; + u_char *teln; + u_char *eaz; + u_char channel = 0; int l; MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1); @@ -157,9 +157,9 @@ l3_1tr6_setup_req(struct l3_process *pc, } static void -l3_1tr6_setup(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; int bcfound = 0; char tmp[80]; struct sk_buff *skb = arg; @@ -222,15 +222,15 @@ l3_1tr6_setup(struct l3_process *pc, u8 l3_debug(pc->st, tmp); } newl3state(pc, 6); - L3L4(pc->st, CC_SETUP | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } else release_l3_process(pc); } static void -l3_1tr6_setup_ack(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; struct sk_buff *skb = arg; L3DelTimer(&pc->timer); @@ -252,13 +252,13 @@ l3_1tr6_setup_ack(struct l3_process *pc, } dev_kfree_skb(skb); L3AddTimer(&pc->timer, T304, CC_T304); - L3L4(pc->st, CC_MORE_INFO | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void -l3_1tr6_call_sent(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; struct sk_buff *skb = arg; L3DelTimer(&pc->timer); @@ -284,26 +284,25 @@ l3_1tr6_call_sent(struct l3_process *pc, dev_kfree_skb(skb); L3AddTimer(&pc->timer, T310, CC_T310); newl3state(pc, 3); - L3L4(pc->st, CC_PROCEEDING | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void -l3_1tr6_alert(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; dev_kfree_skb(skb); L3DelTimer(&pc->timer); /* T304 */ newl3state(pc, 4); - L3L4(pc->st, CC_ALERTING | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void -l3_1tr6_info(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; - u_int i; - int tmpcharge = 0; + u_char *p; + int i, tmpcharge = 0; char a_charge[8], tmp[32]; struct sk_buff *skb = arg; @@ -316,7 +315,7 @@ l3_1tr6_info(struct l3_process *pc, u8 p } if (tmpcharge > pc->para.chargeinfo) { pc->para.chargeinfo = tmpcharge; - L3L4(pc->st, CC_CHARGE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { sprintf(tmp, "charging info %d", pc->para.chargeinfo); @@ -329,7 +328,7 @@ l3_1tr6_info(struct l3_process *pc, u8 p } static void -l3_1tr6_info_s2(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; @@ -337,7 +336,7 @@ l3_1tr6_info_s2(struct l3_process *pc, u } static void -l3_1tr6_connect(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; @@ -349,14 +348,14 @@ l3_1tr6_connect(struct l3_process *pc, u newl3state(pc, 10); dev_kfree_skb(skb); pc->para.chargeinfo = 0; - L3L4(pc->st, CC_SETUP | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void -l3_1tr6_rel(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; - u8 *p; + u_char *p; p = skb->data; if ((p = findie(p, skb->len, WE0_cause, 0))) { @@ -379,12 +378,12 @@ l3_1tr6_rel(struct l3_process *pc, u8 pr StopAllL3Timer(pc); newl3state(pc, 0); l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } static void -l3_1tr6_rel_ack(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; @@ -392,17 +391,16 @@ l3_1tr6_rel_ack(struct l3_process *pc, u StopAllL3Timer(pc); newl3state(pc, 0); pc->para.cause = NO_CAUSE; - L3L4(pc->st, CC_RELEASE | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); release_l3_process(pc); } static void -l3_1tr6_disc(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; - u8 *p; - u_int i; - int tmpcharge = 0; + u_char *p; + int i, tmpcharge = 0; char a_charge[8], tmp[32]; StopAllL3Timer(pc); @@ -415,7 +413,7 @@ l3_1tr6_disc(struct l3_process *pc, u8 p } if (tmpcharge > pc->para.chargeinfo) { pc->para.chargeinfo = tmpcharge; - L3L4(pc->st, CC_CHARGE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { sprintf(tmp, "charging info %d", pc->para.chargeinfo); @@ -448,12 +446,12 @@ l3_1tr6_disc(struct l3_process *pc, u8 p } dev_kfree_skb(skb); newl3state(pc, 12); - L3L4(pc->st, CC_DISCONNECT | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); } static void -l3_1tr6_connect_ack(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; @@ -465,22 +463,22 @@ l3_1tr6_connect_ack(struct l3_process *p newl3state(pc, 10); pc->para.chargeinfo = 0; L3DelTimer(&pc->timer); - L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); } static void -l3_1tr6_alert_req(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 7); l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1); } static void -l3_1tr6_setup_rsp(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[24]; - u8 *p = tmp; + u_char tmp[24]; + u_char *p = tmp; int l; MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1); @@ -510,20 +508,20 @@ l3_1tr6_setup_rsp(struct l3_process *pc, } static void -l3_1tr6_reset(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg) { release_l3_process(pc); } static void -l3_1tr6_disconnect_req(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; - u8 cause = 0x10; - u8 clen = 1; + u_char cause = 0x10; + u_char clen = 1; if (pc->para.cause > 0) cause = pc->para.cause; @@ -555,7 +553,7 @@ l3_1tr6_disconnect_req(struct l3_process } static void -l3_1tr6_t303(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { pc->N303--; @@ -569,23 +567,23 @@ l3_1tr6_t303(struct l3_process *pc, u8 p } static void -l3_1tr6_t304(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3_1tr6_t305(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; - u8 cause = 0x90; - u8 clen = 1; + u_char cause = 0x90; + u_char clen = 1; L3DelTimer(&pc->timer); if (pc->para.cause != NO_CAUSE) @@ -614,25 +612,25 @@ l3_1tr6_t305(struct l3_process *pc, u8 p } static void -l3_1tr6_t310(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3_1tr6_t313(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_CONNECT_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void -l3_1tr6_t308_1(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); @@ -641,28 +639,28 @@ l3_1tr6_t308_1(struct l3_process *pc, u8 } static void -l3_1tr6_t308_2(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RELEASE_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); release_l3_process(pc); } static void -l3_1tr6_dl_reset(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg) { pc->para.cause = CAUSE_LocalProcErr; l3_1tr6_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3_1tr6_dl_release(struct l3_process *pc, u8 pr, void *arg) +l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 0); pc->para.cause = 0x1b; /* Destination out of order */ pc->para.loc = 0; - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } @@ -755,8 +753,7 @@ static struct stateentry manstatelist[] static void up1tr6(struct PStack *st, int pr, void *arg) { - u_int i; - int mt, cr; + int i, mt, cr; struct l3_process *proc; struct sk_buff *skb = arg; char tmp[80]; @@ -871,8 +868,7 @@ up1tr6(struct PStack *st, int pr, void * static void down1tr6(struct PStack *st, int pr, void *arg) { - u_int i; - int cr; + int i, cr; struct l3_process *proc; struct Channel *chan; char tmp[80]; @@ -919,7 +915,7 @@ down1tr6(struct PStack *st, int pr, void static void man1tr6(struct PStack *st, int pr, void *arg) { - u_int i; + int i; struct l3_process *proc = arg; if (!proc) { @@ -949,8 +945,8 @@ setstack_1tr6(struct PStack *st) { char tmp[64]; - st->l3.l4l3 = down1tr6; - st->l3.l2l3 = up1tr6; + st->lli.l4l3 = down1tr6; + st->l2.l2l3 = up1tr6; st->l3.l3ml3 = man1tr6; st->l3.N303 = 0; diff -puN drivers/isdn/hisax/l3dss1.c~i4l drivers/isdn/hisax/l3dss1.c --- 25/drivers/isdn/hisax/l3dss1.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/l3dss1.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.30.6.2 2001/09/23 22:24:49 kai Exp $ +/* $Id: l3dss1.c,v 2.32.2.3 2004/01/13 14:31:25 keil Exp $ * * EURO/DSS1 D-channel protocol * @@ -26,8 +26,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.30.6.2 $"; -static spinlock_t l3dss1_lock = SPIN_LOCK_UNLOCKED; +const char *dss1_revision = "$Revision: 2.32.2.3 $"; #define EXT_BEARER_CAPS 1 @@ -49,13 +48,10 @@ static spinlock_t l3dss1_lock = SPIN_LOC static unsigned char new_invoke_id(struct PStack *p) { unsigned char retval; - unsigned long flags; int i; i = 32; /* maximum search depth */ - spin_lock_irqsave(&l3dss1_lock, flags); - retval = p->prot.dss1.last_invoke_id + 1; /* try new id */ while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) { p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8; @@ -68,8 +64,6 @@ static unsigned char new_invoke_id(struc retval = 0; p->prot.dss1.last_invoke_id = retval; p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7)); - spin_unlock_irqrestore(&l3dss1_lock, flags); - return(retval); } /* new_invoke_id */ @@ -77,13 +71,11 @@ static unsigned char new_invoke_id(struc /* free a used invoke id */ /*************************/ static void free_invoke_id(struct PStack *p, unsigned char id) -{ unsigned long flags; +{ if (!id) return; /* 0 = invalid value */ - spin_lock_irqsave(&l3dss1_lock, flags); p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7)); - spin_unlock_irqrestore(&l3dss1_lock, flags); } /* free_invoke_id */ @@ -136,7 +128,7 @@ l3dss1_search_dummy_proc(struct PStack * /* and a return result is delivered. id specifies the invoke id. */ /*******************************************************************/ static void -l3dss1_dummy_return_result(struct PStack *st, int id, u8 *p, u8 nlen) +l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) { isdn_ctrl ic; struct IsdnCardState *cs; struct l3_process *pc = NULL; @@ -203,7 +195,7 @@ l3dss1_dummy_error_return(struct PStack /*******************************************************************/ static void l3dss1_dummy_invoke(struct PStack *st, int cr, int id, - int ident, u8 *p, u8 nlen) + int ident, u_char *p, u_char nlen) { isdn_ctrl ic; struct IsdnCardState *cs; @@ -227,7 +219,7 @@ l3dss1_dummy_invoke(struct PStack *st, i static void l3dss1_parse_facility(struct PStack *st, struct l3_process *pc, - int cr, u8 * p) + int cr, u_char * p) { int qd_len = 0; unsigned char nlen = 0, ilen, cp_tag; @@ -447,7 +439,7 @@ l3dss1_parse_facility(struct PStack *st, pc->prot.dss1.remote_result = 0; /* success */ pc->prot.dss1.invoke_id = 0; pc->redir_result = pc->prot.dss1.remote_result; - L3L4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ else l3_debug(st,"return error unknown identifier"); break; @@ -492,7 +484,7 @@ l3dss1_parse_facility(struct PStack *st, pc->prot.dss1.remote_result = err_ret; /* result */ pc->prot.dss1.invoke_id = 0; pc->redir_result = pc->prot.dss1.remote_result; - L3L4(st, CC_REDIR | INDICATION, pc); + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Deflection error */ else l3_debug(st,"return result unknown identifier"); @@ -504,10 +496,10 @@ l3dss1_parse_facility(struct PStack *st, } static void -l3dss1_message(struct l3_process *pc, u8 mt) +l3dss1_message(struct l3_process *pc, u_char mt) { struct sk_buff *skb; - u8 *p; + u_char *p; if (!(skb = l3_alloc_skb(4))) return; @@ -517,11 +509,11 @@ l3dss1_message(struct l3_process *pc, u8 } static void -l3dss1_message_cause(struct l3_process *pc, u8 mt, u8 cause) +l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause) { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; MsgHead(p, pc->callref, mt); @@ -538,10 +530,10 @@ l3dss1_message_cause(struct l3_process * } static void -l3dss1_status_send(struct l3_process *pc, u8 pr, void *arg) +l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg) { - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; struct sk_buff *skb; @@ -564,14 +556,14 @@ l3dss1_status_send(struct l3_process *pc } static void -l3dss1_msg_without_setup(struct l3_process *pc, u8 pr, void *arg) +l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) { /* This routine is called if here was no SETUP made (checks in dss1up and in * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code * MT_STATUS_ENQUIRE in the NULL state is handled too */ - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; struct sk_buff *skb; @@ -690,7 +682,7 @@ struct ie_len max_ie_len[] = { }; static int -getmax_ie_len(u8 ie) { +getmax_ie_len(u_char ie) { int i = 0; while (max_ie_len[i].ie != -1) { if (max_ie_len[i].ie == ie) @@ -701,7 +693,7 @@ getmax_ie_len(u8 ie) { } static int -ie_in_set(struct l3_process *pc, u8 ie, int *checklist) { +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { int ret = 1; while (*checklist != -1) { @@ -721,13 +713,13 @@ static int check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) { int *cl = checklist; - u8 mt; - u8 *p, ie; + u_char mt; + u_char *p, ie; int l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - u8 codeset = 0; - u8 old_codeset = 0; - u8 codelock = 1; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; p = skb->data; /* skip cr */ @@ -736,7 +728,7 @@ check_infoelements(struct l3_process *pc p += l; mt = *p++; oldpos = 0; - while ((p - skb->data) < (int)skb->len) { + while ((p - skb->data) < skb->len) { if ((*p & 0xf0) == 0x90) { /* shift codeset */ old_codeset = codeset; codeset = *p & 7; @@ -870,7 +862,7 @@ l3dss1_std_ie_err(struct l3_process *pc, static int l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { - u8 *p; + u_char *p; p = skb->data; if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { @@ -893,8 +885,8 @@ l3dss1_get_channel_id(struct l3_process static int l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) { - u8 l, i=0; - u8 *p; + u_char l, i=0; + u_char *p; p = skb->data; pc->para.cause = 31; @@ -931,11 +923,11 @@ l3dss1_get_cause(struct l3_process *pc, } static void -l3dss1_msg_with_uus(struct l3_process *pc, u8 cmd) +l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd) { struct sk_buff *skb; - u8 tmp[16+40]; - u8 *p = tmp; + u_char tmp[16+40]; + u_char *p = tmp; int l; MsgHead(p, pc->callref, cmd); @@ -957,7 +949,7 @@ l3dss1_msg_with_uus(struct l3_process *p } /* l3dss1_msg_with_uus */ static void -l3dss1_release_req(struct l3_process *pc, u8 pr, void *arg) +l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg) { StopAllL3Timer(pc); newl3state(pc, 19); @@ -969,7 +961,7 @@ l3dss1_release_req(struct l3_process *pc } static void -l3dss1_release_cmpl(struct l3_process *pc, u8 pr, void *arg) +l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -981,14 +973,14 @@ l3dss1_release_cmpl(struct l3_process *p pc->para.cause = NO_CAUSE; StopAllL3Timer(pc); newl3state(pc, 0); - L3L4(pc->st, CC_RELEASE | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); dss1_release_l3_process(pc); } #if EXT_BEARER_CAPS -static u8 * -EncodeASyncParams(u8 * p, u8 si2) +static u_char * +EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb p[0] = 0; @@ -1052,8 +1044,8 @@ EncodeASyncParams(u8 * p, u8 si2) return p + 3; } -static u8 -EncodeSyncParams(u8 si2, u8 ai) +static u_char +EncodeSyncParams(u_char si2, u_char ai) { switch (si2) { @@ -1097,10 +1089,10 @@ EncodeSyncParams(u8 si2, u8 ai) } -static u8 -DecodeASyncParams(u8 si2, u8 * p) +static u_char +DecodeASyncParams(u_char si2, u_char * p) { - u8 info; + u_char info; switch (p[5]) { case 66: // 1200 bit/s @@ -1154,8 +1146,8 @@ DecodeASyncParams(u8 si2, u8 * p) } -static u8 -DecodeSyncParams(u8 si2, u8 info) +static u_char +DecodeSyncParams(u_char si2, u_char info) { info &= 0x7f; switch (info) { @@ -1195,10 +1187,10 @@ DecodeSyncParams(u8 si2, u8 info) } } -static u8 +static u_char DecodeSI2(struct sk_buff *skb) { - u8 *p; //, *pend=skb->data + skb->len; + u_char *p; //, *pend=skb->data + skb->len; if ((p = findie(skb->data, skb->len, 0x7c, 0))) { switch (p[4] & 0x0f) { @@ -1225,20 +1217,20 @@ DecodeSI2(struct sk_buff *skb) static void -l3dss1_setup_req(struct l3_process *pc, u8 pr, +l3dss1_setup_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[128]; - u8 *p = tmp; - u8 channel = 0; - - u8 send_keypad; - u8 screen = 0x80; - u8 *teln; - u8 *msn; - u8 *sub; - u8 *sp; + u_char tmp[128]; + u_char *p = tmp; + u_char channel = 0; + + u_char send_keypad; + u_char screen = 0x80; + u_char *teln; + u_char *msn; + u_char *sub; + u_char *sp; int l; MsgHead(p, pc->callref, MT_SETUP); @@ -1436,7 +1428,7 @@ l3dss1_setup_req(struct l3_process *pc, } static void -l3dss1_call_proc(struct l3_process *pc, u8 pr, void *arg) +l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int id, ret; @@ -1471,11 +1463,11 @@ l3dss1_call_proc(struct l3_process *pc, L3AddTimer(&pc->timer, T310, CC_T310); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, ret); - L3L4(pc->st, CC_PROCEEDING | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void -l3dss1_setup_ack(struct l3_process *pc, u8 pr, void *arg) +l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int id, ret; @@ -1510,16 +1502,16 @@ l3dss1_setup_ack(struct l3_process *pc, L3AddTimer(&pc->timer, T304, CC_T304); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, ret); - L3L4(pc->st, CC_MORE_INFO | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void -l3dss1_disconnect(struct l3_process *pc, u8 pr, void *arg) +l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; - u8 *p; + u_char *p; int ret; - u8 cause = 0; + u_char cause = 0; StopAllL3Timer(pc); if ((ret = l3dss1_get_cause(pc, skb))) { @@ -1542,7 +1534,7 @@ l3dss1_disconnect(struct l3_process *pc, if (cause) newl3state(pc, 19); if (11 != ret) - L3L4(pc->st, CC_DISCONNECT | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); else if (!cause) l3dss1_release_req(pc, pr, NULL); if (cause) { @@ -1552,7 +1544,7 @@ l3dss1_disconnect(struct l3_process *pc, } static void -l3dss1_connect(struct l3_process *pc, u8 pr, void *arg) +l3dss1_connect(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -1568,11 +1560,11 @@ l3dss1_connect(struct l3_process *pc, u8 /* here should inserted COLP handling KKe */ if (ret) l3dss1_std_ie_err(pc, ret); - L3L4(pc->st, CC_SETUP | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void -l3dss1_alerting(struct l3_process *pc, u8 pr, void *arg) +l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -1586,13 +1578,13 @@ l3dss1_alerting(struct l3_process *pc, u newl3state(pc, 4); if (ret) l3dss1_std_ie_err(pc, ret); - L3L4(pc->st, CC_ALERTING | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void -l3dss1_setup(struct l3_process *pc, u8 pr, void *arg) +l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; int bcfound = 0; char tmp[80]; struct sk_buff *skb = arg; @@ -1603,7 +1595,7 @@ l3dss1_setup(struct l3_process *pc, u8 p * Bearer Capabilities */ p = skb->data; - /* only the first occurrence 'll be detected ! */ + /* only the first occurence 'll be detected ! */ if ((p = findie(p, skb->len, 0x04, 0))) { if ((p[1] < 2) || (p[1] > 11)) err = 1; @@ -1752,23 +1744,23 @@ l3dss1_setup(struct l3_process *pc, u8 p newl3state(pc, 6); if (err) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, err); - L3L4(pc->st, CC_SETUP | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } static void -l3dss1_reset(struct l3_process *pc, u8 pr, void *arg) +l3dss1_reset(struct l3_process *pc, u_char pr, void *arg) { dss1_release_l3_process(pc); } static void -l3dss1_disconnect_req(struct l3_process *pc, u8 pr, void *arg) +l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[16+40]; - u8 *p = tmp; + u_char tmp[16+40]; + u_char *p = tmp; int l; - u8 cause = 16; + u_char cause = 16; if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; @@ -1801,7 +1793,7 @@ l3dss1_disconnect_req(struct l3_process } static void -l3dss1_setup_rsp(struct l3_process *pc, u8 pr, +l3dss1_setup_rsp(struct l3_process *pc, u_char pr, void *arg) { if (!pc->para.bchannel) @@ -1817,7 +1809,7 @@ l3dss1_setup_rsp(struct l3_process *pc, } static void -l3dss1_connect_ack(struct l3_process *pc, u8 pr, void *arg) +l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -1831,17 +1823,17 @@ l3dss1_connect_ack(struct l3_process *pc L3DelTimer(&pc->timer); if (ret) l3dss1_std_ie_err(pc, ret); - L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); } static void -l3dss1_reject_req(struct l3_process *pc, u8 pr, void *arg) +l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; - u8 cause = 21; + u_char cause = 21; if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; @@ -1858,16 +1850,16 @@ l3dss1_reject_req(struct l3_process *pc, return; memcpy(skb_put(skb, l), tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); dss1_release_l3_process(pc); } static void -l3dss1_release(struct l3_process *pc, u8 pr, void *arg) +l3dss1_release(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; - u8 *p; + u_char *p; int ret, cause=0; StopAllL3Timer(pc); @@ -1892,13 +1884,13 @@ l3dss1_release(struct l3_process *pc, u8 l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause); else l3dss1_message(pc, MT_RELEASE_COMPLETE); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); dss1_release_l3_process(pc); } static void -l3dss1_alert_req(struct l3_process *pc, u8 pr, +l3dss1_alert_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 7); @@ -1909,16 +1901,16 @@ l3dss1_alert_req(struct l3_process *pc, } static void -l3dss1_proceed_req(struct l3_process *pc, u8 pr, +l3dss1_proceed_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 9); l3dss1_message(pc, MT_CALL_PROCEEDING); - L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); } static void -l3dss1_setup_ack_req(struct l3_process *pc, u8 pr, +l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 25); @@ -1931,8 +1923,8 @@ l3dss1_setup_ack_req(struct l3_process * /* deliver a incoming display message to HL */ /********************************************/ static void -l3dss1_deliver_display(struct l3_process *pc, int pr, u8 *infp) -{ u8 len; +l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; isdn_ctrl ic; struct IsdnCardState *cs; char *p; @@ -1954,11 +1946,11 @@ l3dss1_deliver_display(struct l3_process static void -l3dss1_progress(struct l3_process *pc, u8 pr, void *arg) +l3dss1_progress(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int err = 0; - u8 *p; + u_char *p; if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { if (p[1] != 2) { @@ -2007,15 +1999,15 @@ l3dss1_progress(struct l3_process *pc, u if (err) l3dss1_std_ie_err(pc, err); if (ERR_IE_COMPREHENSION != err) - L3L4(pc->st, CC_PROGRESS | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); } static void -l3dss1_notify(struct l3_process *pc, u8 pr, void *arg) +l3dss1_notify(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int err = 0; - u8 *p; + u_char *p; if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { if (p[1] != 1) { @@ -2048,11 +2040,11 @@ l3dss1_notify(struct l3_process *pc, u8 if (err) l3dss1_std_ie_err(pc, err); if (ERR_IE_COMPREHENSION != err) - L3L4(pc->st, CC_NOTIFY | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); } static void -l3dss1_status_enq(struct l3_process *pc, u8 pr, void *arg) +l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg) { int ret; struct sk_buff *skb = arg; @@ -2064,11 +2056,11 @@ l3dss1_status_enq(struct l3_process *pc, } static void -l3dss1_information(struct l3_process *pc, u8 pr, void *arg) +l3dss1_information(struct l3_process *pc, u_char pr, void *arg) { int ret; struct sk_buff *skb = arg; - u8 *p; + u_char *p; char tmp[32]; ret = check_infoelements(pc, skb, ie_INFORMATION); @@ -2080,7 +2072,7 @@ l3dss1_information(struct l3_process *pc if ((p = findie(p, skb->len, 0x70, 0))) { iecpy(tmp, p, 1); strcat(pc->para.setup.eazmsn, tmp); - L3L4(pc->st, CC_MORE_INFO | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } L3AddTimer(&pc->timer, T302, CC_T302); } @@ -2089,14 +2081,14 @@ l3dss1_information(struct l3_process *pc /******************************/ /* handle deflection requests */ /******************************/ -static void l3dss1_redir_req(struct l3_process *pc, u8 pr, void *arg) +static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[128]; - u8 *p = tmp; - u8 *subp; - u8 len_phone = 0; - u8 len_sub = 0; + u_char tmp[128]; + u_char *p = tmp; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; int l; @@ -2161,7 +2153,7 @@ static void l3dss1_redir_req(struct l3_p /********************************************/ /* handle deflection request in early state */ /********************************************/ -static void l3dss1_redir_req_early(struct l3_process *pc, u8 pr, void *arg) +static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) { l3dss1_proceed_req(pc,pr,arg); l3dss1_redir_req(pc,pr,arg); @@ -2169,13 +2161,13 @@ static void l3dss1_redir_req_early(struc /***********************************************/ /* handle special commands for this protocol. */ -/* Examples are call independent services like */ +/* Examples are call independant services like */ /* remote operations with dummy callref. */ /***********************************************/ static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic) -{ u8 id; - u8 temp[265]; - u8 *p = temp; +{ u_char id; + u_char temp[265]; + u_char *p = temp; int i, l, proc_len; struct sk_buff *skb; struct l3_process *pc = NULL; @@ -2279,9 +2271,9 @@ l3dss1_io_timer(struct l3_process *pc) } /* l3dss1_io_timer */ static void -l3dss1_release_ind(struct l3_process *pc, u8 pr, void *arg) +l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; struct sk_buff *skb = arg; int callState = 0; p = skb->data; @@ -2295,31 +2287,31 @@ l3dss1_release_ind(struct l3_process *pc /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 * set down layer 3 without sending any message */ - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); dss1_release_l3_process(pc); } else { - L3L4(pc->st, CC_IGNORE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); } } static void -l3dss1_dummy(struct l3_process *pc, u8 pr, void *arg) +l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg) { } static void -l3dss1_t302(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 28; /* invalid number */ l3dss1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3dss1_t303(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { pc->N303--; @@ -2328,30 +2320,30 @@ l3dss1_t303(struct l3_process *pc, u8 pr } else { L3DelTimer(&pc->timer); l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102); - L3L4(pc->st, CC_NOSETUP_RSP, pc); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); dss1_release_l3_process(pc); } } static void -l3dss1_t304(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3dss1_t305(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t305(struct l3_process *pc, u_char pr, void *arg) { - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; struct sk_buff *skb; - u8 cause = 16; + u_char cause = 16; L3DelTimer(&pc->timer); if (pc->para.cause != NO_CAUSE) @@ -2374,27 +2366,27 @@ l3dss1_t305(struct l3_process *pc, u8 pr } static void -l3dss1_t310(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3dss1_t313(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_CONNECT_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void -l3dss1_t308_1(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 19); L3DelTimer(&pc->timer); @@ -2403,50 +2395,50 @@ l3dss1_t308_1(struct l3_process *pc, u8 } static void -l3dss1_t308_2(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RELEASE_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); dss1_release_l3_process(pc); } static void -l3dss1_t318(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t318(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 102; /* Timer expiry */ pc->para.loc = 0; /* local */ - L3L4(pc->st, CC_RESUME_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); newl3state(pc, 19); l3dss1_message(pc, MT_RELEASE); L3AddTimer(&pc->timer, T308, CC_T308_1); } static void -l3dss1_t319(struct l3_process *pc, u8 pr, void *arg) +l3dss1_t319(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 102; /* Timer expiry */ pc->para.loc = 0; /* local */ - L3L4(pc->st, CC_SUSPEND_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); newl3state(pc, 10); } static void -l3dss1_restart(struct l3_process *pc, u8 pr, void *arg) +l3dss1_restart(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); dss1_release_l3_process(pc); } static void -l3dss1_status(struct l3_process *pc, u8 pr, void *arg) +l3dss1_status(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; struct sk_buff *skb = arg; int ret; - u8 cause = 0, callState = 0; + u_char cause = 0, callState = 0; if ((ret = l3dss1_get_cause(pc, skb))) { if (pc->debug & L3_DEB_WARN) @@ -2474,7 +2466,7 @@ l3dss1_status(struct l3_process *pc, u8 cause = 99; } if (cause) { - u8 tmp; + u_char tmp; if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); @@ -2492,14 +2484,14 @@ l3dss1_status(struct l3_process *pc, u8 * if received MT_STATUS with cause == 111 and call * state == 0, then we must set down layer 3 */ - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); dss1_release_l3_process(pc); } } static void -l3dss1_facility(struct l3_process *pc, u8 pr, void *arg) +l3dss1_facility(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2507,20 +2499,20 @@ l3dss1_facility(struct l3_process *pc, u ret = check_infoelements(pc, skb, ie_FACILITY); l3dss1_std_ie_err(pc, ret); { - u8 *p; + u_char *p; if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) l3dss1_parse_facility(pc->st, pc, pc->callref, p); } } static void -l3dss1_suspend_req(struct l3_process *pc, u8 pr, void *arg) +l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[32]; - u8 *p = tmp; - u8 i, l; - u8 *msg = pc->chan->setup.phone; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; MsgHead(p, pc->callref, MT_SUSPEND); l = *msg++; @@ -2543,7 +2535,7 @@ l3dss1_suspend_req(struct l3_process *pc } static void -l3dss1_suspend_ack(struct l3_process *pc, u8 pr, void *arg) +l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2551,7 +2543,7 @@ l3dss1_suspend_ack(struct l3_process *pc L3DelTimer(&pc->timer); newl3state(pc, 0); pc->para.cause = NO_CAUSE; - L3L4(pc->st, CC_SUSPEND | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); /* We don't handle suspend_ack for IE errors now */ if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) if (pc->debug & L3_DEB_WARN) @@ -2560,7 +2552,7 @@ l3dss1_suspend_ack(struct l3_process *pc } static void -l3dss1_suspend_rej(struct l3_process *pc, u8 pr, void *arg) +l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2581,20 +2573,20 @@ l3dss1_suspend_rej(struct l3_process *pc return; } L3DelTimer(&pc->timer); - L3L4(pc->st, CC_SUSPEND_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); newl3state(pc, 10); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, ret); } static void -l3dss1_resume_req(struct l3_process *pc, u8 pr, void *arg) +l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[32]; - u8 *p = tmp; - u8 i, l; - u8 *msg = pc->para.setup.phone; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; MsgHead(p, pc->callref, MT_RESUME); @@ -2618,7 +2610,7 @@ l3dss1_resume_req(struct l3_process *pc, } static void -l3dss1_resume_ack(struct l3_process *pc, u8 pr, void *arg) +l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int id, ret; @@ -2645,14 +2637,14 @@ l3dss1_resume_ack(struct l3_process *pc, return; } L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RESUME | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); newl3state(pc, 10); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, ret); } static void -l3dss1_resume_rej(struct l3_process *pc, u8 pr, void *arg) +l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2673,7 +2665,7 @@ l3dss1_resume_rej(struct l3_process *pc, return; } L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RESUME_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); newl3state(pc, 0); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, ret); @@ -2681,11 +2673,11 @@ l3dss1_resume_rej(struct l3_process *pc, } static void -l3dss1_global_restart(struct l3_process *pc, u8 pr, void *arg) +l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) { - u8 tmp[32]; - u8 *p; - u8 ri, ch = 0, chan = 0; + u_char tmp[32]; + u_char *p; + u_char ri, ch = 0, chan = 0; int l; struct sk_buff *skb = arg; struct l3_process *up; @@ -2711,9 +2703,9 @@ l3dss1_global_restart(struct l3_process up = pc->st->l3.proc; while (up) { if ((ri & 7) == 7) - L4L3(up->st, CC_RESTART | REQUEST, up); + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); else if (up->para.bchannel == chan) - L4L3(up->st, CC_RESTART | REQUEST, up); + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); up = up->next; } p = tmp; @@ -2735,26 +2727,26 @@ l3dss1_global_restart(struct l3_process } static void -l3dss1_dl_reset(struct l3_process *pc, u8 pr, void *arg) +l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg) { pc->para.cause = 0x29; /* Temporary failure */ pc->para.loc = 0; l3dss1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3dss1_dl_release(struct l3_process *pc, u8 pr, void *arg) +l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 0); pc->para.cause = 0x1b; /* Destination out of order */ pc->para.loc = 0; - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } static void -l3dss1_dl_reestablish(struct l3_process *pc, u8 pr, void *arg) +l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T309, CC_T309); @@ -2762,7 +2754,7 @@ l3dss1_dl_reestablish(struct l3_process } static void -l3dss1_dl_reest_status(struct l3_process *pc, u8 pr, void *arg) +l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); @@ -2920,10 +2912,10 @@ static struct stateentry manstatelist[] static void global_handler(struct PStack *st, int mt, struct sk_buff *skb) { - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; - u_int i; + int i; struct l3_process *proc = st->l3.global; proc->callref = skb->data[2]; /* cr flag */ @@ -2961,10 +2953,9 @@ global_handler(struct PStack *st, int mt static void dss1up(struct PStack *st, int pr, void *arg) { - u_int i; - int mt, cr, cause, callState; + int i, mt, cr, cause, callState; char *ptr; - u8 *p; + u_char *p; struct sk_buff *skb = arg; struct l3_process *proc; @@ -2999,7 +2990,7 @@ dss1up(struct PStack *st, int pr, void * return; } cr = getcallref(skb->data); - if (skb->len < (u_int)((skb->data[1] & 0x0f) + 3)) { + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { l3_debug(st, "dss1up frame too short(%d)", skb->len); dev_kfree_skb(skb); return; @@ -3136,8 +3127,7 @@ dss1up(struct PStack *st, int pr, void * static void dss1down(struct PStack *st, int pr, void *arg) { - u_int i; - int cr; + int i, cr; struct l3_process *proc; struct Channel *chan; @@ -3188,29 +3178,29 @@ dss1down(struct PStack *st, int pr, void static void dss1man(struct PStack *st, int pr, void *arg) { - u_int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < MANSLLEN; i++) + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == MANSLLEN) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d dss1man state %d prim %#x", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d dss1man state %d prim %#x", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } } void @@ -3219,9 +3209,9 @@ setstack_dss1(struct PStack *st) char tmp[64]; int i; - st->l3.l4l3 = dss1down; - st->l3.l4l3_proto = l3dss1_cmd_global; - st->l3.l2l3 = dss1up; + st->lli.l4l3 = dss1down; + st->lli.l4l3_proto = l3dss1_cmd_global; + st->l2.l2l3 = dss1up; st->l3.l3ml3 = dss1man; st->l3.N303 = 1; st->prot.dss1.last_invoke_id = 0; diff -puN drivers/isdn/hisax/l3ni1.c~i4l drivers/isdn/hisax/l3ni1.c --- 25/drivers/isdn/hisax/l3ni1.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/l3ni1.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: l3ni1.c,v 2.5.6.3 2001/09/23 22:24:50 kai Exp $ +/* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $ * * NI1 D-channel protocol * @@ -24,8 +24,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *ni1_revision = "$Revision: 2.5.6.3 $"; -static spinlock_t l3ni1_lock = SPIN_LOCK_UNLOCKED; +const char *ni1_revision = "$Revision: 2.8.2.3 $"; #define EXT_BEARER_CAPS 1 @@ -47,13 +46,10 @@ static spinlock_t l3ni1_lock = SPIN_LOCK static unsigned char new_invoke_id(struct PStack *p) { unsigned char retval; - unsigned long flags; int i; i = 32; /* maximum search depth */ - spin_lock_irqsave(&l3ni1_lock, flags); - retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; @@ -66,8 +62,6 @@ static unsigned char new_invoke_id(struc retval = 0; p->prot.ni1.last_invoke_id = retval; p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); - spin_unlock_irqrestore(&l3ni1_lock, flags); - return(retval); } /* new_invoke_id */ @@ -75,13 +69,11 @@ static unsigned char new_invoke_id(struc /* free a used invoke id */ /*************************/ static void free_invoke_id(struct PStack *p, unsigned char id) -{ unsigned long flags; +{ if (!id) return; /* 0 = invalid value */ - spin_lock_irqsave(&l3ni1_lock, flags); p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); - spin_unlock_irqrestore(&l3ni1_lock, flags); } /* free_invoke_id */ @@ -134,7 +126,7 @@ l3ni1_search_dummy_proc(struct PStack *s /* and a return result is delivered. id specifies the invoke id. */ /*******************************************************************/ static void -l3ni1_dummy_return_result(struct PStack *st, int id, u8 *p, u8 nlen) +l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) { isdn_ctrl ic; struct IsdnCardState *cs; struct l3_process *pc = NULL; @@ -201,7 +193,7 @@ l3ni1_dummy_error_return(struct PStack * /*******************************************************************/ static void l3ni1_dummy_invoke(struct PStack *st, int cr, int id, - int ident, u8 *p, u8 nlen) + int ident, u_char *p, u_char nlen) { isdn_ctrl ic; struct IsdnCardState *cs; @@ -225,7 +217,7 @@ l3ni1_dummy_invoke(struct PStack *st, in static void l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, - int cr, u8 * p) + int cr, u_char * p) { int qd_len = 0; unsigned char nlen = 0, ilen, cp_tag; @@ -375,7 +367,7 @@ l3ni1_parse_facility(struct PStack *st, pc->prot.ni1.remote_result = 0; /* success */ pc->prot.ni1.invoke_id = 0; pc->redir_result = pc->prot.ni1.remote_result; - L3L4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ else l3_debug(st,"return error unknown identifier"); break; @@ -420,7 +412,7 @@ l3ni1_parse_facility(struct PStack *st, pc->prot.ni1.remote_result = err_ret; /* result */ pc->prot.ni1.invoke_id = 0; pc->redir_result = pc->prot.ni1.remote_result; - L3L4(st, CC_REDIR | INDICATION, pc); + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Deflection error */ else l3_debug(st,"return result unknown identifier"); @@ -432,10 +424,10 @@ l3ni1_parse_facility(struct PStack *st, } static void -l3ni1_message(struct l3_process *pc, u8 mt) +l3ni1_message(struct l3_process *pc, u_char mt) { struct sk_buff *skb; - u8 *p; + u_char *p; if (!(skb = l3_alloc_skb(4))) return; @@ -445,15 +437,15 @@ l3ni1_message(struct l3_process *pc, u8 } static void -l3ni1_message_plus_chid(struct l3_process *pc, u8 mt) +l3ni1_message_plus_chid(struct l3_process *pc, u_char mt) /* sends an l3 messages plus channel id - added GE 05/09/00 */ { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; - u8 chid; + u_char tmp[16]; + u_char *p = tmp; + u_char chid; - chid = (u8)(pc->para.bchannel & 0x03) | 0x88; + chid = (u_char)(pc->para.bchannel & 0x03) | 0x88; MsgHead(p, pc->callref, mt); *p++ = IE_CHANNEL_ID; *p++ = 0x01; @@ -466,11 +458,11 @@ l3ni1_message_plus_chid(struct l3_proces } static void -l3ni1_message_cause(struct l3_process *pc, u8 mt, u8 cause) +l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; MsgHead(p, pc->callref, mt); @@ -487,10 +479,10 @@ l3ni1_message_cause(struct l3_process *p } static void -l3ni1_status_send(struct l3_process *pc, u8 pr, void *arg) +l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) { - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; struct sk_buff *skb; @@ -513,14 +505,14 @@ l3ni1_status_send(struct l3_process *pc, } static void -l3ni1_msg_without_setup(struct l3_process *pc, u8 pr, void *arg) +l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) { /* This routine is called if here was no SETUP made (checks in ni1up and in * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code * MT_STATUS_ENQUIRE in the NULL state is handled too */ - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; struct sk_buff *skb; @@ -639,7 +631,7 @@ struct ie_len max_ie_len[] = { }; static int -getmax_ie_len(u8 ie) { +getmax_ie_len(u_char ie) { int i = 0; while (max_ie_len[i].ie != -1) { if (max_ie_len[i].ie == ie) @@ -650,7 +642,7 @@ getmax_ie_len(u8 ie) { } static int -ie_in_set(struct l3_process *pc, u8 ie, int *checklist) { +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { int ret = 1; while (*checklist != -1) { @@ -670,13 +662,13 @@ static int check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) { int *cl = checklist; - u8 mt; - u8 *p, ie; + u_char mt; + u_char *p, ie; int l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - u8 codeset = 0; - u8 old_codeset = 0; - u8 codelock = 1; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; p = skb->data; /* skip cr */ @@ -685,7 +677,7 @@ check_infoelements(struct l3_process *pc p += l; mt = *p++; oldpos = 0; - while ((u_int)(p - skb->data) < skb->len) { + while ((p - skb->data) < skb->len) { if ((*p & 0xf0) == 0x90) { /* shift codeset */ old_codeset = codeset; codeset = *p & 7; @@ -819,7 +811,7 @@ l3ni1_std_ie_err(struct l3_process *pc, static int l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { - u8 *p; + u_char *p; p = skb->data; if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { @@ -842,8 +834,8 @@ l3ni1_get_channel_id(struct l3_process * static int l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { - u8 l, i=0; - u8 *p; + u_char l, i=0; + u_char *p; p = skb->data; pc->para.cause = 31; @@ -880,11 +872,11 @@ l3ni1_get_cause(struct l3_process *pc, s } static void -l3ni1_msg_with_uus(struct l3_process *pc, u8 cmd) +l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) { struct sk_buff *skb; - u8 tmp[16+40]; - u8 *p = tmp; + u_char tmp[16+40]; + u_char *p = tmp; int l; MsgHead(p, pc->callref, cmd); @@ -906,7 +898,7 @@ l3ni1_msg_with_uus(struct l3_process *pc } /* l3ni1_msg_with_uus */ static void -l3ni1_release_req(struct l3_process *pc, u8 pr, void *arg) +l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) { StopAllL3Timer(pc); newl3state(pc, 19); @@ -918,7 +910,7 @@ l3ni1_release_req(struct l3_process *pc, } static void -l3ni1_release_cmpl(struct l3_process *pc, u8 pr, void *arg) +l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -930,14 +922,14 @@ l3ni1_release_cmpl(struct l3_process *pc pc->para.cause = NO_CAUSE; StopAllL3Timer(pc); newl3state(pc, 0); - L3L4(pc->st, CC_RELEASE | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); ni1_release_l3_process(pc); } #if EXT_BEARER_CAPS -static u8 * -EncodeASyncParams(u8 * p, u8 si2) +static u_char * +EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb p[0] = 0; @@ -1001,8 +993,8 @@ EncodeASyncParams(u8 * p, u8 si2) return p + 3; } -static u8 -EncodeSyncParams(u8 si2, u8 ai) +static u_char +EncodeSyncParams(u_char si2, u_char ai) { switch (si2) { @@ -1046,10 +1038,10 @@ EncodeSyncParams(u8 si2, u8 ai) } -static u8 -DecodeASyncParams(u8 si2, u8 * p) +static u_char +DecodeASyncParams(u_char si2, u_char * p) { - u8 info; + u_char info; switch (p[5]) { case 66: // 1200 bit/s @@ -1103,8 +1095,8 @@ DecodeASyncParams(u8 si2, u8 * p) } -static u8 -DecodeSyncParams(u8 si2, u8 info) +static u_char +DecodeSyncParams(u_char si2, u_char info) { info &= 0x7f; switch (info) { @@ -1144,10 +1136,10 @@ DecodeSyncParams(u8 si2, u8 info) } } -static u8 +static u_char DecodeSI2(struct sk_buff *skb) { - u8 *p; //, *pend=skb->data + skb->len; + u_char *p; //, *pend=skb->data + skb->len; if ((p = findie(skb->data, skb->len, 0x7c, 0))) { switch (p[4] & 0x0f) { @@ -1174,16 +1166,16 @@ DecodeSI2(struct sk_buff *skb) static void -l3ni1_setup_req(struct l3_process *pc, u8 pr, +l3ni1_setup_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[128]; - u8 *p = tmp; + u_char tmp[128]; + u_char *p = tmp; - u8 *teln; - u8 *sub; - u8 *sp; + u_char *teln; + u_char *sub; + u_char *sp; int l; MsgHead(p, pc->callref, MT_SETUP); @@ -1289,7 +1281,7 @@ l3ni1_setup_req(struct l3_process *pc, u } static void -l3ni1_call_proc(struct l3_process *pc, u8 pr, void *arg) +l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int id, ret; @@ -1324,11 +1316,11 @@ l3ni1_call_proc(struct l3_process *pc, u L3AddTimer(&pc->timer, T310, CC_T310); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3ni1_std_ie_err(pc, ret); - L3L4(pc->st, CC_PROCEEDING | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void -l3ni1_setup_ack(struct l3_process *pc, u8 pr, void *arg) +l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int id, ret; @@ -1363,16 +1355,16 @@ l3ni1_setup_ack(struct l3_process *pc, u L3AddTimer(&pc->timer, T304, CC_T304); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3ni1_std_ie_err(pc, ret); - L3L4(pc->st, CC_MORE_INFO | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void -l3ni1_disconnect(struct l3_process *pc, u8 pr, void *arg) +l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; - u8 *p; + u_char *p; int ret; - u8 cause = 0; + u_char cause = 0; StopAllL3Timer(pc); if ((ret = l3ni1_get_cause(pc, skb))) { @@ -1395,7 +1387,7 @@ l3ni1_disconnect(struct l3_process *pc, if (cause) newl3state(pc, 19); if (11 != ret) - L3L4(pc->st, CC_DISCONNECT | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); else if (!cause) l3ni1_release_req(pc, pr, NULL); if (cause) { @@ -1405,7 +1397,7 @@ l3ni1_disconnect(struct l3_process *pc, } static void -l3ni1_connect(struct l3_process *pc, u8 pr, void *arg) +l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -1421,11 +1413,11 @@ l3ni1_connect(struct l3_process *pc, u8 /* here should inserted COLP handling KKe */ if (ret) l3ni1_std_ie_err(pc, ret); - L3L4(pc->st, CC_SETUP | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void -l3ni1_alerting(struct l3_process *pc, u8 pr, void *arg) +l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -1439,13 +1431,13 @@ l3ni1_alerting(struct l3_process *pc, u8 newl3state(pc, 4); if (ret) l3ni1_std_ie_err(pc, ret); - L3L4(pc->st, CC_ALERTING | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void -l3ni1_setup(struct l3_process *pc, u8 pr, void *arg) +l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; int bcfound = 0; char tmp[80]; struct sk_buff *skb = arg; @@ -1456,7 +1448,7 @@ l3ni1_setup(struct l3_process *pc, u8 pr * Bearer Capabilities */ p = skb->data; - /* only the first occurrence 'll be detected ! */ + /* only the first occurence 'll be detected ! */ if ((p = findie(p, skb->len, 0x04, 0))) { if ((p[1] < 2) || (p[1] > 11)) err = 1; @@ -1605,23 +1597,23 @@ l3ni1_setup(struct l3_process *pc, u8 pr newl3state(pc, 6); if (err) /* STATUS for none mandatory IE errors after actions are taken */ l3ni1_std_ie_err(pc, err); - L3L4(pc->st, CC_SETUP | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } static void -l3ni1_reset(struct l3_process *pc, u8 pr, void *arg) +l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) { ni1_release_l3_process(pc); } static void -l3ni1_disconnect_req(struct l3_process *pc, u8 pr, void *arg) +l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[16+40]; - u8 *p = tmp; + u_char tmp[16+40]; + u_char *p = tmp; int l; - u8 cause = 16; + u_char cause = 16; if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; @@ -1654,7 +1646,7 @@ l3ni1_disconnect_req(struct l3_process * } static void -l3ni1_setup_rsp(struct l3_process *pc, u8 pr, +l3ni1_setup_rsp(struct l3_process *pc, u_char pr, void *arg) { if (!pc->para.bchannel) @@ -1672,7 +1664,7 @@ l3ni1_setup_rsp(struct l3_process *pc, u } static void -l3ni1_connect_ack(struct l3_process *pc, u8 pr, void *arg) +l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -1686,17 +1678,17 @@ l3ni1_connect_ack(struct l3_process *pc, L3DelTimer(&pc->timer); if (ret) l3ni1_std_ie_err(pc, ret); - L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); } static void -l3ni1_reject_req(struct l3_process *pc, u8 pr, void *arg) +l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; - u8 cause = 21; + u_char cause = 21; if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; @@ -1713,16 +1705,16 @@ l3ni1_reject_req(struct l3_process *pc, return; memcpy(skb_put(skb, l), tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); ni1_release_l3_process(pc); } static void -l3ni1_release(struct l3_process *pc, u8 pr, void *arg) +l3ni1_release(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; - u8 *p; + u_char *p; int ret, cause=0; StopAllL3Timer(pc); @@ -1747,13 +1739,13 @@ l3ni1_release(struct l3_process *pc, u8 l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); else l3ni1_message(pc, MT_RELEASE_COMPLETE); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); ni1_release_l3_process(pc); } static void -l3ni1_alert_req(struct l3_process *pc, u8 pr, +l3ni1_alert_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 7); @@ -1764,16 +1756,16 @@ l3ni1_alert_req(struct l3_process *pc, u } static void -l3ni1_proceed_req(struct l3_process *pc, u8 pr, +l3ni1_proceed_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 9); l3ni1_message(pc, MT_CALL_PROCEEDING); - L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); } static void -l3ni1_setup_ack_req(struct l3_process *pc, u8 pr, +l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 25); @@ -1786,8 +1778,8 @@ l3ni1_setup_ack_req(struct l3_process *p /* deliver a incoming display message to HL */ /********************************************/ static void -l3ni1_deliver_display(struct l3_process *pc, int pr, u8 *infp) -{ u8 len; +l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; isdn_ctrl ic; struct IsdnCardState *cs; char *p; @@ -1809,11 +1801,11 @@ l3ni1_deliver_display(struct l3_process static void -l3ni1_progress(struct l3_process *pc, u8 pr, void *arg) +l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int err = 0; - u8 *p; + u_char *p; if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { if (p[1] != 2) { @@ -1862,15 +1854,15 @@ l3ni1_progress(struct l3_process *pc, u8 if (err) l3ni1_std_ie_err(pc, err); if (ERR_IE_COMPREHENSION != err) - L3L4(pc->st, CC_PROGRESS | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); } static void -l3ni1_notify(struct l3_process *pc, u8 pr, void *arg) +l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int err = 0; - u8 *p; + u_char *p; if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { if (p[1] != 1) { @@ -1903,11 +1895,11 @@ l3ni1_notify(struct l3_process *pc, u8 p if (err) l3ni1_std_ie_err(pc, err); if (ERR_IE_COMPREHENSION != err) - L3L4(pc->st, CC_NOTIFY | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); } static void -l3ni1_status_enq(struct l3_process *pc, u8 pr, void *arg) +l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) { int ret; struct sk_buff *skb = arg; @@ -1919,11 +1911,11 @@ l3ni1_status_enq(struct l3_process *pc, } static void -l3ni1_information(struct l3_process *pc, u8 pr, void *arg) +l3ni1_information(struct l3_process *pc, u_char pr, void *arg) { int ret; struct sk_buff *skb = arg; - u8 *p; + u_char *p; char tmp[32]; ret = check_infoelements(pc, skb, ie_INFORMATION); @@ -1935,7 +1927,7 @@ l3ni1_information(struct l3_process *pc, if ((p = findie(p, skb->len, 0x70, 0))) { iecpy(tmp, p, 1); strcat(pc->para.setup.eazmsn, tmp); - L3L4(pc->st, CC_MORE_INFO | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } L3AddTimer(&pc->timer, T302, CC_T302); } @@ -1944,14 +1936,14 @@ l3ni1_information(struct l3_process *pc, /******************************/ /* handle deflection requests */ /******************************/ -static void l3ni1_redir_req(struct l3_process *pc, u8 pr, void *arg) +static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[128]; - u8 *p = tmp; - u8 *subp; - u8 len_phone = 0; - u8 len_sub = 0; + u_char tmp[128]; + u_char *p = tmp; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; int l; @@ -2016,7 +2008,7 @@ static void l3ni1_redir_req(struct l3_pr /********************************************/ /* handle deflection request in early state */ /********************************************/ -static void l3ni1_redir_req_early(struct l3_process *pc, u8 pr, void *arg) +static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) { l3ni1_proceed_req(pc,pr,arg); l3ni1_redir_req(pc,pr,arg); @@ -2024,13 +2016,13 @@ static void l3ni1_redir_req_early(struct /***********************************************/ /* handle special commands for this protocol. */ -/* Examples are call independent services like */ +/* Examples are call independant services like */ /* remote operations with dummy callref. */ /***********************************************/ static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) -{ u8 id; - u8 temp[265]; - u8 *p = temp; +{ u_char id; + u_char temp[265]; + u_char *p = temp; int i, l, proc_len; struct sk_buff *skb; struct l3_process *pc = NULL; @@ -2134,9 +2126,9 @@ l3ni1_io_timer(struct l3_process *pc) } /* l3ni1_io_timer */ static void -l3ni1_release_ind(struct l3_process *pc, u8 pr, void *arg) +l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; struct sk_buff *skb = arg; int callState = 0; p = skb->data; @@ -2150,31 +2142,31 @@ l3ni1_release_ind(struct l3_process *pc, /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 * set down layer 3 without sending any message */ - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); ni1_release_l3_process(pc); } else { - L3L4(pc->st, CC_IGNORE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); } } static void -l3ni1_dummy(struct l3_process *pc, u8 pr, void *arg) +l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) { } static void -l3ni1_t302(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 28; /* invalid number */ l3ni1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3ni1_t303(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { pc->N303--; @@ -2183,30 +2175,30 @@ l3ni1_t303(struct l3_process *pc, u8 pr, } else { L3DelTimer(&pc->timer); l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); - L3L4(pc->st, CC_NOSETUP_RSP, pc); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); ni1_release_l3_process(pc); } } static void -l3ni1_t304(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 102; l3ni1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3ni1_t305(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) { - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; struct sk_buff *skb; - u8 cause = 16; + u_char cause = 16; L3DelTimer(&pc->timer); if (pc->para.cause != NO_CAUSE) @@ -2229,27 +2221,27 @@ l3ni1_t305(struct l3_process *pc, u8 pr, } static void -l3ni1_t310(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 102; l3ni1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3ni1_t313(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.loc = 0; pc->para.cause = 102; l3ni1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_CONNECT_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void -l3ni1_t308_1(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 19); L3DelTimer(&pc->timer); @@ -2258,50 +2250,50 @@ l3ni1_t308_1(struct l3_process *pc, u8 p } static void -l3ni1_t308_2(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RELEASE_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); ni1_release_l3_process(pc); } static void -l3ni1_t318(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 102; /* Timer expiry */ pc->para.loc = 0; /* local */ - L3L4(pc->st, CC_RESUME_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); newl3state(pc, 19); l3ni1_message(pc, MT_RELEASE); L3AddTimer(&pc->timer, T308, CC_T308_1); } static void -l3ni1_t319(struct l3_process *pc, u8 pr, void *arg) +l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); pc->para.cause = 102; /* Timer expiry */ pc->para.loc = 0; /* local */ - L3L4(pc->st, CC_SUSPEND_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); newl3state(pc, 10); } static void -l3ni1_restart(struct l3_process *pc, u8 pr, void *arg) +l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); ni1_release_l3_process(pc); } static void -l3ni1_status(struct l3_process *pc, u8 pr, void *arg) +l3ni1_status(struct l3_process *pc, u_char pr, void *arg) { - u8 *p; + u_char *p; struct sk_buff *skb = arg; int ret; - u8 cause = 0, callState = 0; + u_char cause = 0, callState = 0; if ((ret = l3ni1_get_cause(pc, skb))) { if (pc->debug & L3_DEB_WARN) @@ -2329,7 +2321,7 @@ l3ni1_status(struct l3_process *pc, u8 p cause = 99; } if (cause) { - u8 tmp; + u_char tmp; if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); @@ -2347,14 +2339,14 @@ l3ni1_status(struct l3_process *pc, u8 p * if received MT_STATUS with cause == 111 and call * state == 0, then we must set down layer 3 */ - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); ni1_release_l3_process(pc); } } static void -l3ni1_facility(struct l3_process *pc, u8 pr, void *arg) +l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2362,20 +2354,20 @@ l3ni1_facility(struct l3_process *pc, u8 ret = check_infoelements(pc, skb, ie_FACILITY); l3ni1_std_ie_err(pc, ret); { - u8 *p; + u_char *p; if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) l3ni1_parse_facility(pc->st, pc, pc->callref, p); } } static void -l3ni1_suspend_req(struct l3_process *pc, u8 pr, void *arg) +l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[32]; - u8 *p = tmp; - u8 i, l; - u8 *msg = pc->chan->setup.phone; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; MsgHead(p, pc->callref, MT_SUSPEND); l = *msg++; @@ -2398,7 +2390,7 @@ l3ni1_suspend_req(struct l3_process *pc, } static void -l3ni1_suspend_ack(struct l3_process *pc, u8 pr, void *arg) +l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2406,7 +2398,7 @@ l3ni1_suspend_ack(struct l3_process *pc, L3DelTimer(&pc->timer); newl3state(pc, 0); pc->para.cause = NO_CAUSE; - L3L4(pc->st, CC_SUSPEND | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); /* We don't handle suspend_ack for IE errors now */ if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) if (pc->debug & L3_DEB_WARN) @@ -2415,7 +2407,7 @@ l3ni1_suspend_ack(struct l3_process *pc, } static void -l3ni1_suspend_rej(struct l3_process *pc, u8 pr, void *arg) +l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2436,20 +2428,20 @@ l3ni1_suspend_rej(struct l3_process *pc, return; } L3DelTimer(&pc->timer); - L3L4(pc->st, CC_SUSPEND_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); newl3state(pc, 10); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3ni1_std_ie_err(pc, ret); } static void -l3ni1_resume_req(struct l3_process *pc, u8 pr, void *arg) +l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u8 tmp[32]; - u8 *p = tmp; - u8 i, l; - u8 *msg = pc->para.setup.phone; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; MsgHead(p, pc->callref, MT_RESUME); @@ -2473,7 +2465,7 @@ l3ni1_resume_req(struct l3_process *pc, } static void -l3ni1_resume_ack(struct l3_process *pc, u8 pr, void *arg) +l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int id, ret; @@ -2500,14 +2492,14 @@ l3ni1_resume_ack(struct l3_process *pc, return; } L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RESUME | CONFIRM, pc); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); newl3state(pc, 10); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3ni1_std_ie_err(pc, ret); } static void -l3ni1_resume_rej(struct l3_process *pc, u8 pr, void *arg) +l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; int ret; @@ -2528,7 +2520,7 @@ l3ni1_resume_rej(struct l3_process *pc, return; } L3DelTimer(&pc->timer); - L3L4(pc->st, CC_RESUME_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); newl3state(pc, 0); if (ret) /* STATUS for none mandatory IE errors after actions are taken */ l3ni1_std_ie_err(pc, ret); @@ -2536,11 +2528,11 @@ l3ni1_resume_rej(struct l3_process *pc, } static void -l3ni1_global_restart(struct l3_process *pc, u8 pr, void *arg) +l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) { - u8 tmp[32]; - u8 *p; - u8 ri, ch = 0, chan = 0; + u_char tmp[32]; + u_char *p; + u_char ri, ch = 0, chan = 0; int l; struct sk_buff *skb = arg; struct l3_process *up; @@ -2566,9 +2558,9 @@ l3ni1_global_restart(struct l3_process * up = pc->st->l3.proc; while (up) { if ((ri & 7) == 7) - L4L3(up->st, CC_RESTART | REQUEST, up); + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); else if (up->para.bchannel == chan) - L4L3(up->st, CC_RESTART | REQUEST, up); + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); up = up->next; } @@ -2591,26 +2583,26 @@ l3ni1_global_restart(struct l3_process * } static void -l3ni1_dl_reset(struct l3_process *pc, u8 pr, void *arg) +l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) { pc->para.cause = 0x29; /* Temporary failure */ pc->para.loc = 0; l3ni1_disconnect_req(pc, pr, NULL); - L3L4(pc->st, CC_SETUP_ERR, pc); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void -l3ni1_dl_release(struct l3_process *pc, u8 pr, void *arg) +l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 0); pc->para.cause = 0x1b; /* Destination out of order */ pc->para.loc = 0; - L3L4(pc->st, CC_RELEASE | INDICATION, pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } static void -l3ni1_dl_reestablish(struct l3_process *pc, u8 pr, void *arg) +l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T309, CC_T309); @@ -2618,7 +2610,7 @@ l3ni1_dl_reestablish(struct l3_process * } static void -l3ni1_dl_reest_status(struct l3_process *pc, u8 pr, void *arg) +l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); @@ -2626,9 +2618,9 @@ l3ni1_dl_reest_status(struct l3_process l3ni1_status_send(pc, 0, NULL); } -static void l3ni1_SendSpid( struct l3_process *pc, u8 pr, struct sk_buff *skb, int iNewState ) +static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState ) { - u8 * p; + u_char * p; char * pSPID; struct Channel * pChan = pc->st->lli.userdata; int l; @@ -2640,7 +2632,7 @@ static void l3ni1_SendSpid( struct l3_pr { printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn ); newl3state( pc, 0 ); - L3L2( pc->st, DL_RELEASE | REQUEST, NULL ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); return; } @@ -2665,15 +2657,15 @@ static void l3ni1_SendSpid( struct l3_pr L3DelTimer( &pc->timer ); L3AddTimer( &pc->timer, TSPID, CC_TSPID ); - L3L2( pc->st, DL_DATA | REQUEST, skb ); + pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb ); } -static void l3ni1_spid_send( struct l3_process *pc, u8 pr, void *arg ) +static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) { l3ni1_SendSpid( pc, pr, arg, 20 ); } -void l3ni1_spid_epid( struct l3_process *pc, u8 pr, void *arg ) +void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) { struct sk_buff *skb = arg; @@ -2687,7 +2679,7 @@ void l3ni1_spid_epid( struct l3_process dev_kfree_skb( skb); } -static void l3ni1_spid_tout( struct l3_process *pc, u8 pr, void *arg ) +static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg ) { if ( pc->state < 22 ) l3ni1_SendSpid( pc, pr, arg, pc->state+1 ); @@ -2698,7 +2690,7 @@ static void l3ni1_spid_tout( struct l3_p printk( KERN_ERR "SPID not accepted\n" ); newl3state( pc, 0 ); - L3L2( pc->st, DL_RELEASE | REQUEST, NULL ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); } } @@ -2856,10 +2848,10 @@ static struct stateentry manstatelist[] static void global_handler(struct PStack *st, int mt, struct sk_buff *skb) { - u8 tmp[16]; - u8 *p = tmp; + u_char tmp[16]; + u_char *p = tmp; int l; - u_int i; + int i; struct l3_process *proc = st->l3.global; if ( skb ) @@ -2900,10 +2892,9 @@ global_handler(struct PStack *st, int mt static void ni1up(struct PStack *st, int pr, void *arg) { - u_int i; - int mt, cr, cause, callState; + int i, mt, cr, cause, callState; char *ptr; - u8 *p; + u_char *p; struct sk_buff *skb = arg; struct l3_process *proc; @@ -2942,7 +2933,7 @@ ni1up(struct PStack *st, int pr, void *a return; } cr = getcallref(skb->data); - if (skb->len < (u_int)((skb->data[1] & 0x0f) + 3)) { + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { l3_debug(st, "ni1up frame too short(%d)", skb->len); dev_kfree_skb(skb); return; @@ -3087,8 +3078,7 @@ ni1up(struct PStack *st, int pr, void *a static void ni1down(struct PStack *st, int pr, void *arg) { - u_int i; - int cr; + int i, cr; struct l3_process *proc; struct Channel *chan; @@ -3139,7 +3129,7 @@ ni1down(struct PStack *st, int pr, void static void ni1man(struct PStack *st, int pr, void *arg) { - u_int i; + int i; struct l3_process *proc = arg; if (!proc) { @@ -3170,9 +3160,9 @@ setstack_ni1(struct PStack *st) char tmp[64]; int i; - st->l3.l4l3 = ni1down; - st->l3.l4l3_proto = l3ni1_cmd_global; - st->l3.l2l3 = ni1up; + st->lli.l4l3 = ni1down; + st->lli.l4l3_proto = l3ni1_cmd_global; + st->l2.l2l3 = ni1up; st->l3.l3ml3 = ni1man; st->l3.N303 = 1; st->prot.ni1.last_invoke_id = 0; diff -puN drivers/isdn/hisax/Makefile~i4l drivers/isdn/hisax/Makefile --- 25/drivers/isdn/hisax/Makefile~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/Makefile 2004-02-09 22:19:20.000000000 -0800 @@ -1,19 +1,23 @@ # Makefile for the hisax ISDN device driver +# The target object and module list name. + # Define maximum number of cards EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) -# Each configuration option enables a list of files. - obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o +obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o +obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o -obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o -obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_hfcpci.o + +ifdef CONFIG_HISAX_HDLC +obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o +endif # Multipart objects. @@ -21,7 +25,7 @@ hisax_st5481-y := st5481_init.o st54 st5481_b.o st5481_hdlc.o hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o cert.o + lmgr.o q931.o callc.o fsm.o hisax-$(CONFIG_HISAX_EURO) += l3dss1.o hisax-$(CONFIG_HISAX_NI1) += l3ni1.o hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o @@ -33,12 +37,12 @@ hisax-$(CONFIG_HISAX_S0BOX) += s0box.o hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o -hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o -hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o +hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o -hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o \ +hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \ isar.o hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o @@ -51,11 +55,9 @@ hisax-$(CONFIG_HISAX_NICCY) += niccy.o hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o -hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o -hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_W6692) += w6692.o hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o #hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o -CERT = $(shell cd $(src); md5sum -c md5sums.asc > /dev/null 2> /dev/null ;echo $$?) -CFLAGS_cert.o = -DCERTIFICATION=$(CERT) diff -puN -L drivers/isdn/hisax/md5sums.asc drivers/isdn/hisax/md5sums.asc~i4l /dev/null --- 25/drivers/isdn/hisax/md5sums.asc +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,22 +0,0 @@ -# This are valid md5sums for certificated HiSax driver. -# The certification is valid only if the md5sums of all files match. -# The certification is valid only for ELSA Microlink PCI, -# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+, -# HFC-S PCI A based cards and HFC-S USB based isdn tas -# in the moment. -# Read ../../../Documentation/isdn/HiSax.cert for more informations. -# -d08b59f56fb9ed1fbd17713342c75081 isac.c -e81e6e96f307e55f8b9777aca2b356d9 isdnl1.c -cfd2527d9fb01885484cba74bfc67121 isdnl2.c -8c6829f11459f9d044b5768803fb646d isdnl3.c -d40f88dff4191d2660240749cbdcb688 tei.c -3bd3bd05ee4cb25ffe046200b569a83a callc.c -d518f52402ebc3f1be84e09af375313c cert.c -c425de1f8be86e84006de63c9bb3cc5f l3dss1.c -4c411e29d4103ba60e9af4e3e1234a99 l3_1tr6.c -68c6cc2784f208e3247a5a555918d014 elsa.c -8d63a85d7222cf7b40e663e543191d8f diva.c -8c8cb4ce621fb84d8e337a696e75b0df sedlbauer.c -ebe5613d535748409407568435b2be97 hfc_pci.c -# end of md5sums diff -puN drivers/isdn/hisax/mic.c~i4l drivers/isdn/hisax/mic.c --- 25/drivers/isdn/hisax/mic.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/mic.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: mic.c,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $ +/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for mic cards * @@ -18,8 +18,7 @@ extern const char *CardType[]; -const char *mic_revision = "$Revision: 1.10.6.2 $"; -static spinlock_t mic_lock = SPIN_LOCK_UNLOCKED; +const char *mic_revision = "$Revision: 1.12.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -31,146 +30,210 @@ static spinlock_t mic_lock = SPIN_LOCK_U /* CARD_ADR (Write) */ #define MIC_RESET 0x3 /* same as DOS driver */ -static inline u8 -readreg(struct IsdnCardState *cs, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&mic_lock, flags); - byteout(cs->hw.mic.adr, off); + byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&mic_lock, flags); - return (ret); } static inline void -writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&mic_lock, flags); - byteout(cs->hw.mic.adr, off); - byteout(adr, data); - spin_unlock_irqrestore(&mic_lock, flags); + byteout(ale, off); + insb(adr, data, size); } + static inline void -readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - byteout(cs->hw.mic.adr, off); - insb(adr, data, size); + byteout(ale, off); + byteout(adr, data); } static inline void -writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - byteout(cs->hw.mic.adr, off); + byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) -{ - return readreg(cs, cs->hw.mic.isac, offset); -} +/* Interface functions */ -static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - writereg(cs, cs->hw.mic.isac, offset, value); + return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset)); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - readfifo(cs, cs->hw.mic.isac, 0, data, size); + writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) -{ - writefifo(cs, cs->hw.mic.isac, 0, data, size); -} - -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - return readreg(cs, cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)); + readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writereg(cs, cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value); + writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - readfifo(cs, cs->hw.mic.hscx, hscx ? 0x40 : 0, data, size); + return (readreg(cs->hw.mic.adr, + cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0))); } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writefifo(cs, cs->hw.mic.hscx, hscx ? 0x40 : 0, data, size); + writereg(cs->hw.mic.adr, + cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value); } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static struct card_ops mic_ops = { - .init = inithscxisac, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - -static int __init -mic_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->irq = card->para[0]; - cs->hw.mic.cfg_reg = card->para[1]; - cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR; - cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; - cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; - - if (!request_io(&cs->rs, cs->hw.mic.cfg_reg, 8, "mic isdn")) - goto err; - - printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n", - cs->hw.mic.cfg_reg, cs->irq); +/* + * fast interrupt HSCX stuff goes here + */ - cs->card_ops = &mic_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; +#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \ + cs->hw.mic.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \ + cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data) + +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \ + cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \ + cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +mic_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0); + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +void +release_io_mic(struct IsdnCardState *cs) +{ + int bytecnt = 8; + + if (cs->hw.mic.cfg_reg) + release_region(cs->hw.mic.cfg_reg, bytecnt); +} + +static int +mic_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + u_long flags; + + switch (mt) { + case CARD_RESET: + return(0); + case CARD_RELEASE: + release_io_mic(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscx(cs); /* /RTSA := ISAC RST */ + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } int __init setup_mic(struct IsdnCard *card) { + int bytecnt; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, mic_revision); printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_MIC) + return (0); + + bytecnt = 8; + cs->hw.mic.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR; + cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; + cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; - if (mic_probe(card->cs, card) < 0) - return 0; - return 1; + if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.mic.cfg_reg, + cs->hw.mic.cfg_reg + bytecnt); + return (0); + } + printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n", + cs->hw.mic.cfg_reg, cs->irq); + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &mic_card_msg; + cs->irq_func = &mic_interrupt; + ISACVersion(cs, "mic:"); + if (HscxVersion(cs, "mic:")) { + printk(KERN_WARNING + "mic: wrong HSCX versions check IO address\n"); + release_io_mic(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/netjet.c~i4l drivers/isdn/hisax/netjet.c --- 25/drivers/isdn/hisax/netjet.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/netjet.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.24.6.6 2001/09/23 22:24:50 kai Exp $ +/* $Id: netjet.c,v 1.29.2.3 2004/01/13 14:31:26 keil Exp $ * * low level stuff for Traverse Technologie NETJet ISDN cards * @@ -25,63 +25,40 @@ #include #include "netjet.h" -const char *NETjet_revision = "$Revision: 1.24.6.6 $"; -static spinlock_t netjet_lock = SPIN_LOCK_UNLOCKED; +const char *NETjet_revision = "$Revision: 1.29.2.3 $"; /* Interface functions */ -u8 -NETjet_ReadIC(struct IsdnCardState *cs, u8 offset) +u_char +NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) { - unsigned long flags; - u8 ret; + u_char ret; - spin_lock_irqsave(&netjet_lock, flags); cs->hw.njet.auxd &= 0xfc; cs->hw.njet.auxd |= (offset>>4) & 3; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2)); - spin_unlock_irqrestore(&netjet_lock, flags); return(ret); } void -NETjet_WriteIC(struct IsdnCardState *cs, u8 offset, u8 value) +NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) { - unsigned long flags; - - spin_lock_irqsave(&netjet_lock, flags); cs->hw.njet.auxd &= 0xfc; cs->hw.njet.auxd |= (offset>>4) & 3; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value); - spin_unlock_irqrestore(&netjet_lock, flags); } void -NETjet_ReadICfifo(struct IsdnCardState *cs, u8 *data, int size) +NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); insb(cs->hw.njet.isac, data, size); } -void -NETjet_WriteICfifo(struct IsdnCardState *cs, u8 *data, int size) -{ - cs->hw.njet.auxd &= 0xfc; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - outsb(cs->hw.njet.isac, data, size); -} - -struct dc_hw_ops netjet_dc_ops = { - .read_reg = NETjet_ReadIC, - .write_reg = NETjet_WriteIC, - .read_fifo = NETjet_ReadICfifo, - .write_fifo = NETjet_WriteICfifo, -}; - -static u16 fcstab[256] = +__u16 fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, @@ -117,7 +94,15 @@ static u16 fcstab[256] = 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u8 fill) +void +NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) +{ + cs->hw.njet.auxd &= 0xfc; + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + outsb(cs->hw.njet.isac, data, size); +} + +void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) { u_int mask=0x000000ff, val = 0, *p=pos; u_int i; @@ -140,7 +125,7 @@ void mode_tiger(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - u8 led; + u_char led; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "Tiger mode %d bchan %d/%d", @@ -216,11 +201,11 @@ mode_tiger(struct BCState *bcs, int mode bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); } -static void printframe(struct IsdnCardState *cs, u8 *buf, int count, char *s) { +static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { char tmp[128]; char *t = tmp; int i=count,j; - u8 *p = buf; + u_char *p = buf; t += sprintf(t, "tiger %s(%4d)", s, count); while (i>0) { @@ -269,11 +254,11 @@ static void printframe(struct IsdnCardSt static int make_raw_data(struct BCState *bcs) { // this make_raw is for 64k register u_int i,s_cnt=0; - register u8 j; - register u8 val; - register u8 s_one = 0; - register u8 s_val = 0; - register u8 bitcnt = 0; + register u_char j; + register u_char val; + register u_char s_one = 0; + register u_char s_val = 0; + register u_char bitcnt = 0; u_int fcs; if (!bcs->tx_skb) { @@ -359,11 +344,11 @@ static int make_raw_data(struct BCState static int make_raw_data_56k(struct BCState *bcs) { // this make_raw is for 56k register u_int i,s_cnt=0; - register u8 j; - register u8 val; - register u8 s_one = 0; - register u8 s_val = 0; - register u8 bitcnt = 0; + register u_char j; + register u_char val; + register u_char s_one = 0; + register u_char s_val = 0; + register u_char bitcnt = 0; u_int fcs; if (!bcs->tx_skb) { @@ -439,7 +424,8 @@ static void got_frame(struct BCState *bc memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } - sched_b_event(bcs, B_RCVBUFREADY); + test_and_set_bit(B_RCVBUFREADY, &bcs->event); + schedule_work(&bcs->tqueue); if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME) printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec"); @@ -449,16 +435,16 @@ static void got_frame(struct BCState *bc static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ int i; - register u8 j; - register u8 val; + register u_char j; + register u_char val; u_int *pend = bcs->hw.tiger.rec +NETJET_DMA_RXSIZE -1; - register u8 state = bcs->hw.tiger.r_state; - register u8 r_one = bcs->hw.tiger.r_one; - register u8 r_val = bcs->hw.tiger.r_val; + register u_char state = bcs->hw.tiger.r_state; + register u_char r_one = bcs->hw.tiger.r_one; + register u_char r_val = bcs->hw.tiger.r_val; register u_int bitcnt = bcs->hw.tiger.r_bitcnt; u_int *p = buf; int bits; - u8 mask; + u_char mask; if (bcs->mode == L1_MODE_HDLC) { // it's 64k mask = 0xff; @@ -682,9 +668,7 @@ void netjet_fill_dma(struct BCState *bcs if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { - p = inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR) - - bcs->hw.tiger.send_dma - + bcs->hw.tiger.send; + p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); sp = bcs->hw.tiger.sendp; if (p == bcs->hw.tiger.s_end) p = bcs->hw.tiger.send -1; @@ -705,9 +689,7 @@ void netjet_fill_dma(struct BCState *bcs write_raw(bcs, p, bcs->hw.tiger.free - cnt); } } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) { - p = inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR) - - bcs->hw.tiger.send_dma - + bcs->hw.tiger.send; + p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); cnt = bcs->hw.tiger.s_end - p; if (cnt < 2) { p = bcs->hw.tiger.send + 1; @@ -729,7 +711,7 @@ void netjet_fill_dma(struct BCState *bcs static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { u_int mask, val, *p=buf; - int i, s_cnt; + u_int i, s_cnt; if (cnt <= 0) return; @@ -766,7 +748,11 @@ static void write_raw(struct BCState *bc if (!bcs->tx_skb) { debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt); } else { - xmit_complete_b(bcs); + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->hw.tiger.free = cnt - s_cnt; @@ -790,7 +776,8 @@ static void write_raw(struct BCState *bc debugl1(bcs->cs, "tiger write_raw: fill rest %d", cnt - s_cnt); } - sched_b_event(bcs, B_XMTBUFREADY); + test_and_set_bit(B_XMTBUFREADY, &bcs->event); + schedule_work(&bcs->tqueue); } } } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { @@ -838,36 +825,59 @@ void write_tiger(struct IsdnCardState *c static void tiger_l2l1(struct PStack *st, int pr, void *arg) { + struct BCState *bcs = st->l1.bcs; struct sk_buff *skb = arg; - struct IsdnCardState *cs = st->l1.bcs->cs; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n"); + } else { + bcs->tx_skb = skb; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc); - if (cs->hw.njet.bc_activate) - (cs->hw.njet.bc_activate)(cs, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + mode_tiger(bcs, st->l1.mode, st->l1.bc); + /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ + spin_unlock_irqrestore(&bcs->cs->lock, flags); + bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc)); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): - if (cs->hw.njet.bc_deactivate) - (cs->hw.njet.bc_deactivate)(cs, st->l1.bc); + /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ + bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc)); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - mode_tiger(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + mode_tiger(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -928,7 +938,7 @@ setstack_tiger(struct PStack *st, struct if (open_tigerstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = tiger_l2l1; + st->l2.l2l1 = tiger_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); @@ -936,47 +946,32 @@ setstack_tiger(struct PStack *st, struct } -static struct bc_l1_ops netjet_l1_ops = { - .fill_fifo = netjet_fill_dma, - .open = setstack_tiger, - .close = close_tigerstate, -}; - void __init inittiger(struct IsdnCardState *cs) { - cs->bc_l1_ops = &netjet_l1_ops; - - cs->bcs[0].hw.tiger.send = - pci_alloc_consistent(cs->hw.njet.pdev, - NETJET_DMA_TXSIZE * sizeof(unsigned int), - &cs->bcs[0].hw.tiger.send_dma); - if (!cs->bcs[0].hw.tiger.send) { + if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int), + GFP_KERNEL | GFP_DMA))) { printk(KERN_WARNING "HiSax: No memory for tiger.send\n"); return; } - cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; - - cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send; - cs->bcs[1].hw.tiger.send_dma = cs->bcs[0].hw.tiger.send_dma; - cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; + cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE/2 - 1; + cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; + cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send; + cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq; + cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int)); debugl1(cs, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send, (u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1)); - outl(cs->bcs[0].hw.tiger.send_dma, + outl(virt_to_bus(cs->bcs[0].hw.tiger.send), cs->hw.njet.base + NETJET_DMA_READ_START); - outl(cs->bcs[0].hw.tiger.send_dma + NETJET_DMA_TXSIZE/2 - 1, + outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq), cs->hw.njet.base + NETJET_DMA_READ_IRQ); - outl(cs->bcs[0].hw.tiger.send_dma + NETJET_DMA_TXSIZE - 1, + outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end), cs->hw.njet.base + NETJET_DMA_READ_END); - - cs->bcs[0].hw.tiger.rec = - pci_alloc_consistent(cs->hw.njet.pdev, - NETJET_DMA_RXSIZE * sizeof(unsigned int), - &cs->bcs[0].hw.tiger.rec_dma); - if (!cs->bcs[0].hw.tiger.rec) { + if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_RXSIZE * sizeof(unsigned int), + GFP_KERNEL | GFP_DMA))) { printk(KERN_WARNING "HiSax: No memory for tiger.rec\n"); return; @@ -984,39 +979,36 @@ inittiger(struct IsdnCardState *cs) debugl1(cs, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec, (u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1)); cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec; - cs->bcs[1].hw.tiger.rec_dma = cs->bcs[0].hw.tiger.rec_dma; memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int)); - outl(cs->bcs[0].hw.tiger.rec_dma, + outl(virt_to_bus(cs->bcs[0].hw.tiger.rec), cs->hw.njet.base + NETJET_DMA_WRITE_START); - outl(cs->bcs[0].hw.tiger.rec_dma + NETJET_DMA_RXSIZE/2 - 1, + outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE/2 - 1), cs->hw.njet.base + NETJET_DMA_WRITE_IRQ); - outl(cs->bcs[0].hw.tiger.rec_dma + NETJET_DMA_RXSIZE - 1, + outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1), cs->hw.njet.base + NETJET_DMA_WRITE_END); debugl1(cs, "tiger: dmacfg %x/%x pulse=%d", inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); cs->hw.njet.last_is0 = 0; + cs->bcs[0].BC_SetStack = setstack_tiger; + cs->bcs[1].BC_SetStack = setstack_tiger; + cs->bcs[0].BC_Close = close_tigerstate; + cs->bcs[1].BC_Close = close_tigerstate; } -static void +void releasetiger(struct IsdnCardState *cs) { if (cs->bcs[0].hw.tiger.send) { - pci_free_consistent(cs->hw.njet.pdev, - NETJET_DMA_TXSIZE * sizeof(unsigned int), - cs->bcs[0].hw.tiger.send, - cs->bcs[0].hw.tiger.send_dma); + kfree(cs->bcs[0].hw.tiger.send); cs->bcs[0].hw.tiger.send = NULL; } if (cs->bcs[1].hw.tiger.send) { cs->bcs[1].hw.tiger.send = NULL; } if (cs->bcs[0].hw.tiger.rec) { - pci_free_consistent(cs->hw.njet.pdev, - NETJET_DMA_RXSIZE * sizeof(unsigned int), - cs->bcs[0].hw.tiger.rec, - cs->bcs[0].hw.tiger.rec_dma); + kfree(cs->bcs[0].hw.tiger.rec); cs->bcs[0].hw.tiger.rec = NULL; } if (cs->bcs[1].hw.tiger.rec) { @@ -1025,11 +1017,11 @@ releasetiger(struct IsdnCardState *cs) } void -netjet_release(struct IsdnCardState *cs) +release_io_netjet(struct IsdnCardState *cs) { byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0); releasetiger(cs); - hisax_release_resources(cs); + release_region(cs->hw.njet.base, 256); } diff -puN drivers/isdn/hisax/netjet.h~i4l drivers/isdn/hisax/netjet.h --- 25/drivers/isdn/hisax/netjet.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/netjet.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: netjet.h,v 2.5.6.3 2001/09/23 22:24:50 kai Exp $ +/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $ * * NETjet common header file * @@ -57,12 +57,10 @@ extern const char *CardType[]; #define HDLC_FLAG_VALUE 0x7e -extern struct dc_hw_ops netjet_dc_ops; - -u8 NETjet_ReadIC(struct IsdnCardState *cs, u8 offset); -void NETjet_WriteIC(struct IsdnCardState *cs, u8 offset, u8 value); -void NETjet_ReadICfifo(struct IsdnCardState *cs, u8 *data, int size); -void NETjet_WriteICfifo(struct IsdnCardState *cs, u8 *data, int size); +u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); +void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); +void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); +void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); void read_tiger(struct IsdnCardState *cs); void write_tiger(struct IsdnCardState *cs); @@ -70,5 +68,5 @@ void write_tiger(struct IsdnCardState *c void netjet_fill_dma(struct BCState *bcs); void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs); void inittiger(struct IsdnCardState *cs); -void netjet_release(struct IsdnCardState *cs); +void release_io_netjet(struct IsdnCardState *cs); diff -puN drivers/isdn/hisax/niccy.c~i4l drivers/isdn/hisax/niccy.c --- 25/drivers/isdn/hisax/niccy.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/niccy.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: niccy.c,v 1.15.6.6 2001/10/20 22:08:24 kai Exp $ +/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) @@ -24,8 +24,7 @@ #include extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.15.6.6 $"; -static spinlock_t niccy_lock = SPIN_LOCK_UNLOCKED; +const char *niccy_revision = "$Revision: 1.21.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -47,127 +46,140 @@ static spinlock_t niccy_lock = SPIN_LOCK #define PCI_IRQ_DISABLE 0xff0000 #define PCI_IRQ_ASSERT 0x800000 -static inline u8 -readreg(unsigned int ale, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&niccy_lock, flags); byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&niccy_lock, flags); - return ret; + return (ret); } static inline void -writereg(unsigned int ale, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&niccy_lock, flags); byteout(ale, off); - byteout(adr, data); - spin_unlock_irqrestore(&niccy_lock, flags); + insb(adr, data, size); } + static inline void -readfifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { byteout(ale, off); - insb(adr, data, size); + byteout(adr, data); } static inline void -writefifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset); + return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs->hw.niccy.hscx_ale, - cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.niccy.hscx_ale, + cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0))); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - readfifo(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, - hscx ? 0x40 : 0, data, size); -} +#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \ + cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \ + cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data) -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - writefifo(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, - hscx ? 0x40 : 0, data, size); -} +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \ + cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt) -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \ + cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" static irqreturn_t niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - + u_char val; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); if (cs->subtyp == NICCY_PCI) { int ival; ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */ + if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */ + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; + } outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); } - return hscxisac_irq(intno, dev_id, regs); + val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } void -niccy_release(struct IsdnCardState *cs) +release_io_niccy(struct IsdnCardState *cs) { if (cs->subtyp == NICCY_PCI) { int val; @@ -175,11 +187,15 @@ niccy_release(struct IsdnCardState *cs) val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); val &= PCI_IRQ_DISABLE; outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + release_region(cs->hw.niccy.cfg_reg, 0x40); + release_region(cs->hw.niccy.isac, 4); + } else { + release_region(cs->hw.niccy.isac, 2); + release_region(cs->hw.niccy.isac_ale, 2); } - hisax_release_resources(cs); } -static int +static void niccy_reset(struct IsdnCardState *cs) { if (cs->subtyp == NICCY_PCI) { @@ -189,78 +205,32 @@ niccy_reset(struct IsdnCardState *cs) val |= PCI_IRQ_ENABLE; outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); } - return 0; + inithscxisac(cs, 3); } -static struct card_ops niccy_ops = { - .init = inithscxisac, - .reset = niccy_reset, - .release = niccy_release, - .irq_func = niccy_interrupt, -}; - -static int __init -niccy_probe(struct IsdnCardState *cs) +static int +niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n", - CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI", - cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); - cs->card_ops = &niccy_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - return -EBUSY; - return 0; -} - -static int __init -niccy_pnp_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = NICCY_PNP; - cs->irq = card->para[0]; - cs->hw.niccy.isac = card->para[1] + ISAC_PNP; - cs->hw.niccy.hscx = card->para[1] + HSCX_PNP; - cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP; - cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP; - cs->hw.niccy.cfg_reg = 0; - - if (!request_io(&cs->rs, cs->hw.niccy.isac, 2, "niccy data")) - goto err; - if (!request_io(&cs->rs, cs->hw.niccy.isac_ale, 2, "niccy addr")) - goto err; - if (niccy_probe(cs) < 0) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -niccy_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - u32 pci_ioaddr; - - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = NICCY_PCI; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.niccy.cfg_reg = pci_resource_start(pdev, 0); - pci_ioaddr = pci_resource_start(pdev, 1); - cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; - cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR; - cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA; - cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; - if (!request_io(&cs->rs, cs->hw.niccy.isac, 4, "niccy")) - goto err; - if (!request_io(&cs->rs, cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) - goto err; - if (niccy_probe(cs) < 0) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + u_long flags; + + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + niccy_reset(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_niccy(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + niccy_reset(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } static struct pci_dev *niccy_dev __initdata = NULL; @@ -271,62 +241,149 @@ static struct pnp_card *pnp_c __devinitd int __init setup_niccy(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, niccy_revision); printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NICCY) + return (0); #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; + struct pnp_dev *pnp_d = NULL; + int err; - if ((pb = pnp_find_card( + if ((pnp_c = pnp_find_card( ISAPNP_VENDOR('S', 'D', 'A'), ISAPNP_FUNCTION(0x0150), pnp_c))) { - pnp_c = pb; - pd = NULL; - if (!(pd = pnp_find_dev(pnp_c, + if (!(pnp_d = pnp_find_dev(pnp_c, ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pd))) { + ISAPNP_FUNCTION(0x0150), pnp_d))) { printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n"); return (0); } - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "NiccyPnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "NiccyPnP: activate failed\n"); - pnp_device_detach(pd); - return 0; + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0) || !pnp_port_valid(pd, 1)) { + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[2] = pnp_port_start(pnp_d, 1); + card->para[0] = pnp_irq(pnp_d, 0);; + if (!card->para[0] || !card->para[1] || !card->para[2]) { printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0), pnp_port_start(pd, 1)); - pnp_device_detach(pd); + card->para[0], card->para[1], card->para[2]); + pnp_disable_dev(pnp_d); return(0); } - card->para[1] = pnp_port_start(pd, 0); - card->para[2] = pnp_port_start(pd, 1); - card->para[0] = pnp_irq(pd, 0); } else { printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n"); } } #endif if (card->para[1]) { - if (niccy_pnp_probe(card->cs, card) < 0) - return 0; - return 1; + cs->hw.niccy.isac = card->para[1] + ISAC_PNP; + cs->hw.niccy.hscx = card->para[1] + HSCX_PNP; + cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP; + cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP; + cs->hw.niccy.cfg_reg = 0; + cs->subtyp = NICCY_PNP; + cs->irq = card->para[0]; + if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) { + printk(KERN_WARNING + "HiSax: %s data port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.isac, + cs->hw.niccy.isac + 1); + return (0); + } + if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) { + printk(KERN_WARNING + "HiSax: %s address port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.isac_ale, + cs->hw.niccy.isac_ale + 1); + release_region(cs->hw.niccy.isac, 2); + return (0); + } } else { -#ifdef CONFIG_PCI +#if CONFIG_PCI + u_int pci_ioaddr; + cs->subtyp = 0; if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { - if (niccy_pci_probe(card->cs, niccy_dev) < 0) - return 0; - return 1; + if (pci_enable_device(niccy_dev)) + return(0); + /* get IRQ */ + if (!niccy_dev->irq) { + printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); + return(0); + } + cs->irq = niccy_dev->irq; + cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); + if (!cs->hw.niccy.cfg_reg) { + printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); + return(0); + } + pci_ioaddr = pci_resource_start(niccy_dev, 1); + if (!pci_ioaddr) { + printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); + return(0); + } + cs->subtyp = NICCY_PCI; + } else { + printk(KERN_WARNING "Niccy: No PCI card found\n"); + return(0); + } + cs->irq_flags |= SA_SHIRQ; + cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; + cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR; + cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA; + cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; + if (!request_region(cs->hw.niccy.isac, 4, "niccy")) { + printk(KERN_WARNING + "HiSax: %s data port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.isac, + cs->hw.niccy.isac + 4); + return (0); + } + if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) { + printk(KERN_WARNING + "HiSax: %s pci port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.cfg_reg, + cs->hw.niccy.cfg_reg + 0x40); + release_region(cs->hw.niccy.isac, 4); + return (0); } +#else + printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n"); + printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n"); + return (0); #endif /* CONFIG_PCI */ } - return 0; + printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n", + CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI", + cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &niccy_card_msg; + cs->irq_func = &niccy_interrupt; + ISACVersion(cs, "Niccy:"); + if (HscxVersion(cs, "Niccy:")) { + printk(KERN_WARNING + "Niccy: wrong HSCX versions check IO address\n"); + release_io_niccy(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/nj_s.c~i4l drivers/isdn/hisax/nj_s.c --- 25/drivers/isdn/hisax/nj_s.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/nj_s.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: nj_s.c,v 2.7.6.6 2001/09/23 22:24:50 kai Exp $ +/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $ * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. @@ -15,43 +15,74 @@ #include #include "netjet.h" -const char *NETjet_S_revision = "$Revision: 2.7.6.6 $"; +const char *NETjet_S_revision = "$Revision: 2.13.2.4 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} static irqreturn_t -nj_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val, sval; + u_char val, s1val, s0val; + u_long flags; - spin_lock(&cs->lock); - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { + spin_lock_irqsave(&cs->lock, flags); + s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1); + if (!(s1val & NETJET_ISACIRQ)) { val = NETjet_ReadIC(cs, ISAC_ISTA); if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); + debugl1(cs, "tiger: i1 %x %x", s1val, val); if (val) { isac_interrupt(cs, val); NETjet_WriteIC(cs, ISAC_MASK, 0xFF); NETjet_WriteIC(cs, ISAC_MASK, 0x0); } - } + s1val = 1; + } else + s1val = 0; + /* + * read/write stat0 is better, because lower IRQ rate + * Note the IRQ is on for 125 us if a condition match + * thats long on modern CPU and so the IRQ is reentered + * all the time. + */ + s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0); + if ((s0val | s1val)==0) { // shared IRQ + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; + } + if (s0val) + byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); /* start new code 13/07/00 GE */ /* set bits in sval to indicate which page is free */ if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) /* the 2nd write page is free */ - sval = 0x08; + s0val = 0x08; else /* the 1st write page is free */ - sval = 0x04; + s0val = 0x04; if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) /* the 2nd read page is free */ - sval = sval | 0x02; + s0val |= 0x02; else /* the 1st read page is free */ - sval = sval | 0x01; - if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */ + s0val |= 0x01; + if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ { - cs->hw.njet.irqstat0 = sval; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n", + cs->hw.njet.last_is0, s0val); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED;; + } + cs->hw.njet.irqstat0 = s0val; if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) /* we have a read dma int */ @@ -61,112 +92,58 @@ nj_s_interrupt(int intno, void *dev_id, /* we have a write dma int */ write_tiger(cs); /* end new code 13/07/00 GE */ + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } -/* if (!testcnt--) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } -*/ - spin_unlock(&cs->lock); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static int -nj_s_reset(struct IsdnCardState *cs) +static void +reset_netjet_s(struct IsdnCardState *cs) { cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ + mdelay(10); + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ /* now edge triggered for TJ320 GE 13/07/00 */ + /* see comment in IRQ function */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + mdelay(10); cs->hw.njet.auxd = 0; cs->hw.njet.dmactrl = 0; byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - return 0; } -static void -nj_s_init(struct IsdnCardState *cs) -{ - inittiger(cs); - initisac(cs); -} - -static struct card_ops nj_s_ops = { - .init = nj_s_init, - .reset = nj_s_reset, - .release = netjet_release, - .irq_func = nj_s_interrupt, -}; - -static int __init -nj_s_probe(struct IsdnCardState *cs, struct pci_dev *pdev) +static int +NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - if (pci_enable_device(pdev)) - goto err; - - pci_set_master(pdev); + u_long flags; - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.njet.pdev = pdev; - cs->hw.njet.base = pci_resource_start(pdev, 0); - if (!request_io(&cs->rs, cs->hw.njet.base, 0x100, "netjet-s isdn")) - return 0; - - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - - byteout(cs->hw.njet.auxa, 0); - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - - switch ((NETjet_ReadIC(cs, ISAC_RBCH) >> 5) & 3) { - case 0 : - break; - case 3 : - printk(KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" ); - goto err; - default : - printk(KERN_WARNING "NETjet-S: No PCI card found\n" ); - goto err; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_netjet_s(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + reset_netjet_s(cs); + inittiger(cs); + spin_lock_irqsave(&cs->lock, flags); + clear_pending_isac_ints(cs); + initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); } - printk(KERN_INFO - "NETjet-S: PCI card configured at %#lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - - nj_s_reset(cs); - cs->irq_flags |= SA_SHIRQ; - cs->card_ops = &nj_s_ops; - isac_setup(cs, &netjet_dc_ops); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return(0); } static struct pci_dev *dev_netjet __initdata = NULL; @@ -174,32 +151,116 @@ static struct pci_dev *dev_netjet __init int __init setup_netjet_s(struct IsdnCard *card) { + int bytecnt; + struct IsdnCardState *cs = card->cs; char tmp[64]; #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif strcpy(tmp, NETjet_S_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", - HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_S) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + +#if CONFIG_PCI - dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet); - if (dev_netjet) { - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */ - if (dev_netjet->subsystem_vendor == 0x55 && - dev_netjet->subsystem_device == 0x02) { - printk(KERN_WARNING "Netjet: You tried to load this " - "driver with an incompatible TigerJet-card\n"); - printk(KERN_WARNING "Use type=41 for Formula-n " - "enter:now ISDN PCI and compatible\n"); - return 0; + for ( ;; ) + { + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + pci_set_master(dev_netjet); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); + return(0); + } + /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */ + if ((dev_netjet->subsystem_vendor == 0x55) && + (dev_netjet->subsystem_device == 0x02)) { + printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n"); + printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n"); + return(0); + } + /* end new code */ + } else { + printk(KERN_WARNING "NETjet-S: No PCI card found\n"); + return(0); } - if (nj_s_probe(card->cs, dev_netjet)) - return 1; - return 0; + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + mdelay(10); + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + mdelay(10); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) ) + { + case 0 : + break; + + case 3 : + printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETjet-S: No PCI card found\n" ); + return 0; + } + break; } - printk(KERN_WARNING "NETjet-S: No PCI card found\n"); - return 0; -} +#else + + printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + printk(KERN_INFO + "NETjet-S: PCI card configured at %#lx IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %#lx-%#lx already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + setup_isac(cs); + cs->cardmsg = &NETjet_S_card_msg; + cs->irq_func = &netjet_s_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "NETjet-S:"); + return (1); +} diff -puN drivers/isdn/hisax/nj_u.c~i4l drivers/isdn/hisax/nj_u.c --- 25/drivers/isdn/hisax/nj_u.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/nj_u.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: nj_u.c,v 2.8.6.6 2001/09/23 22:24:50 kai Exp $ +/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $ * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. @@ -15,15 +15,25 @@ #include #include "netjet.h" -const char *NETjet_U_revision = "$Revision: 2.8.6.6 $"; +const char *NETjet_U_revision = "$Revision: 2.14.2.3 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} static irqreturn_t -nj_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) +netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val, sval; + u_char val, sval; + u_long flags; - spin_lock(&cs->lock); + spin_lock_irqsave(&cs->lock, flags); if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & NETJET_ISACIRQ)) { val = NETjet_ReadIC(cs, ICC_ISTA); @@ -51,6 +61,10 @@ nj_u_interrupt(int intno, void *dev_id, sval = sval | 0x01; if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */ { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; + } cs->hw.njet.irqstat0 = sval; if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) @@ -61,113 +75,58 @@ nj_u_interrupt(int intno, void *dev_id, /* we have a write dma int */ write_tiger(cs); /* end new code 13/07/00 GE */ + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } -/* if (!testcnt--) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } -*/ - spin_unlock(&cs->lock); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static int -nj_u_reset(struct IsdnCardState *cs) +static void +reset_netjet_u(struct IsdnCardState *cs) { cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + mdelay(10); cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ /* now edge triggered for TJ320 GE 13/07/00 */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - + mdelay(10); cs->hw.njet.auxd = 0xC0; cs->hw.njet.dmactrl = 0; byteout(cs->hw.njet.auxa, 0); byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - return 0; } -static void -nj_u_init(struct IsdnCardState *cs) +static int +NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - inittiger(cs); - initicc(cs); - /* Reenable all IRQ */ - NETjet_WriteIC(cs, ICC_MASK, 0); -} - -static struct card_ops nj_u_ops = { - .init = nj_u_init, - .reset = nj_u_reset, - .release = netjet_release, - .irq_func = nj_u_interrupt, -}; - -static int __init -nj_u_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - pci_set_master(pdev); - - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.njet.pdev = pdev; - cs->hw.njet.base = pci_resource_start(pdev, 0); - if (!request_io(&cs->rs, cs->hw.njet.base, 0x100, "netspider-u isdn")) - goto err; - - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + u_long flags; - switch ((NETjet_ReadIC(cs, ICC_RBCH) >> 5) & 3) { - case 3: - break; - case 0: - printk(KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" ); - goto err; - default: - printk(KERN_WARNING "NETspider-U: No PCI card found\n" ); - goto err; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_netjet_u(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inittiger(cs); + reset_netjet_u(cs); + clear_pending_icc_ints(cs); + initicc(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); } - printk(KERN_INFO "NETspider-U: PCI card configured at %#lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - - nj_u_reset(cs); - cs->card_ops = &nj_u_ops; - icc_setup(cs, &netjet_dc_ops); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return(0); } static struct pci_dev *dev_netjet __initdata = NULL; @@ -175,21 +134,111 @@ static struct pci_dev *dev_netjet __init int __init setup_netjet_u(struct IsdnCard *card) { + int bytecnt; + struct IsdnCardState *cs = card->cs; char tmp[64]; +#if CONFIG_PCI +#endif #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif strcpy(tmp, NETjet_U_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", - HiSax_getrev(tmp)); - - dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet); - if (dev_netjet) { - if (nj_u_probe(card->cs, dev_netjet)) - return 1; - return 0; + printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_U) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + +#if CONFIG_PCI + + for ( ;; ) + { + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + pci_set_master(dev_netjet); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETspider-U: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + mdelay(10); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + mdelay(10); + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + mdelay(10); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) ) + { + case 3 : + break; + + case 0 : + printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETspider-U: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETspider-U: PCI card configured at %#lx IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %#lx-%#lx already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); } - printk(KERN_WARNING "NETspider-U: No PCI card found\n"); - return 0; + setup_icc(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_U_card_msg; + cs->irq_func = &netjet_u_interrupt; + cs->irq_flags |= SA_SHIRQ; + ICCVersion(cs, "NETspider-U:"); + return (1); } diff -puN drivers/isdn/hisax/q931.c~i4l drivers/isdn/hisax/q931.c --- 25/drivers/isdn/hisax/q931.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/q931.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.10.6.3 2001/09/23 22:24:50 kai Exp $ +/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $ * * code to decode ITU Q.931 call control messages * @@ -21,9 +21,9 @@ #include "l3_1tr6.h" void -iecpy(u8 * dest, u8 * iestart, int ieoffset) +iecpy(u_char * dest, u_char * iestart, int ieoffset) { - u8 *p; + u_char *p; int l; p = iestart + ieoffset + 2; @@ -38,7 +38,7 @@ iecpy(u8 * dest, u8 * iestart, int ieoff */ static struct MessageType { - u8 nr; + u_char nr; char *descr; } mtlist[] = { @@ -198,7 +198,7 @@ struct MessageType mt_n1[] = static int -prbits(char *dest, u8 b, int start, int len) +prbits(char *dest, u_char b, int start, int len) { char *dp = dest; @@ -214,8 +214,8 @@ prbits(char *dest, u8 b, int start, int } static -u8 * -skipext(u8 * p) +u_char * +skipext(u_char * p) { while (!(*p++ & 0x80)); return (p); @@ -230,7 +230,7 @@ skipext(u8 * p) static struct CauseValue { - u8 nr; + u_char nr; char *edescr; char *ddescr; } cvlist[] = { @@ -442,11 +442,11 @@ struct CauseValue { static int -prcause(char *dest, u8 * p) +prcause(char *dest, u_char * p) { - u8 *end; + u_char *end; char *dp = dest; - u_int i, cause; + int i, cause; end = p + p[1] + 1; p += 2; @@ -519,7 +519,7 @@ struct MessageType cause_1tr6[] = int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); static int -prcause_1tr6(char *dest, u8 * p) +prcause_1tr6(char *dest, u_char * p) { char *dp = dest; int i, cause; @@ -554,7 +554,7 @@ prcause_1tr6(char *dest, u8 * p) } static int -prchident(char *dest, u8 * p) +prchident(char *dest, u_char * p) { char *dp = dest; @@ -566,7 +566,7 @@ prchident(char *dest, u8 * p) } static int -prcalled(char *dest, u8 * p) +prcalled(char *dest, u_char * p) { int l; char *dp = dest; @@ -583,7 +583,7 @@ prcalled(char *dest, u8 * p) return (dp - dest); } static int -prcalling(char *dest, u8 * p) +prcalling(char *dest, u_char * p) { int l; char *dp = dest; @@ -610,7 +610,7 @@ prcalling(char *dest, u8 * p) static int -prbearer(char *dest, u8 * p) +prbearer(char *dest, u_char * p) { char *dp = dest, ch; @@ -658,10 +658,10 @@ prbearer(char *dest, u8 * p) static int -prbearer_ni1(char *dest, u8 * p) +prbearer_ni1(char *dest, u_char * p) { char *dp = dest; - u8 len; + u_char len; p++; len = *p++; @@ -715,7 +715,7 @@ prbearer_ni1(char *dest, u8 * p) } static int -general(char *dest, u8 * p) +general(char *dest, u_char * p) { char *dp = dest; char ch = ' '; @@ -742,7 +742,7 @@ general(char *dest, u8 * p) } static int -general_ni1(char *dest, u8 * p) +general_ni1(char *dest, u_char * p) { char *dp = dest; char ch = ' '; @@ -769,7 +769,7 @@ general_ni1(char *dest, u8 * p) } static int -prcharge(char *dest, u8 * p) +prcharge(char *dest, u_char * p) { char *dp = dest; int l; @@ -786,7 +786,7 @@ prcharge(char *dest, u8 * p) return (dp - dest); } static int -prtext(char *dest, u8 * p) +prtext(char *dest, u_char * p) { char *dp = dest; int l; @@ -802,7 +802,7 @@ prtext(char *dest, u8 * p) } static int -prfeatureind(char *dest, u8 * p) +prfeatureind(char *dest, u_char * p) { char *dp = dest; @@ -839,7 +839,7 @@ prfeatureind(char *dest, u8 * p) static struct DTag { /* Display tags */ - u8 nr; + u_char nr; char *descr; } dtaglist[] = { { 0x82, "Continuation" }, @@ -868,11 +868,10 @@ struct DTag { /* Display tags */ #define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) static int -disptext_ni1(char *dest, u8 * p) +disptext_ni1(char *dest, u_char * p) { char *dp = dest; - int l, tag, len; - u_int i; + int l, tag, len, i; p++; l = *p++ - 1; @@ -908,7 +907,7 @@ disptext_ni1(char *dest, u8 * p) return (dp - dest); } static int -display(char *dest, u8 * p) +display(char *dest, u_char * p) { char *dp = dest; char ch = ' '; @@ -937,7 +936,7 @@ display(char *dest, u8 * p) } int -prfacility(char *dest, u8 * p) +prfacility(char *dest, u_char * p) { char *dp = dest; int l, l2; @@ -968,9 +967,9 @@ prfacility(char *dest, u8 * p) static struct InformationElement { - u8 nr; + u_char nr; char *descr; - int (*f) (char *, u8 *); + int (*f) (char *, u_char *); } ielist[] = { { @@ -1149,11 +1148,11 @@ static struct InformationElement we_6[] #define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) int -QuickHex(char *txt, u8 * p, int cnt) +QuickHex(char *txt, u_char * p, int cnt) { register int i; register char *t = txt; - register u8 w; + register u_char w; for (i = 0; i < cnt; i++) { *t++ = ' '; @@ -1173,7 +1172,7 @@ QuickHex(char *txt, u8 * p, int cnt) } void -LogFrame(struct IsdnCardState *cs, u8 * buf, int size) +LogFrame(struct IsdnCardState *cs, u_char * buf, int size) { char *dp; @@ -1197,11 +1196,11 @@ LogFrame(struct IsdnCardState *cs, u8 * void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) { - u8 *bend, *buf; + u_char *bend, *buf; char *dp; unsigned char pd, cr_l, cr, mt; unsigned char sapi, tei, ftyp; - u_int i, cset = 0, cs_old = 0, cs_fest = 0; + int i, cset = 0, cs_old = 0, cs_fest = 0; int size, finish = 0; if (skb->len < 3) diff -puN -L drivers/isdn/hisax/rawhdlc.c drivers/isdn/hisax/rawhdlc.c~i4l /dev/null --- 25/drivers/isdn/hisax/rawhdlc.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,543 +0,0 @@ -/* $Id: rawhdlc.c,v 1.5.6.2 2001/09/23 22:24:51 kai Exp $ - * - * support routines for cards that don't support HDLC - * - * Author Brent Baccala - * Copyright by Karsten Keil - * by Brent Baccala - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * - * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930, - * don't perform HDLC encapsulation over the B channel. Drivers for - * such cards use support routines in this file to perform B channel HDLC. - * - * Bit-synchronous HDLC encapsulation is a means of encapsulating packets - * over a continuously transmitting serial communications link. - * It looks like this: - * - * 11111111101111110...........0111111011111111111 - * iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii - * - * i = idle f = flag d = data - * - * When idle, the channel sends a continuous string of ones (mark - * idle; illustrated), or a continuous string of flag characters (flag - * idle). The beginning of a data frame is marked by a flag character - * (01111110), then comes the actual data, followed by another flag - * character, after which another frame may be sent immediately (a - * single flag may serve as both the end of one frame and the start of - * the next), or the link may return to idle. Obviously, the flag - * character can not appear anywhere in the data (or a false - * end-of-frame would occur), so the transmitter performs - * "bit-stuffing" - inserting a zero bit after every five one bits, - * irregardless of the original bit after the five ones. Byte - * ordering is irrelevant at this point - the data is treated as a - * string of bits, not bytes. Since no more than 5 ones may now occur - * in a row, the flag sequence, with its 6 ones, is unique. - * - * Upon reception, a zero bit that occur after 5 one bits is simply - * discarded. A series of 6 one bits is end-of-frame, and a series of - * 7 one bits is an abort. Once bit-stuffing has been corrected for, - * an integer number of bytes should now be present. The last two - * of these bytes form the Frame Check Sequence, a CRC that is verified - * and then discarded. Note that bit-stuffing is performed on the FCS - * just as if it were regular data. - * - * - * - * int make_raw_hdlc_data(u8 *src, u_int slen, - * u8 *dst, u_int dsize) - * - * Used for transmission. Copies slen bytes from src to dst, performing - * HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process. - * dsize is size of destination buffer, and should be at least - * ((6*slen)/5)+5 bytes to ensure adequate space will be available. - * Function returns length (in bytes) of valid destination buffer, or - * 0 upon destination overflow. - * - * void init_hdlc_state(struct hdlc_state *stateptr, int mode) - * - * Initializes hdlc_state structure before first call to read_raw_hdlc_data - * - * mode = 0: Sane mode - * mode = 1/2: - * Insane mode; NETJet use a shared unsigned int memory block ( - * with busmaster DMA), the bit pattern of every word is - * <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> - * according to Siemens IOM-2 interface, so we have to handle - * the src buffer as unsigned int and have to shift/mask the - * B-channel bytes. - * mode 1 -> B1 mode 2 -> B2 data is used - * - * int read_raw_hdlc_data(struct hdlc_state *saved_state, - * u8 *src, u_int slen, - * u8 *dst, u_int dsize) - * - * Used for reception. Scans source buffer bit-by-bit looking for - * valid HDLC frames, which are copied to destination buffer. HDLC - * state information is stored in a structure, which allows this - * function to process frames spread across several blocks of raw - * HDLC data. Part of the state information is bit offsets into - * the source and destination buffers. - * - * A return value >0 indicates the length of a valid frame, now - * stored in the destination buffer. In this case, the source - * buffer might not be completely processed, so this function should - * be called again with the same source buffer, possibly with a - * different destination buffer. - * - * A return value of zero indicates that the source buffer was - * completely processed without finding a valid end-of-packet; - * however, we might be in the middle of packet reception, so - * the function should be called again with the next block of - * raw HDLC data and the same destination buffer. It is NOT - * permitted to change the destination buffer in this case, - * since data may already have begun to be stored there. - * - * A return value of -1 indicates some kind of error - destination - * buffer overflow, CRC check failed, frame not a multiple of 8 - * bits. Destination buffer probably contains invalid data, which - * should be discarded. Call function again with same source buffer - * and a new (or same) destination buffer. - * - * Suggested calling sequence: - * - * init_hdlc_state(...); - * for (EACH_RAW_DATA_BLOCK) { - * while (len = read_raw_hdlc_data(...)) { - * if (len == -1) DISCARD_FRAME; - * else PROCESS_FRAME; - * } - * } - * - * - * Test the code in this file as follows: - * gcc -DDEBUGME -o rawhdlctest rawhdlc.c - * ./rawhdlctest < rawdata - * - * The file "rawdata" can be easily generated from a HISAX B-channel - * hex dump (CF CF CF 02 ...) using the following perl script: - * - * while(<>) { - * @hexlist = split ' '; - * while ($hexstr = shift(@hexlist)) { - * printf "%c", hex($hexstr); - * } - * } - * - */ - -#ifdef DEBUGME -#include -#endif - -#include -#include -#include "rawhdlc.h" - -/* There's actually an identical copy of this table in the PPP code - * (ppp_crc16_table), but I don't want this code dependent on PPP - */ - -// static -__u16 fcstab[256] = -{ - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e - - -#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \ - bitcnt++;\ - out_val >>= 1;\ - if (val & 1) {\ - s_one++;\ - out_val |= 0x80;\ - } else {\ - s_one = 0;\ - out_val &= 0x7f;\ - }\ - if (bitcnt==8) {\ - if (d_cnt == dsize) return 0;\ - dst[d_cnt++] = out_val;\ - bitcnt = 0;\ - }\ - if (s_one == 5) {\ - out_val >>= 1;\ - out_val &= 0x7f;\ - bitcnt++;\ - s_one = 0;\ - }\ - if (bitcnt==8) {\ - if (d_cnt == dsize) return 0;\ - dst[d_cnt++] = out_val;\ - bitcnt = 0;\ - }\ - val >>= 1;\ - } - -/* Optimization suggestion: If needed, this function could be - * dramatically sped up using a state machine. Each state would - * correspond to having seen N one bits, and being offset M bits into - * the current output byte. N ranges from 0 to 4, M from 0 to 7, so - * we need 5*8 = 35 states. Each state would have a table with 256 - * entries, one for each input character. Each entry would contain - * three output characters, an output state, an a byte increment - * that's either 1 or 2. All this could fit in four bytes; so we need - * 4 bytes * 256 characters = 1 KB for each state (35 KB total). Zero - * the output buffer before you start. For each character in your - * input, you look it up in the current state's table and get three - * bytes to be or'ed into the output at the current byte offset, and - * an byte increment to move your pointer forward. A simple Perl - * script could generate the tables. Given HDLC semantics, probably - * would be better to set output to all 1s, then use ands instead of ors. - * A smaller state machine could operate on nibbles instead of bytes. - * A state machine for 32-bit architectures could use word offsets - * instead of byte offsets, requiring 5*32 = 160 states; probably - * best to work on nibbles in such a case. - */ - - -int make_raw_hdlc_data(u8 *src, u_int slen, u8 *dst, u_int dsize) -{ - register u_int i,d_cnt=0; - register u8 j; - register u8 val; - register u8 s_one = 0; - register u8 out_val = 0; - register u8 bitcnt = 0; - u_int fcs; - - - dst[d_cnt++] = HDLC_FLAG_VALUE; - fcs = PPP_INITFCS; - for (i=0; i>8) & 0xff; - MAKE_RAW_BYTE; - val = HDLC_FLAG_VALUE; - for (j=0; j<8; j++) { - bitcnt++; - out_val >>= 1; - if (val & 1) - out_val |= 0x80; - else - out_val &= 0x7f; - if (bitcnt==8) { - if (d_cnt == dsize) return 0; - dst[d_cnt++] = out_val; - bitcnt = 0; - } - val >>= 1; - } - if (bitcnt) { - while (8>bitcnt++) { - out_val >>= 1; - out_val |= 0x80; - } - if (d_cnt == dsize) return 0; - dst[d_cnt++] = out_val; - } - - return d_cnt; -} - -void init_hdlc_state(struct hdlc_state *stateptr, int mode) -{ - stateptr->state = HDLC_ZERO_SEARCH; - stateptr->r_one = 0; - stateptr->r_val = 0; - stateptr->o_bitcnt = 0; - stateptr->i_bitcnt = 0; - stateptr->insane_mode = mode; -} - -/* Optimization suggestion: A similar state machine could surely - * be developed for this function as well. - */ - -int read_raw_hdlc_data(struct hdlc_state *saved_state, - u8 *src, u_int slen, u8 *dst, u_int dsize) -{ - int retval=0; - register u8 val; - register u8 state = saved_state->state; - register u8 r_one = saved_state->r_one; - register u8 r_val = saved_state->r_val; - register u_int o_bitcnt = saved_state->o_bitcnt; - register u_int i_bitcnt = saved_state->i_bitcnt; - register u_int fcs = saved_state->fcs; - register u_int *isrc = (u_int *) src; - - /* Use i_bitcnt (bit offset into source buffer) to reload "val" - * in case we're starting up again partway through a source buffer - */ - - if ((i_bitcnt >> 3) < slen) { - if (saved_state->insane_mode==1) { - val = isrc[(i_bitcnt >> 3)] & 0xff; - } else if (saved_state->insane_mode==2) { - val = (isrc[i_bitcnt >> 3] >>8) & 0xff; - } else { - val = src[i_bitcnt >> 3]; - } - val >>= i_bitcnt & 7; - } - - /* One bit per loop. Keep going until we've got something to - * report (retval != 0), or we exhaust the source buffer - */ - - while ((retval == 0) && ((i_bitcnt >> 3) < slen)) { - if ((i_bitcnt & 7) == 0) { - if (saved_state->insane_mode==1) { - val = isrc[(i_bitcnt >> 3)] & 0xff; - } else if (saved_state->insane_mode==2) { - val = (isrc[i_bitcnt >> 3] >>8) & 0xff; - } else { - val = src[i_bitcnt >> 3]; - } -#ifdef DEBUGME - printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val); -#endif - if (val == 0xff) { - state = HDLC_ZERO_SEARCH; - o_bitcnt = 0; - r_one = 0; - i_bitcnt += 8; - continue; - } - } - -#ifdef DEBUGME - /* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/ -#endif - - if (state == HDLC_ZERO_SEARCH) { - if (val & 1) { - r_one++; - } else { - r_one=0; - state= HDLC_FLAG_SEARCH; - } - } else if (state == HDLC_FLAG_SEARCH) { - if (val & 1) { - r_one++; - if (r_one>6) { - state=HDLC_ZERO_SEARCH; - } - } else { - if (r_one==6) { - o_bitcnt=0; - r_val=0; - state=HDLC_FLAG_FOUND; - } - r_one=0; - } - } else if (state == HDLC_FLAG_FOUND) { - if (val & 1) { - r_one++; - if (r_one>6) { - state=HDLC_ZERO_SEARCH; - } else { - r_val >>= 1; - r_val |= 0x80; - o_bitcnt++; - } - } else { - if (r_one==6) { - o_bitcnt=0; - r_val=0; - r_one=0; - i_bitcnt++; - val >>= 1; - continue; - } else if (r_one!=5) { - r_val >>= 1; - r_val &= 0x7f; - o_bitcnt++; - } - r_one=0; - } - if ((state != HDLC_ZERO_SEARCH) && - !(o_bitcnt & 7)) { -#ifdef DEBUGME - printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt); -#endif - state=HDLC_FRAME_FOUND; - fcs = PPP_INITFCS; - dst[0] = r_val; - fcs = PPP_FCS (fcs, r_val); - } - } else if (state == HDLC_FRAME_FOUND) { - if (val & 1) { - r_one++; - if (r_one>6) { - state=HDLC_ZERO_SEARCH; - o_bitcnt=0; - } else { - r_val >>= 1; - r_val |= 0x80; - o_bitcnt++; - } - } else { - if (r_one==6) { - r_val=0; - r_one=0; - o_bitcnt++; - if (o_bitcnt & 7) { - /* Alignment error */ -#ifdef DEBUGME - printf("Alignment error\n"); -#endif - state=HDLC_FLAG_SEARCH; - retval = -1; - } else if (fcs==PPP_GOODFCS) { - /* Valid frame */ - state=HDLC_FLAG_FOUND; - retval = (o_bitcnt>>3)-3; - } else { - /* CRC error */ -#ifdef DEBUGME - printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS); -#endif - state=HDLC_FLAG_FOUND; - retval = -1; - } - } else if (r_one==5) { - r_one=0; - i_bitcnt++; - val >>= 1; - continue; - } else { - r_val >>= 1; - r_val &= 0x7f; - o_bitcnt++; - } - r_one=0; - } - if ((state == HDLC_FRAME_FOUND) && - !(o_bitcnt & 7)) { - if ((o_bitcnt>>3)>=dsize) { - /* Buffer overflow error */ -#ifdef DEBUGME - printf("Buffer overflow error\n"); -#endif - r_val=0; - state=HDLC_FLAG_SEARCH; - retval = -1; - } else { - dst[(o_bitcnt>>3)-1] = r_val; - fcs = PPP_FCS (fcs, r_val); -#ifdef DEBUGME - printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs); -#endif - } - } - } - i_bitcnt ++; - val >>= 1; - } - - /* We exhausted the source buffer before anything else happened - * (retval==0). Reset i_bitcnt in expectation of a new source - * buffer. Other, we either had an error or a valid frame, so - * reset o_bitcnt in expectation of a new destination buffer. - */ - - if (retval == 0) { - i_bitcnt = 0; - } else { - o_bitcnt = 0; - } - - saved_state->state = state; - saved_state->r_one = r_one; - saved_state->r_val = r_val; - saved_state->fcs = fcs; - saved_state->o_bitcnt = o_bitcnt; - saved_state->i_bitcnt = i_bitcnt; - - return (retval); -} - - - -#ifdef DEBUGME - -char buffer[1024]; -char obuffer[1024]; - -main() -{ - int buflen=0; - int len; - struct hdlc_state hdlc_state; - - while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++; - - printf("buflen = %d\n", buflen); - - init_hdlc_state(&hdlc_state, 0); - - while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) { - if (len == -1) printf("Error @ byte %d/bit %d\n", - hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7); - else { - printf("Frame received: len %d\n", len); - } - } - - printf("Done\n"); -} - -#endif diff -puN -L drivers/isdn/hisax/rawhdlc.h drivers/isdn/hisax/rawhdlc.h~i4l /dev/null --- 25/drivers/isdn/hisax/rawhdlc.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,28 +0,0 @@ -/* $Id: rawhdlc.h,v 1.3.6.2 2001/09/23 22:24:51 kai Exp $ - * - * Author Brent Baccala - * Copyright by Brent Baccala - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef RAWHDLC_H -struct hdlc_state { - char insane_mode; - u8 state; - u8 r_one; - u8 r_val; - u_int o_bitcnt; - u_int i_bitcnt; - u_int fcs; -}; - - -int make_raw_hdlc_data(u8 *src, u_int slen, u8 *dst, u_int dsize); -void init_hdlc_state(struct hdlc_state *stateptr, int mode); -int read_raw_hdlc_data(struct hdlc_state *saved_state, - u8 *src, u_int slen, u8 *dst, u_int dsize); -#define RAWHDLC_H -#endif diff -puN drivers/isdn/hisax/s0box.c~i4l drivers/isdn/hisax/s0box.c --- 25/drivers/isdn/hisax/s0box.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/s0box.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: s0box.c,v 2.4.6.2 2001/09/23 22:24:51 kai Exp $ +/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for Creatix S0BOX * @@ -17,16 +17,10 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *s0box_revision = "$Revision: 2.4.6.2 $"; -static spinlock_t s0box_lock = SPIN_LOCK_UNLOCKED; +const char *s0box_revision = "$Revision: 2.6.2.4 $"; static inline void -writereg(struct IsdnCardState *cs, int addr, u8 off, u8 val) -{ - unsigned long flags; - unsigned long padr = cs->hw.teles3.cfg_reg; - - spin_lock_irqsave(&s0box_lock, flags); +writereg(unsigned int padr, signed int addr, u_char off, u_char val) { outb_p(0x1c,padr+2); outb_p(0x14,padr+2); outb_p((addr+off)&0x7f,padr); @@ -35,21 +29,16 @@ writereg(struct IsdnCardState *cs, int a outb_p(0x17,padr+2); outb_p(0x14,padr+2); outb_p(0x1c,padr+2); - spin_unlock_irqrestore(&s0box_lock, flags); } -static u8 nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf, +static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 4, 0xc, 2, 0xa, 6, 0xe } ; -static inline u8 -readreg(struct IsdnCardState *cs, int addr, u8 off) -{ - u8 n1, n2; - unsigned long flags; - unsigned long padr = cs->hw.teles3.cfg_reg; +static inline u_char +readreg(unsigned int padr, signed int addr, u_char off) { + register u_char n1, n2; - spin_lock_irqsave(&s0box_lock, flags); outb_p(0x1c,padr+2); outb_p(0x14,padr+2); outb_p((addr+off)|0x80,padr); @@ -60,16 +49,14 @@ readreg(struct IsdnCardState *cs, int ad n2 = (inb_p(padr+1) >> 3) & 0x17; outb_p(0x14,padr+2); outb_p(0x1c,padr+2); - spin_unlock_irqrestore(&s0box_lock, flags); return nibtab[n1] | (nibtab[n2] << 4); } static inline void -read_fifo(struct IsdnCardState *cs, signed int adr, u8 * data, int size) +read_fifo(unsigned int padr, signed int adr, u_char * data, int size) { int i; - u8 n1, n2; - unsigned long padr = cs->hw.teles3.cfg_reg; + register u_char n1, n2; outb_p(0x1c, padr+2); outb_p(0x14, padr+2); @@ -84,14 +71,13 @@ read_fifo(struct IsdnCardState *cs, sign } outb_p(0x14,padr+2); outb_p(0x1c,padr+2); + return; } static inline void -write_fifo(struct IsdnCardState *cs, signed int adr, u8 * data, int size) +write_fifo(unsigned int padr, signed int adr, u_char * data, int size) { int i; - unsigned long padr = cs->hw.teles3.cfg_reg; - outb_p(0x1c, padr+2); outb_p(0x14, padr+2); outb_p(adr&0x7f, padr); @@ -102,79 +88,140 @@ write_fifo(struct IsdnCardState *cs, sig } outb_p(0x14,padr+2); outb_p(0x1c,padr+2); + return; } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.teles3.isac, offset); + return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.teles3.isac, offset, value); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - read_fifo(cs, cs->hw.teles3.isacfifo, data, size); + read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - write_fifo(cs, cs->hw.teles3.isacfifo, data, size); + write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs, cs->hw.teles3.hscx[hscx], offset); + return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writereg(cs, cs->hw.teles3.hscx[hscx], offset, value); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - read_fifo(cs, cs->hw.teles3.hscxfifo[hscx], data, size); +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ +#define MAXCOUNT 5 + struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + int count = 0; + + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + count++; + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); + if (val && count < MAXCOUNT) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); + if (val && count < MAXCOUNT) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (count >= MAXCOUNT) + printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +void +release_io_s0box(struct IsdnCardState *cs) +{ + release_region(cs->hw.teles3.cfg_reg, 8); +} + +static int +S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + u_long flags; + + switch (mt) { + case CARD_RESET: + break; + case CARD_RELEASE: + release_io_s0box(cs); + break; + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + break; + case CARD_TEST: + break; + } + return(0); } -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +int __init +setup_s0box(struct IsdnCard *card) { - write_fifo(cs, cs->hw.teles3.hscxfifo[hscx], data, size); -} + struct IsdnCardState *cs = card->cs; + char tmp[64]; -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static struct card_ops s0box_ops = { - .init = inithscxisac, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; + strcpy(tmp, s0box_revision); + printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_S0BOX) + return (0); -static int __init -s0box_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ cs->hw.teles3.cfg_reg = card->para[1]; cs->hw.teles3.hscx[0] = -0x20; cs->hw.teles3.hscx[1] = 0x0; @@ -183,32 +230,37 @@ s0box_probe(struct IsdnCardState *cs, st cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; cs->irq = card->para[0]; - if (!request_io(&cs->rs, cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) - goto err; + if (!request_region(cs->hw.teles3.cfg_reg,8, "S0Box parallel I/O")) { + printk(KERN_WARNING + "HiSax: %s ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.teles3.cfg_reg, + cs->hw.teles3.cfg_reg + 7); + return 0; + } printk(KERN_INFO - "HiSax: %s config irq:%d isac:0x%x cfg:0x%x\n", - CardType[cs->typ], cs->irq, - cs->hw.teles3.isac, cs->hw.teles3.cfg_reg); + "HiSax: %s config irq:%d isac:0x%x cfg:0x%x\n", + CardType[cs->typ], cs->irq, + cs->hw.teles3.isac, cs->hw.teles3.cfg_reg); printk(KERN_INFO - "HiSax: hscx A:0x%x hscx B:0x%x\n", - cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]); - cs->card_ops = &s0box_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -int __init -setup_s0box(struct IsdnCard *card) -{ - char tmp[64]; - - strcpy(tmp, s0box_revision); - printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp)); - if (s0box_probe(card->cs, card)) - return 0; - return 1; + "HiSax: hscx A:0x%x hscx B:0x%x\n", + cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]); + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &S0Box_card_msg; + cs->irq_func = &s0box_interrupt; + ISACVersion(cs, "S0Box:"); + if (HscxVersion(cs, "S0Box:")) { + printk(KERN_WARNING + "S0Box: wrong HSCX versions check IO address\n"); + release_io_s0box(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/saphir.c~i4l drivers/isdn/hisax/saphir.c --- 25/drivers/isdn/hisax/saphir.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/saphir.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: saphir.c,v 1.8.6.2 2001/09/23 22:24:51 kai Exp $ +/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for HST Saphir 1 * @@ -19,8 +19,7 @@ #include "isdnl1.h" extern const char *CardType[]; -static char *saphir_rev = "$Revision: 1.8.6.2 $"; -static spinlock_t saphir_lock = SPIN_LOCK_UNLOCKED; +static char *saphir_rev = "$Revision: 1.10.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -32,138 +31,160 @@ static spinlock_t saphir_lock = SPIN_LOC #define SPARE_REG 4 #define RESET_REG 5 -static inline u8 -readreg(struct IsdnCardState *cs, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&saphir_lock, flags); - byteout(cs->hw.saphir.ale, off); + byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&saphir_lock, flags); - return ret; + return (ret); } static inline void -writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&saphir_lock, flags); - byteout(cs->hw.saphir.ale, off); - byteout(adr, data); - spin_unlock_irqrestore(&saphir_lock, flags); + byteout(ale, off); + insb(adr, data, size); } + static inline void -readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 *data, int size) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - byteout(cs->hw.saphir.ale, off); - insb(adr, data, size); + byteout(ale, off); + byteout(adr, data); } static inline void -writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 *data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - byteout(cs->hw.saphir.ale, off); + byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.saphir.isac, offset); + return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.saphir.isac, offset, value); + writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.saphir.isac, 0, data, size); + readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.saphir.isac, 0, data, size); + writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs, cs->hw.saphir.hscx, offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, + offset + (hscx ? 0x40 : 0))); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writereg(cs, cs->hw.saphir.hscx, offset + (hscx ? 0x40 : 0), value); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, + offset + (hscx ? 0x40 : 0), value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - readfifo(cs, cs->hw.saphir.hscx, hscx ? 0x40 : 0, data, size); -} +#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data) -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - writefifo(cs, cs->hw.saphir.hscx, hscx ? 0x40 : 0, data, size); -} +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +#include "hscx_irq.c" static irqreturn_t saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - irqreturn_t ret; + u_char val; + u_long flags; - ret = hscxisac_irq(intno, dev_id, regs); - mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ); - return ret; + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + /* Watchdog */ + if (cs->hw.saphir.timer.function) + mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ); + else + printk(KERN_WARNING "saphir: Spurious timer!\n"); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } static void SaphirWatchDog(struct IsdnCardState *cs) { + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); /* 5 sec WatchDog, so read at least every 4 sec */ - isac_read(cs, ISAC_RBCH); + cs->readisac(cs, ISAC_RBCH); + spin_unlock_irqrestore(&cs->lock, flags); mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ); } -static void -saphir_release(struct IsdnCardState *cs) +void +release_io_saphir(struct IsdnCardState *cs) { byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); - del_timer_sync(&cs->hw.saphir.timer); + del_timer(&cs->hw.saphir.timer); cs->hw.saphir.timer.function = NULL; - hisax_release_resources(cs); + if (cs->hw.saphir.cfg_reg) + release_region(cs->hw.saphir.cfg_reg, 6); } static int saphir_reset(struct IsdnCardState *cs) { - u8 irq_val; + u_char irq_val; switch(cs->irq) { case 5: irq_val = 0; @@ -186,66 +207,94 @@ saphir_reset(struct IsdnCardState *cs) } byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ + mdelay(10); byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ + mdelay(10); byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02); return (0); } -static struct card_ops saphir_ops = { - .init = inithscxisac, - .reset = saphir_reset, - .release = saphir_release, - .irq_func = saphir_interrupt, -}; +static int +saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + u_long flags; + + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + saphir_reset(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_saphir(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} -static int __init -saphir_probe(struct IsdnCardState *cs, struct IsdnCard *card) + +int __init +setup_saphir(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, saphir_rev); + printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_HSTSAPHIR) + return (0); + + /* IO-Ports */ cs->hw.saphir.cfg_reg = card->para[1]; cs->hw.saphir.isac = card->para[1] + ISAC_DATA; cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; cs->irq = card->para[0]; - - if (!request_io(&cs->rs, cs->hw.saphir.cfg_reg, 6, "saphir")) - goto err; + if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.saphir.cfg_reg, + cs->hw.saphir.cfg_reg + 5); + return (0); + } printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n", - CardType[cs->typ], cs->irq, cs->hw.saphir.cfg_reg); + CardType[cs->typ], cs->irq, cs->hw.saphir.cfg_reg); - if (saphir_reset(cs)) - goto err; - - cs->card_ops = &saphir_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - - init_timer(&cs->hw.saphir.timer); + setup_isac(cs); cs->hw.saphir.timer.function = (void *) SaphirWatchDog; cs->hw.saphir.timer.data = (long) cs; + init_timer(&cs->hw.saphir.timer); cs->hw.saphir.timer.expires = jiffies + 4*HZ; add_timer(&cs->hw.saphir.timer); - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -int __init -setup_saphir(struct IsdnCard *card) -{ - char tmp[64]; - - strcpy(tmp, saphir_rev); - printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", - HiSax_getrev(tmp)); - - if (saphir_probe(card->cs, card) < 0) - return 0; - return 1; + if (saphir_reset(cs)) { + release_io_saphir(cs); + return (0); + } + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &saphir_card_msg; + cs->irq_func = &saphir_interrupt; + ISACVersion(cs, "saphir:"); + if (HscxVersion(cs, "saphir:")) { + printk(KERN_WARNING + "saphir: wrong HSCX versions check IO address\n"); + release_io_saphir(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/sedlbauer.c~i4l drivers/isdn/hisax/sedlbauer.c --- 25/drivers/isdn/hisax/sedlbauer.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/sedlbauer.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.25.6.6 2001/09/23 22:24:51 kai Exp $ +/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $ * * low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -50,16 +50,16 @@ #include extern const char *CardType[]; -static spinlock_t sedlbauer_lock = SPIN_LOCK_UNLOCKED; -const char *Sedlbauer_revision = "$Revision: 1.25.6.6 $"; +const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pyramid", "speed fax+ pci"}; + "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"}; #define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_HST_SAPHIR3 0x52 #define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 #define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 #define PCI_SUB_ID_SEDLBAUER 0x01 @@ -72,7 +72,9 @@ const char *Sedlbauer_Types[] = #define SEDL_SPEED_PCI 6 #define SEDL_SPEEDFAX_PYRAMID 7 #define SEDL_SPEEDFAX_PCI 8 +#define HST_SAPHIR3 9 +#define SEDL_CHIP_TEST 0 #define SEDL_CHIP_ISAC_HSCX 1 #define SEDL_CHIP_ISAC_ISAR 2 #define SEDL_CHIP_IPAC 3 @@ -117,209 +119,264 @@ const char *Sedlbauer_Types[] = #define SEDL_RESET 0x3 /* same as DOS driver */ -static inline u8 -readreg(struct IsdnCardState *cs, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - u8 ret; - unsigned long flags; + register u_char ret; - spin_lock_irqsave(&sedlbauer_lock, flags); - byteout(cs->hw.sedl.adr, off); + byteout(ale, off); ret = bytein(adr); - spin_unlock_irqrestore(&sedlbauer_lock, flags); - return ret; + return (ret); } static inline void -readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - unsigned long flags; - - spin_lock_irqsave(&sedlbauer_lock, flags); - byteout(cs->hw.sedl.adr, off); + byteout(ale, off); insb(adr, data, size); - spin_unlock_irqrestore(&sedlbauer_lock, flags); } static inline void -writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - byteout(cs->hw.sedl.adr, off); + byteout(ale, off); byteout(adr, data); } static inline void -writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - byteout(cs->hw.sedl.adr, off); + byteout(ale, off); outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.sedl.isac, offset); + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.sedl.isac, offset, value); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.sedl.isac, 0, data, size); + readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.sedl.isac, 0, data, size); + writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs, cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)); + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs, cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value); } static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs, cs->hw.sedl.hscx, hscx ? 0x40 : 0, data, size); + readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs, cs->hw.sedl.hscx, hscx ? 0x40 : 0, data, size); + writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - -static inline u8 -ipac_read(struct IsdnCardState *cs, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs, cs->hw.sedl.isac, offset); + return (readreg(cs->hw.sedl.adr, + cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0))); } -static inline void -ipac_write(struct IsdnCardState *cs, u8 offset, u8 value) -{ - writereg(cs, cs->hw.sedl.isac, offset, value); -} - -static inline void -ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) -{ - readfifo(cs, cs->hw.sedl.isac, offset, data, size); -} - -static inline void -ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size) +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { - writefifo(cs, cs->hw.sedl.isac, offset, data, size); + writereg(cs->hw.sedl.adr, + cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value); } -/* This will generate ipac_dc_ops and ipac_bc_ops using the functions - * above */ - -BUILD_IPAC_OPS(ipac); - - /* ISAR access routines * mode = 0 access with IRQ on * mode = 1 access with IRQ off * mode = 2 access with IRQ off and using last offset */ -static u8 -isar_read(struct IsdnCardState *cs, int mode, u8 offset) +static u_char +ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) { if (mode == 0) - return readreg(cs, cs->hw.sedl.hscx, offset); - - if (mode == 1) + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset)); + else if (mode == 1) byteout(cs->hw.sedl.adr, offset); - - return bytein(cs->hw.sedl.hscx); + return(bytein(cs->hw.sedl.hscx)); } static void -isar_write(struct IsdnCardState *cs, int mode, u8 offset, u8 value) +WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) { if (mode == 0) - return writereg(cs, cs->hw.sedl.hscx, offset, value); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value); + else { + if (mode == 1) + byteout(cs->hw.sedl.adr, offset); + byteout(cs->hw.sedl.hscx, value); + } +} - if (mode == 1) - byteout(cs->hw.sedl.adr, offset); +/* + * fast interrupt HSCX stuff goes here + */ - byteout(cs->hw.sedl.hscx, value); -} +#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \ + cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \ + cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data) -static struct bc_hw_ops isar_ops = { - .read_reg = isar_read, - .write_reg = isar_write, -}; +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \ + cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \ + cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" static irqreturn_t sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + spin_lock_irqsave(&cs->lock, flags); if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { /* The card tends to generate interrupts while being removed causing us to just crash the kernel. bad. */ + spin_unlock_irqrestore(&cs->lock, flags); printk(KERN_WARNING "Sedlbauer: card not available!\n"); return IRQ_NONE; } - return hscxisac_irq(intno, dev_id, regs); + + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t +sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 5; + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); + ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; } static irqreturn_t -sedlbauer_isar_interrupt(int intno, void *dev_id, struct pt_regs *regs) +sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; + u_char val; int cnt = 5; + u_long flags; - spin_lock(&cs->lock); - val = isar_read(cs, 0, ISAR_IRQBIT); + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); Start_ISAR: if (val & ISAR_IRQSTA) isar_int_main(cs); - val = isac_read(cs, ISAC_ISTA); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); Start_ISAC: if (val) isac_interrupt(cs, val); - val = isar_read(cs, 0, ISAR_IRQBIT); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); if ((val & ISAR_IRQSTA) && --cnt) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "ISAR IntStat after IntRoutine"); goto Start_ISAR; } - val = isac_read(cs, ISAC_ISTA); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); if (val && --cnt) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC IntStat after IntRoutine"); @@ -329,362 +386,131 @@ sedlbauer_isar_interrupt(int intno, void if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Sedlbauer IRQ LOOP"); - isar_write(cs, 0, ISAR_IRQBIT, 0); - isac_write(cs, ISAC_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0x0); - isar_write(cs, 0, ISAR_IRQBIT, ISAR_IRQMSK); - spin_unlock(&cs->lock); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static int -sedlbauer_ipac_reset(struct IsdnCardState *cs) +void +release_io_sedlbauer(struct IsdnCardState *cs) { - writereg(cs, cs->hw.sedl.isac, IPAC_POTA2, 0x20); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writereg(cs, cs->hw.sedl.isac, IPAC_POTA2, 0x0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - writereg(cs, cs->hw.sedl.isac, IPAC_CONF, 0x0); - writereg(cs, cs->hw.sedl.isac, IPAC_ACFG, 0xff); - writereg(cs, cs->hw.sedl.isac, IPAC_AOE, 0x0); - writereg(cs, cs->hw.sedl.isac, IPAC_MASK, 0xc0); - writereg(cs, cs->hw.sedl.isac, IPAC_PCFG, 0x12); - return 0; -} + int bytecnt = 8; -static int -sedlbauer_isar_pci_reset(struct IsdnCardState *cs) -{ - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((20*HZ)/1000); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((20*HZ)/1000); - return 0; -} - -static int -sedlbauer_reset(struct IsdnCardState *cs) -{ - printk(KERN_INFO "Sedlbauer: resetting card\n"); - if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA && - cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX) - return 0; - - if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - return sedlbauer_ipac_reset(cs); - } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) && - (cs->hw.sedl.bus == SEDL_BUS_PCI)) { - return sedlbauer_isar_pci_reset(cs); - } else { - byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); + if (cs->subtyp == SEDL_SPEED_FAX) { + bytecnt = 16; + } else if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + bytecnt = 256; } - return 0; + if (cs->hw.sedl.cfg_reg) + release_region(cs->hw.sedl.cfg_reg, bytecnt); } static void -sedlbauer_isar_release(struct IsdnCardState *cs) +reset_sedlbauer(struct IsdnCardState *cs) { - isar_write(cs, 0, ISAR_IRQBIT, 0); - isac_write(cs, ISAC_MASK, 0xFF); - sedlbauer_reset(cs); - isar_write(cs, 0, ISAR_IRQBIT, 0); - isac_write(cs, ISAC_MASK, 0xFF); - hisax_release_resources(cs); -} - -static void -sedlbauer_led_handler(struct IsdnCardState *cs) -{ - if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) - return; - - if (cs->status & 0x2000) - cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; - else - cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; - - if (cs->status & 0x1000) - cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1; - else - cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1; - - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); -} - -static void -sedlbauer_isar_init(struct IsdnCardState *cs) -{ - isar_write(cs, 0, ISAR_IRQBIT, 0); - initisac(cs); - initisar(cs); -} - -static struct card_ops sedlbauer_ops = { - .init = inithscxisac, - .reset = sedlbauer_reset, - .release = hisax_release_resources, - .led_handler = sedlbauer_led_handler, - .irq_func = sedlbauer_interrupt, -}; - -static struct card_ops sedlbauer_ipac_ops = { - .init = ipac_init, - .reset = sedlbauer_reset, - .release = hisax_release_resources, - .led_handler = sedlbauer_led_handler, - .irq_func = ipac_irq, -}; - -static struct card_ops sedlbauer_isar_ops = { - .init = sedlbauer_isar_init, - .reset = sedlbauer_reset, - .release = sedlbauer_isar_release, - .led_handler = sedlbauer_led_handler, - .irq_func = sedlbauer_isar_interrupt, -}; - -static int __init -sedl_ipac_probe(struct IsdnCardState *cs) -{ - u8 val; - - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; - val = readreg(cs, cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); - printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val); - return (val == 1 || val == 2); -} - -static int __init -sedl_ipac_init(struct IsdnCardState *cs) -{ - cs->card_ops = &sedlbauer_ipac_ops; - if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops)) - return -ENODEV; - sedlbauer_reset(cs); - return 0; -} - -static int __init -sedl_isac_isar_init(struct IsdnCardState *cs) -{ - cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; - cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; - __set_bit(HW_ISAR, &cs->HW_Flags); - cs->card_ops = &sedlbauer_isar_ops; - cs->auxcmd = &isar_auxcmd; - isac_setup(cs, &isac_ops); - return isar_setup(cs, &isar_ops); -} + printk(KERN_INFO "Sedlbauer: resetting card\n"); -static int __init -sedl_isac_hscx_init(struct IsdnCardState *cs) -{ - cs->card_ops = &sedlbauer_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - return -ENODEV; - sedlbauer_reset(cs); - return 0; + if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && + (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) { + if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); + mdelay(2); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); + mdelay(10); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12); + } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) && + (cs->hw.sedl.bus == SEDL_BUS_PCI)) { + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + mdelay(2); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + mdelay(10); + } else { + byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ + mdelay(2); + byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ + mdelay(10); + } + } } -static int __init -sedl_card_win_probe(struct IsdnCardState *cs, struct IsdnCard *card) +static int +Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - cs->irq = card->para[0]; - cs->hw.sedl.cfg_reg = card->para[1]; - cs->hw.sedl.bus = SEDL_BUS_ISA; - if (!request_io(&cs->rs, cs->hw.sedl.cfg_reg, 8, "sedlbauer isdn")) - goto err; + u_long flags; - if (sedl_ipac_probe(cs)) { - cs->subtyp = SEDL_SPEED_WIN2_PC104; - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - if (sedl_ipac_init(cs)) - goto err; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF; - if (sedl_isac_hscx_init(cs)) - goto err; - } - printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n", - Sedlbauer_Types[cs->subtyp], - cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 8, cs->irq); - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -sedl_star_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->hw.sedl.bus = SEDL_BUS_PCMCIA; - if (sedl_ipac_probe(cs)) { - cs->subtyp = SEDL_SPEED_STAR2; - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - if (sedl_ipac_init(cs)) - goto err; - } else { - cs->subtyp = SEDL_SPEED_STAR; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; - if (sedl_isac_hscx_init(cs)) - goto err; - } - printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n", - Sedlbauer_Types[cs->subtyp], - cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 8, cs->irq); - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -sedl_fax_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.bus = SEDL_BUS_ISA; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - if (!request_io(&cs->rs, cs->hw.sedl.cfg_reg, 16, "sedlbauer isdn")) - goto err; - - printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n", - Sedlbauer_Types[cs->subtyp], - cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 16, cs->irq); - - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF; - if (sedl_isac_isar_init(cs)) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -sedl_pci_init(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.sedl.cfg_reg = pci_resource_start(pdev, 0); - cs->hw.sedl.bus = SEDL_BUS_PCI; - - if (!request_io(&cs->rs, cs->hw.sedl.cfg_reg, 256, "sedlbauer isdn")) - return -EBUSY; - - printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n", - Sedlbauer_Types[cs->subtyp], - cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 256, cs->irq); - - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg+ 5, 0x02); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - return 0; -} - -static int __init -sedl_fax_pyramid_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - if (sedl_pci_init(cs, pdev)) - goto err; - - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAR; - if (sedl_isac_isar_init(cs)) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -sedl_fax_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = SEDL_SPEEDFAX_PCI; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - - if (sedl_pci_init(cs, pdev)) - goto err; - - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAR; - if (sedl_isac_isar_init(cs)) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -sedl_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) -{ - if (pci_enable_device(pdev)) - goto err; - - cs->subtyp = SEDL_SPEED_PCI; - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - if (sedl_pci_init(cs, pdev)) - goto err; - - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; - if (sedl_ipac_init(cs)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_sedlbauer(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + spin_lock_irqsave(&cs->lock, flags); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, + ISAR_IRQBIT, 0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, + ISAC_MASK, 0xFF); + reset_sedlbauer(cs); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, + ISAR_IRQBIT, 0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, + ISAC_MASK, 0xFF); + spin_unlock_irqrestore(&cs->lock, flags); + } + release_io_sedlbauer(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + reset_sedlbauer(cs); + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + clear_pending_isac_ints(cs); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, + ISAR_IRQBIT, 0); + initisac(cs); + initisar(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + } else { + inithscxisac(cs, 3); + } + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + case MDL_INFO_CONN: + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) + return(0); + spin_lock_irqsave(&cs->lock, flags); + if ((long) arg) + cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; + else + cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1; + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + spin_unlock_irqrestore(&cs->lock, flags); + break; + case MDL_INFO_REL: + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) + return(0); + spin_lock_irqsave(&cs->lock, flags); + if ((long) arg) + cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; + else + cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1; + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + spin_unlock_irqrestore(&cs->lock, flags); + break; + } + return(0); } static struct pci_dev *dev_sedl __devinitdata = NULL; @@ -700,124 +526,308 @@ static struct isapnp_device_id sedl_ids[ { 0, } }; -static struct isapnp_device_id *pdev = &sedl_ids[0]; +static struct isapnp_device_id *ipid __initdata = &sedl_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif int __devinit setup_sedlbauer(struct IsdnCard *card) { + int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; char tmp[64]; u16 sub_vendor_id, sub_id; strcpy(tmp, Sedlbauer_revision); - printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", - HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_SEDLBAUER) { + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.bus = SEDL_BUS_ISA; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) { + cs->subtyp = SEDL_SPEED_STAR; + cs->hw.sedl.bus = SEDL_BUS_PCMCIA; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.bus = SEDL_BUS_ISA; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + } else + return (0); + + bytecnt = 8; if (card->para[1]) { - if (cs->typ == ISDN_CTYPE_SEDLBAUER) { - if (sedl_card_win_probe(card->cs, card) < 0) - return 0; - return 1; - } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) { - if (sedl_star_probe(card->cs, card) < 0) - return 0; - return 1; - } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) { - if (sedl_fax_probe(card->cs, card) < 0) - return 0; - return 1; + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + bytecnt = 16; } - } + } else { #ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_card *pb; - struct pnp_dev *pd; - - while(pdev->card_vendor) { - if ((pb = pnp_find_card(pdev->card_vendor, - pdev->card_device, - pnp_c))) { - pnp_c = pb; - pd = NULL; - if ((pd = pnp_find_dev(pnp_c, - pdev->vendor, - pdev->function, - pd))) { - printk(KERN_INFO "HiSax: %s detected\n", - (char *)pdev->driver_data); - if (pnp_device_attach(pd) < 0) { - printk(KERN_ERR "Sedlbauer PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pd) < 0) { - printk(KERN_ERR "Sedlbauer PnP: activate failed\n"); - pnp_device_detach(pd); - return 0; - } - if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - pnp_irq(pd, 0), pnp_port_start(pd, 0)); - pnp_device_detach(pd); - return 0; - } - card->para[1] = pnp_port_start(pd, 0); - card->para[0] = pnp_irq(pd, 0); - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (pdev->function == ISAPNP_FUNCTION(0x2)) { - if (sedl_fax_probe(card->cs, card)) - return 0; - return 1; + if (isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0x2)) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + bytecnt = 16; + } else { + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } + goto ready; } else { - if (sedl_card_win_probe(card->cs, card)) - return 0; - return 1; + printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); + return(0); } - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return 0; } + ipid++; + pnp_c = NULL; + } + if (!ipid->card_vendor) { + printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); } - pdev++; - pnp_c=NULL; - } - if (!pdev->card_vendor) { - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); } - } #endif /* Probe for Sedlbauer speed pci */ -#ifdef CONFIG_PCI - dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl); - if (dev_sedl) { +#if CONFIG_PCI + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return(0); + cs->irq = dev_sedl->irq; + if (!cs->irq) { + printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); + } else { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + cs->irq_flags |= SA_SHIRQ; + cs->hw.sedl.bus = SEDL_BUS_PCI; sub_vendor_id = dev_sedl->subsystem_vendor; sub_id = dev_sedl->subsystem_device; printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); + sub_vendor_id, sub_id); + printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", + cs->hw.sedl.cfg_reg); if (sub_id != PCI_SUB_ID_SEDLBAUER) { printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return 0; + return(0); } if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - if (sedl_fax_pyramid_probe(cs, dev_sedl)) - return 0; - return 1; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - if (sedl_fax_pci_probe(cs, dev_sedl)) - return 0; - return 1; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PCI; + } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = HST_SAPHIR3; } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - if (sedl_pci_probe(cs, dev_sedl)) - return 0; - return 1; + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); } - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return 0; - } + bytecnt = 256; + cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0x02); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + mdelay(2); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + mdelay(10); +#else + printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); + return (0); #endif /* CONFIG_PCI */ - return 0; + } +ready: + /* In case of the sedlbauer pcmcia card, this region is in use, + * reserved for us by the card manager. So we do not check it + * here, it would fail. + */ + if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && + !request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.sedl.cfg_reg, + cs->hw.sedl.cfg_reg + bytecnt); + return (0); + } + + printk(KERN_INFO + "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n", + cs->hw.sedl.cfg_reg, + cs->hw.sedl.cfg_reg + bytecnt, + cs->irq); + + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Sedl_card_msg; + +/* + * testing ISA and PCMCIA Cards for IPAC, default is ISAC + * do not test for PCI card, because ports are different + * and PCI card uses only IPAC (for the moment) + */ + if (cs->hw.sedl.bus != SEDL_BUS_PCI) { + val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR, + cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); + printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val); + if ((val == 1) || (val == 2)) { + /* IPAC */ + cs->subtyp = SEDL_SPEED_WIN2_PC104; + if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { + cs->subtyp = SEDL_SPEED_STAR2; + } + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + } else { + /* ISAC_HSCX oder ISAC_ISAR */ + if (cs->hw.sedl.chip == SEDL_CHIP_TEST) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; + } + } + } + +/* + * hw.sedl.chip is now properly set + */ + printk(KERN_INFO "Sedlbauer: %s detected\n", + Sedlbauer_Types[cs->subtyp]); + + setup_isac(cs); + if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { + if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + } + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &sedlbauer_interrupt_ipac; + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID); + printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); + } else { + /* ISAC_HSCX oder ISAC_ISAR */ + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ISAR; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAR; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAR_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAR_RESET_OFF; + } + cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; + cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; + test_and_set_bit(HW_ISAR, &cs->HW_Flags); + cs->irq_func = &sedlbauer_interrupt_isar; + cs->auxcmd = &isar_auxcmd; + ISACVersion(cs, "Sedlbauer:"); + cs->BC_Read_Reg = &ReadISAR; + cs->BC_Write_Reg = &WriteISAR; + cs->BC_Send_Data = &isar_fill_fifo; + bytecnt = 3; + while (bytecnt) { + ver = ISARVersion(cs, "Sedlbauer:"); + if (ver < 0) + printk(KERN_WARNING + "Sedlbauer: wrong ISAR version (ret = %d)\n", ver); + else + break; + reset_sedlbauer(cs); + bytecnt--; + } + if (!bytecnt) { + release_io_sedlbauer(cs); + return (0); + } + } else { + if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; + cs->irq_flags |= SA_SHIRQ; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF; + } + cs->irq_func = &sedlbauer_interrupt; + ISACVersion(cs, "Sedlbauer:"); + + if (HscxVersion(cs, "Sedlbauer:")) { + printk(KERN_WARNING + "Sedlbauer: wrong HSCX versions check IO address\n"); + release_io_sedlbauer(cs); + return (0); + } + } + } + return (1); } diff -puN drivers/isdn/hisax/sedlbauer_cs.c~i4l drivers/isdn/hisax/sedlbauer_cs.c --- 25/drivers/isdn/hisax/sedlbauer_cs.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/sedlbauer_cs.c 2004-02-09 22:19:20.000000000 -0800 @@ -53,6 +53,7 @@ #include #include #include +#include "hisax_cfg.h" MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards"); MODULE_AUTHOR("Marcus Niemann"); @@ -93,8 +94,6 @@ MODULE_PARM(irq_list, "1-4i"); static int protocol = 2; /* EURO-ISDN Default */ MODULE_PARM(protocol, "i"); -extern int sedl_init_pcmcia(int, int, int*, int); - /*====================================================================*/ /* @@ -176,6 +175,7 @@ typedef struct local_info_t { dev_link_t link; dev_node_t node; int stop; + int cardnr; } local_info_t; /*====================================================================== @@ -203,6 +203,7 @@ static dev_link_t *sedlbauer_attach(void local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) return NULL; memset(local, 0, sizeof(local_info_t)); + local->cardnr = -1; link = &local->link; link->priv = local; /* Interrupt setup */ @@ -324,7 +325,7 @@ static void sedlbauer_config(dev_link_t config_info_t conf; win_req_t req; memreq_t map; - + IsdnCard_t icard; DEBUG(0, "sedlbauer_config(0x%p)\n", link); @@ -509,10 +510,19 @@ static void sedlbauer_config(dev_link_t printk("\n"); link->state &= ~DEV_CONFIG_PENDING; - - sedl_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ, - &(((local_info_t*)link->priv)->stop), - protocol); + + icard.para[0] = link->irq.AssignedIRQ; + icard.para[1] = link->io.BasePort1; + icard.protocol = protocol; + icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; + + last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard); + if (last_ret < 0) { + printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n", + last_ret, link->io.BasePort1); + sedlbauer_release(link); + } else + ((local_info_t*)link->priv)->cardnr = last_ret; return; @@ -532,8 +542,15 @@ cs_failed: static void sedlbauer_release(dev_link_t *link) { + local_info_t *local = link->priv; DEBUG(0, "sedlbauer_release(0x%p)\n", link); + if (local) { + if (local->cardnr >= 0) { + /* no unregister function with hisax */ + HiSax_closecard(local->cardnr); + } + } /* Unlink the device chain */ link->dev = NULL; diff -puN drivers/isdn/hisax/sportster.c~i4l drivers/isdn/hisax/sportster.c --- 25/drivers/isdn/hisax/sportster.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/sportster.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: sportster.c,v 1.14.6.2 2001/09/23 22:24:51 kai Exp $ +/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for USR Sportster internal TA * @@ -19,7 +19,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.14.6.2 $"; +const char *sportster_revision = "$Revision: 1.16.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -38,91 +38,102 @@ calc_off(unsigned int base, unsigned int } static inline void -read_fifo(unsigned int adr, u8 * data, int size) +read_fifo(unsigned int adr, u_char * data, int size) { insb(adr, data, size); } static void -write_fifo(unsigned int adr, u8 * data, int size) +write_fifo(unsigned int adr, u_char * data, int size) { outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return bytein(calc_off(cs->hw.spt.isac, offset)); + return (bytein(calc_off(cs->hw.spt.isac, offset))); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { byteout(calc_off(cs->hw.spt.isac, offset), value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { read_fifo(cs->hw.spt.isac, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { write_fifo(cs->hw.spt.isac, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return bytein(calc_off(cs->hw.spt.hscx[hscx], offset)); + return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset))); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - read_fifo(cs->hw.spt.hscx[hscx], data, size); -} +/* + * fast interrupt HSCX stuff goes here + */ -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - write_fifo(cs->hw.spt.hscx[hscx], data, size); -} +#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg)) +#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt) -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +#include "hscx_irq.c" static irqreturn_t sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; - hscxisac_irq(intno, dev_id, regs); + spin_lock_irqsave(&cs->lock, flags); + val = READHSCX(cs, 1, HSCX_ISTA); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = ReadISAC(cs, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = READHSCX(cs, 1, HSCX_ISTA); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = ReadISAC(cs, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + /* get a new irq impulse if there any pending */ bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static void -sportster_release(struct IsdnCardState *cs) +void +release_io_sportster(struct IsdnCardState *cs) { int i, adr; @@ -133,45 +144,50 @@ sportster_release(struct IsdnCardState * } } -static int -sportster_reset(struct IsdnCardState *cs) +void +reset_sportster(struct IsdnCardState *cs) { cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); + mdelay(10); cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - return 0; + mdelay(10); } static int Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - return(0); -} + u_long flags; -static void -sportster_init(struct IsdnCardState *cs) -{ - inithscxisac(cs); - cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_sportster(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_sportster(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + reset_sportster(cs); + inithscxisac(cs, 1); + cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ + byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); + inithscxisac(cs, 2); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } -static struct card_ops sportster_ops = { - .init = sportster_init, - .reset = sportster_reset, - .release = sportster_release, - .irq_func = sportster_interrupt, -}; - static int __init get_io_range(struct IsdnCardState *cs) { - int i, adr; + int i, j, adr; for (i=0;i<64;i++) { adr = cs->hw.spt.cfg_reg + i *1024; @@ -179,65 +195,76 @@ get_io_range(struct IsdnCardState *cs) printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[cs->typ], adr, adr + 8); - goto err; - } + break; + } } - return 1; - err: - for (i=i-1; i >= 0; i--) { - adr = cs->hw.spt.cfg_reg + i *1024; - release_region(adr, 8); + if (i==64) + return(1); + else { + for (j=0; jhw.spt.cfg_reg + j *1024; + release_region(adr, 8); + } + return(0); } - return 0; } -static int __init -sportster_probe(struct IsdnCardState *cs, struct IsdnCard *card) +int __init +setup_sportster(struct IsdnCard *card) { - cs->irq = card->para[0]; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, sportster_revision); + printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_SPORTSTER) + return (0); + cs->hw.spt.cfg_reg = card->para[1]; + cs->irq = card->para[0]; if (!get_io_range(cs)) - return -EBUSY; + return (0); cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC; cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA; cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB; switch(cs->irq) { - case 5: cs->hw.spt.res_irq = 1; break; - case 7: cs->hw.spt.res_irq = 2; break; - case 10:cs->hw.spt.res_irq = 3; break; - case 11:cs->hw.spt.res_irq = 4; break; - case 12:cs->hw.spt.res_irq = 5; break; - case 14:cs->hw.spt.res_irq = 6; break; - case 15:cs->hw.spt.res_irq = 7; break; - default: - printk(KERN_WARNING "Sportster: wrong IRQ\n"); - goto err; + case 5: cs->hw.spt.res_irq = 1; + break; + case 7: cs->hw.spt.res_irq = 2; + break; + case 10:cs->hw.spt.res_irq = 3; + break; + case 11:cs->hw.spt.res_irq = 4; + break; + case 12:cs->hw.spt.res_irq = 5; + break; + case 14:cs->hw.spt.res_irq = 6; + break; + case 15:cs->hw.spt.res_irq = 7; + break; + default:release_io_sportster(cs); + printk(KERN_WARNING "Sportster: wrong IRQ\n"); + return(0); } - sportster_reset(cs); printk(KERN_INFO "HiSax: %s config irq:%d cfg:0x%X\n", - CardType[cs->typ], cs->irq, cs->hw.spt.cfg_reg); - + CardType[cs->typ], cs->irq, cs->hw.spt.cfg_reg); + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Sportster_card_msg; - cs->card_ops = &sportster_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - sportster_release(cs); - return -EBUSY; -} - -int __init -setup_sportster(struct IsdnCard *card) -{ - char tmp[64]; - - strcpy(tmp, sportster_revision); - printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", - HiSax_getrev(tmp)); - - if (sportster_probe(card->cs, card) < 0) - return 0; - return 1; + cs->irq_func = &sportster_interrupt; + ISACVersion(cs, "Sportster:"); + if (HscxVersion(cs, "Sportster:")) { + printk(KERN_WARNING + "Sportster: wrong HSCX versions check IO address\n"); + release_io_sportster(cs); + return (0); + } + return (1); } diff -puN drivers/isdn/hisax/st5481_b.c~i4l drivers/isdn/hisax/st5481_b.c --- 25/drivers/isdn/hisax/st5481_b.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/st5481_b.c 2004-02-09 22:19:20.000000000 -0800 @@ -31,9 +31,9 @@ static void usb_b_out(struct st5481_bcs struct st5481_b_out *b_out = &bcs->b_out; struct st5481_adapter *adapter = bcs->adapter; struct urb *urb; - u_int packet_size, bytes_sent; - int len, offset, buf_size; - u_int i; + unsigned int packet_size,offset; + int len,buf_size,bytes_sent; + int i; struct sk_buff *skb; if (test_and_set_bit(buf_nr, &b_out->busy)) { @@ -67,22 +67,31 @@ static void usb_b_out(struct st5481_bcs bytes_sent = buf_size - len; if (skb->len < bytes_sent) bytes_sent = skb->len; - - memcpy(urb->transfer_buffer+len, skb->data, bytes_sent); - + { /* swap tx bytes to get hearable audio data */ + register unsigned char *src = skb->data; + register unsigned char *dest = urb->transfer_buffer+len; + register unsigned int count; + for (count = 0; count < bytes_sent; count++) + *dest++ = isdnhdlc_bit_rev_tab[*src++]; + } len += bytes_sent; } else { - len += hdlc_encode(&b_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer+len, buf_size-len); + len += isdnhdlc_encode(&b_out->hdlc_state, + skb->data, skb->len, &bytes_sent, + urb->transfer_buffer+len, buf_size-len); } skb_pull(skb, bytes_sent); - + if (!skb->len) { // Frame sent b_out->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, skb); + B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); + dev_kfree_skb_any(skb); + +/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */ +/* st5481B_sched_event(bcs, B_XMTBUFREADY); */ +/* } */ } } else { if (bcs->mode == L1_MODE_TRANS) { @@ -90,9 +99,9 @@ static void usb_b_out(struct st5481_bcs len = buf_size; } else { // Send flags - len += hdlc_encode(&b_out->hdlc_state, - NULL, 0, &bytes_sent, - urb->transfer_buffer+len, buf_size-len); + len += isdnhdlc_encode(&b_out->hdlc_state, + NULL, 0, &bytes_sent, + urb->transfer_buffer+len, buf_size-len); } } } @@ -136,7 +145,7 @@ static void st5481B_start_xfer(void *con */ static void led_blink(struct st5481_adapter *adapter) { - u8 leds = adapter->leds; + u_char leds = adapter->leds; // 50 frames/sec for each channel if (++adapter->led_counter % 50) { @@ -204,7 +213,7 @@ static void st5481B_mode(struct st5481_b if (bcs->mode != L1_MODE_NULL) { // Open the B channel if (bcs->mode != L1_MODE_TRANS) { - hdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K); + isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K); } st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL); @@ -260,7 +269,7 @@ static int st5481_setup_b_out(struct st5 endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2]; DBG(4,"endpoint address=%02x,packet size=%d", - endpoint->desc.bEndpointAddress,endpoint->desc.wMaxPacketSize); + endpoint->desc.bEndpointAddress, endpoint->desc.wMaxPacketSize); // Allocate memory for 8000bytes/sec + extra bytes if underrun return st5481_setup_isocpipes(b_out->urb, dev, diff -puN drivers/isdn/hisax/st5481_d.c~i4l drivers/isdn/hisax/st5481_d.c --- 25/drivers/isdn/hisax/st5481_d.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/st5481_d.c 2004-02-09 22:19:20.000000000 -0800 @@ -294,8 +294,8 @@ static void usb_d_out(struct st5481_adap { struct st5481_d_out *d_out = &adapter->d_out; struct urb *urb; - unsigned int num_packets; - int len, buf_size, bytes_sent, packet_offset; + unsigned int num_packets, packet_offset; + int len, buf_size, bytes_sent; struct sk_buff *skb; struct usb_iso_packet_descriptor *desc; @@ -313,15 +313,15 @@ static void usb_d_out(struct st5481_adap buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT; if (skb) { - len = hdlc_encode(&d_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer, buf_size); + len = isdnhdlc_encode(&d_out->hdlc_state, + skb->data, skb->len, &bytes_sent, + urb->transfer_buffer, buf_size); skb_pull(skb,bytes_sent); } else { // Send flags or idle - len = hdlc_encode(&d_out->hdlc_state, - NULL, 0, &bytes_sent, - urb->transfer_buffer, buf_size); + len = isdnhdlc_encode(&d_out->hdlc_state, + NULL, 0, &bytes_sent, + urb->transfer_buffer, buf_size); } if (len < buf_size) { @@ -341,7 +341,7 @@ static void usb_d_out(struct st5481_adap desc = &urb->iso_frame_desc[num_packets]; desc->offset = packet_offset; desc->length = SIZE_ISO_PACKETS_D_OUT; - if (len - packet_offset < (int)desc->length) + if (len - packet_offset < desc->length) desc->length = len - packet_offset; num_packets++; packet_offset += desc->length; @@ -413,7 +413,7 @@ static void dout_start_xmit(struct FsmIn DBG(2,"len=%d",skb->len); - hdlc_out_init(&d_out->hdlc_state, 1, 0); + isdnhdlc_out_init(&d_out->hdlc_state, 1, 0); if (test_and_set_bit(buf_nr, &d_out->busy)) { WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); @@ -422,9 +422,9 @@ static void dout_start_xmit(struct FsmIn urb = d_out->urb[buf_nr]; DBG_SKB(0x10, skb); - len = hdlc_encode(&d_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer, 16); + len = isdnhdlc_encode(&d_out->hdlc_state, + skb->data, skb->len, &bytes_sent, + urb->transfer_buffer, 16); skb_pull(skb, bytes_sent); if(len < 16) @@ -664,7 +664,7 @@ static int __devinit st5481_setup_d_out( endpoint = &altsetting->endpoint[EP_D_OUT-1]; DBG(2,"endpoint address=%02x,packet size=%d", - endpoint->desc.bEndpointAddress,endpoint->desc.wMaxPacketSize); + endpoint->desc.bEndpointAddress, endpoint->desc.wMaxPacketSize); return st5481_setup_isocpipes(d_out->urb, dev, usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress), diff -puN drivers/isdn/hisax/st5481.h~i4l drivers/isdn/hisax/st5481.h --- 25/drivers/isdn/hisax/st5481.h~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/st5481.h 2004-02-10 08:01:29.000000000 -0800 @@ -219,15 +219,15 @@ enum { #define L1_EVENT_COUNT (EV_TIMER3 + 1) #define ERR(format, arg...) \ -printk(KERN_ERR __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg) +printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__, ## arg) #define WARN(format, arg...) \ -printk(KERN_WARNING __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg) +printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__, ## arg) #define INFO(format, arg...) \ -printk(KERN_INFO __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg) +printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__, ## arg) -#include "st5481_hdlc.h" +#include "isdnhdlc.h" #include "fsm.h" #include "hisax_if.h" #include @@ -236,9 +236,9 @@ printk(KERN_INFO __FILE__ ": %s: " forma * FIFO handling */ -/* Generic FIFO structure */ +/* Generic FIFO structure */ struct fifo { - u8 r,w,count,size; + u_char r,w,count,size; spinlock_t lock; }; @@ -270,7 +270,7 @@ static inline int fifo_add(struct fifo * index = -1; } else { // Return index where to get the next data to add to the FIFO - index = fifo->w++ & (fifo->size-1); + index = fifo->w++ & (fifo->size-1); fifo->count++; } spin_unlock_irqrestore(&fifo->lock, flags); @@ -289,13 +289,13 @@ static inline int fifo_remove(struct fif return -1; } - spin_lock_irqsave(&fifo->lock, flags); + spin_lock_irqsave(&fifo->lock, flags); if (!fifo->count) { // FIFO empty index = -1; } else { // Return index where to get the next data from the FIFO - index = fifo->r++ & (fifo->size-1); + index = fifo->r++ & (fifo->size-1); fifo->count--; } spin_unlock_irqrestore(&fifo->lock, flags); @@ -336,7 +336,7 @@ struct st5481_intr { }; struct st5481_d_out { - struct hdlc_vars hdlc_state; + struct isdnhdlc_vars hdlc_state; struct urb *urb[2]; /* double buffering */ unsigned long busy; struct sk_buff *tx_skb; @@ -344,15 +344,15 @@ struct st5481_d_out { }; struct st5481_b_out { - struct hdlc_vars hdlc_state; + struct isdnhdlc_vars hdlc_state; struct urb *urb[2]; /* double buffering */ - u8 flow_event; + u_char flow_event; u_long busy; struct sk_buff *tx_skb; }; struct st5481_in { - struct hdlc_vars hdlc_state; + struct isdnhdlc_vars hdlc_state; struct urb *urb[2]; /* double buffering */ int mode; int bufsize; @@ -452,7 +452,7 @@ void st5481_release_isocpipes(struct urb int st5481_isoc_flatten(struct urb *urb); void st5481_usb_pipe_reset(struct st5481_adapter *adapter, - u8 pipe, ctrl_complete_t complete, void *context); + u_char pipe, ctrl_complete_t complete, void *context); void st5481_usb_ctrl_msg(struct st5481_adapter *adapter, u8 request, u8 requesttype, u16 value, u16 index, ctrl_complete_t complete, void *context); @@ -482,7 +482,7 @@ dump_iso_packet(const char *name, struct { int i,j; int len,ofs; - u8 *data; + u_char *data; printk(KERN_DEBUG "%s: packets=%d,errors=%d\n", name,urb->number_of_packets,urb->error_count); diff -puN drivers/isdn/hisax/st5481_init.c~i4l drivers/isdn/hisax/st5481_init.c --- 25/drivers/isdn/hisax/st5481_init.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/st5481_init.c 2004-02-09 22:19:20.000000000 -0800 @@ -14,7 +14,6 @@ * TODO: * * b layer1 delay? - * hdlc as module * hotplug / unregister issues * mod_inc/dec_use_count * unify parts of d/b channel usb handling @@ -59,8 +58,8 @@ static LIST_HEAD(adapter_list); * This function will be called when the adapter is plugged * into the USB bus. */ -static int probe_st5481(struct usb_interface *intf, - const struct usb_device_id *id) +static int __devinit probe_st5481(struct usb_interface *intf, + const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct st5481_adapter *adapter; @@ -140,7 +139,7 @@ static void disconnect_st5481(struct usb usb_set_intfdata(intf, NULL); if (!adapter) return; - + list_del(&adapter->list); st5481_stop(adapter); @@ -196,7 +195,7 @@ static int __init st5481_usb_init(void) st5481_debug = debug; #endif - printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver v0.1.0\n"); + printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n"); retval = st5481_d_init(); if (retval < 0) diff -puN drivers/isdn/hisax/st5481_usb.c~i4l drivers/isdn/hisax/st5481_usb.c --- 25/drivers/isdn/hisax/st5481_usb.c~i4l 2004-02-09 22:19:19.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/st5481_usb.c 2004-02-09 22:19:20.000000000 -0800 @@ -96,7 +96,7 @@ void st5481_usb_device_ctrl_msg(struct s * Asynchronous pipe reset (async version of usb_clear_halt). */ void st5481_usb_pipe_reset(struct st5481_adapter *adapter, - u8 pipe, + u_char pipe, ctrl_complete_t complete, void *context) { DBG(1,"pipe=%02x",pipe); @@ -500,8 +500,8 @@ static void usb_in_complete(struct urb * status = len; len = 0; } else { - status = hdlc_decode(&in->hdlc_state, ptr, len, &count, - in->rcvbuf, in->bufsize); + status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count, + in->rcvbuf, in->bufsize); ptr += count; len -= count; } @@ -633,8 +633,8 @@ void st5481_in_mode(struct st5481_in *in if (in->mode != L1_MODE_NULL) { if (in->mode != L1_MODE_TRANS) - hdlc_rcv_init(&in->hdlc_state, - in->mode == L1_MODE_HDLC_56K); + isdnhdlc_rcv_init(&in->hdlc_state, + in->mode == L1_MODE_HDLC_56K); st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); st5481_usb_device_ctrl_msg(in->adapter, in->counter, diff -puN drivers/isdn/hisax/tei.c~i4l drivers/isdn/hisax/tei.c --- 25/drivers/isdn/hisax/tei.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/tei.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: tei.c,v 2.17.6.3 2001/09/23 22:24:51 kai Exp $ +/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $ * * Author Karsten Keil * based on the teles driver from Jan den Ouden @@ -20,7 +20,7 @@ #include #include -const char *tei_revision = "$Revision: 2.17.6.3 $"; +const char *tei_revision = "$Revision: 2.20.2.3 $"; #define ID_REQUEST 1 #define ID_ASSIGNED 2 @@ -34,7 +34,7 @@ const char *tei_revision = "$Revision: 2 static struct Fsm teifsm; -void tei_handler(struct PStack *st, u8 pr, struct sk_buff *skb); +void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb); enum { ST_TEI_NOP, @@ -74,22 +74,6 @@ static char *strTeiEvent[] = "EV_T202", }; -static inline void -mdl_assign(struct IsdnCardState *cs) -{ - cs->status |= 0x0001; - if (cs->card_ops->led_handler) - cs->card_ops->led_handler(cs); -} - -static inline void -mdl_remove(struct IsdnCardState *cs) -{ - cs->status = 0; - if (cs->card_ops->led_handler) - cs->card_ops->led_handler(cs); -} - unsigned int random_ri(void) { @@ -116,10 +100,10 @@ findtei(struct PStack *st, int tei) } static void -put_tei_msg(struct PStack *st, u8 m_id, unsigned int ri, u8 tei) +put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei) { struct sk_buff *skb; - u8 *bp; + u_char *bp; if (!(skb = alloc_skb(8, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No skb for TEI manager\n"); @@ -135,7 +119,7 @@ put_tei_msg(struct PStack *st, u8 m_id, bp[2] = ri & 0xff; bp[3] = m_id; bp[4] = (tei << 1) | 1; - L2L1(st, PH_DATA | REQUEST, skb); + st->l2.l2l1(st, PH_DATA | REQUEST, skb); } static void @@ -145,7 +129,7 @@ tei_id_request(struct FsmInst *fi, int e if (st->l2.tei != -1) { st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign request for already assigned tei %d", + "assign request for allready asigned tei %d", st->l2.tei); return; } @@ -181,9 +165,9 @@ tei_id_assign(struct FsmInst *fi, int ev } else if (ri == st->ma.ri) { FsmDelTimer(&st->ma.t202, 1); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); + st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); cs = (struct IsdnCardState *) st->l1.hardware; - mdl_assign(cs); + cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); } } @@ -255,9 +239,9 @@ tei_id_remove(struct FsmInst *fi, int ev if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { FsmDelTimer(&st->ma.t202, 5); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - L3L2(st, MDL_REMOVE | REQUEST, 0); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); cs = (struct IsdnCardState *) st->l1.hardware; - mdl_remove(cs); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); } } @@ -291,9 +275,9 @@ tei_id_req_tout(struct FsmInst *fi, int FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); } else { st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); - L3L2(st, MDL_ERROR | RESPONSE, 0); + st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0); cs = (struct IsdnCardState *) st->l1.hardware; - mdl_remove(cs); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); } } @@ -314,9 +298,9 @@ tei_id_ver_tout(struct FsmInst *fi, int } else { st->ma.tei_m.printdebug(&st->ma.tei_m, "verify req for tei %d failed", st->l2.tei); - L3L2(st, MDL_REMOVE | REQUEST, 0); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); cs = (struct IsdnCardState *) st->l1.hardware; - mdl_remove(cs); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); } } @@ -387,9 +371,9 @@ tei_l2tei(struct PStack *st, int pr, voi if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "fixed assign tei %d", st->l2.tei); - L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); + st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); cs = (struct IsdnCardState *) st->l1.hardware; - mdl_assign(cs); + cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); } return; } diff -puN drivers/isdn/hisax/teleint.c~i4l drivers/isdn/hisax/teleint.c --- 25/drivers/isdn/hisax/teleint.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/teleint.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: teleint.c,v 1.14.6.2 2001/09/23 22:24:52 kai Exp $ +/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $ * * low level stuff for TeleInt isdn cards * @@ -18,38 +18,33 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.14.6.2 $"; -static spinlock_t teleint_lock = SPIN_LOCK_UNLOCKED; +const char *TeleInt_revision = "$Revision: 1.16.2.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static inline u8 -readreg(unsigned int ale, unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) { - register u8 ret; + register u_char ret; int max_delay = 2000; - unsigned long flags; - spin_lock_irqsave(&teleint_lock, flags); byteout(ale, off); ret = HFC_BUSY & bytein(ale); while (ret && --max_delay) ret = HFC_BUSY & bytein(ale); if (!max_delay) { printk(KERN_WARNING "TeleInt Busy not inactive\n"); - spin_unlock_irqrestore(&teleint_lock, flags); return (0); } ret = bytein(adr); - spin_unlock_irqrestore(&teleint_lock, flags); return (ret); } static inline void -readfifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size) +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - register u8 ret; + register u_char ret; register int max_delay = 20000; register int i; @@ -68,34 +63,29 @@ readfifo(unsigned int ale, unsigned int static inline void -writereg(unsigned int ale, unsigned int adr, u8 off, u8 data) +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) { - register u8 ret; + register u_char ret; int max_delay = 2000; - unsigned long flags; - spin_lock_irqsave(&teleint_lock, flags); byteout(ale, off); ret = HFC_BUSY & bytein(ale); while (ret && --max_delay) ret = HFC_BUSY & bytein(ale); if (!max_delay) { printk(KERN_WARNING "TeleInt Busy not inactive\n"); - spin_unlock_irqrestore(&teleint_lock, flags); return; } byteout(adr, data); - spin_unlock_irqrestore(&teleint_lock, flags); } static inline void -writefifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size) +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { - register u8 ret; + register u_char ret; register int max_delay = 20000; register int i; - /* fifo write without cli because it's already done */ byteout(ale, off); for (i = 0; ihw.hfc.cip = offset; return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset)); } static void -WriteISAC(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { cs->hw.hfc.cip = offset; writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value); } static void -ReadISACfifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { cs->hw.hfc.cip = 0; readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); } static void -WriteISACfifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { cs->hw.hfc.cip = 0; writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = ReadISAC, - .write_reg = WriteISAC, - .read_fifo = ReadISACfifo, - .write_fifo = WriteISACfifo, -}; - -static u8 -ReadHFC(struct IsdnCardState *cs, int data, u8 reg) +static u_char +ReadHFC(struct IsdnCardState *cs, int data, u_char reg) { - register u8 ret; + register u_char ret; if (data) { cs->hw.hfc.cip = reg; @@ -163,7 +146,7 @@ ReadHFC(struct IsdnCardState *cs, int da } static void -WriteHFC(struct IsdnCardState *cs, int data, u8 reg, u8 value) +WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value) { byteout(cs->hw.hfc.addr | 1, reg); cs->hw.hfc.cip = reg; @@ -173,18 +156,14 @@ WriteHFC(struct IsdnCardState *cs, int d debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); } -static struct bc_hw_ops hfc_ops = { - .read_reg = ReadHFC, - .write_reg = WriteHFC, -}; - static irqreturn_t -teleint_interrupt(int intno, void *dev_id, struct pt_regs *regs) +TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u8 val; + u_char val; + u_long flags; - spin_lock(&cs->lock); + spin_lock_irqsave(&cs->lock, flags); val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); Start_ISAC: if (val) @@ -197,7 +176,7 @@ teleint_interrupt(int intno, void *dev_i } writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF); writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0); - spin_unlock(&cs->lock); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } @@ -205,7 +184,9 @@ static void TeleInt_Timer(struct IsdnCardState *cs) { int stat = 0; - + u_long flags; + + spin_lock_irqsave(&cs->lock, flags); if (cs->bcs[0].mode) { stat |= 1; main_irq_hfc(&cs->bcs[0]); @@ -214,52 +195,83 @@ TeleInt_Timer(struct IsdnCardState *cs) stat |= 2; main_irq_hfc(&cs->bcs[1]); } - cs->hw.hfc.timer.expires = jiffies + 1; + spin_unlock_irqrestore(&cs->lock, flags); + stat = HZ/100; + if (!stat) + stat = 1; + cs->hw.hfc.timer.expires = jiffies + stat; add_timer(&cs->hw.hfc.timer); } -static void -teleint_release(struct IsdnCardState *cs) +void +release_io_TeleInt(struct IsdnCardState *cs) { del_timer(&cs->hw.hfc.timer); releasehfc(cs); - hisax_release_resources(cs); + if (cs->hw.hfc.addr) + release_region(cs->hw.hfc.addr, 2); } -static int -teleint_reset(struct IsdnCardState *cs) +static void +reset_TeleInt(struct IsdnCardState *cs) { printk(KERN_INFO "TeleInt: resetting card\n"); cs->hw.hfc.cirm |= HFC_RESET; byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((30*HZ)/1000); + mdelay(10); cs->hw.hfc.cirm &= ~HFC_RESET; byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); - return 0; + mdelay(10); } -static void -teleint_init(struct IsdnCardState *cs) +static int +TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - inithfc(cs); - initisac(cs); - cs->hw.hfc.timer.expires = jiffies + 1; - add_timer(&cs->hw.hfc.timer); -} + u_long flags; + int delay; -static struct card_ops teleint_ops = { - .init = teleint_init, - .reset = teleint_reset, - .release = teleint_release, - .irq_func = teleint_interrupt, -}; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_TeleInt(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_TeleInt(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + reset_TeleInt(cs); + inithfc(cs); + clear_pending_isac_ints(cs); + initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + cs->writeisac(cs, ISAC_CMDR, 0x41); + spin_unlock_irqrestore(&cs->lock, flags); + delay = HZ/100; + if (!delay) + delay = 1; + cs->hw.hfc.timer.expires = jiffies + delay; + add_timer(&cs->hw.hfc.timer); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} -static int __init -teleint_probe(struct IsdnCardState *cs, struct IsdnCard *card) +int __init +setup_TeleInt(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, TeleInt_revision); + printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_TELEINT) + return (0); + cs->hw.hfc.addr = card->para[1] & 0x3fe; cs->irq = card->para[0]; cs->hw.hfc.cirm = HFC_CIRM; @@ -272,61 +284,56 @@ teleint_probe(struct IsdnCardState *cs, cs->hw.hfc.timer.function = (void *) TeleInt_Timer; cs->hw.hfc.timer.data = (long) cs; init_timer(&cs->hw.hfc.timer); - if (!request_io(&cs->rs, cs->hw.hfc.addr, 2, "TeleInt isdn")) - goto err; - + if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.hfc.addr, + cs->hw.hfc.addr + 2); + return (0); + } /* HW IO = IO */ byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff); byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54); switch (cs->irq) { - case 3: - cs->hw.hfc.cirm |= HFC_INTA; - break; - case 4: - cs->hw.hfc.cirm |= HFC_INTB; - break; - case 5: - cs->hw.hfc.cirm |= HFC_INTC; - break; - case 7: - cs->hw.hfc.cirm |= HFC_INTD; - break; - case 10: - cs->hw.hfc.cirm |= HFC_INTE; - break; - case 11: - cs->hw.hfc.cirm |= HFC_INTF; - break; - default: - printk(KERN_WARNING "TeleInt: wrong IRQ\n"); - goto err; + case 3: + cs->hw.hfc.cirm |= HFC_INTA; + break; + case 4: + cs->hw.hfc.cirm |= HFC_INTB; + break; + case 5: + cs->hw.hfc.cirm |= HFC_INTC; + break; + case 7: + cs->hw.hfc.cirm |= HFC_INTD; + break; + case 10: + cs->hw.hfc.cirm |= HFC_INTE; + break; + case 11: + cs->hw.hfc.cirm |= HFC_INTF; + break; + default: + printk(KERN_WARNING "TeleInt: wrong IRQ\n"); + release_io_TeleInt(cs); + return (0); } byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt); printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n", - cs->hw.hfc.addr, cs->irq); - - cs->card_ops = &teleint_ops; - teleint_reset(cs); - isac_setup(cs, &isac_ops); - hfc_setup(cs, &hfc_ops); - return 0; - - err: - hisax_release_resources(cs); - return -EBUSY; -} - -int __init -setup_TeleInt(struct IsdnCard *card) -{ - char tmp[64]; - - strcpy(tmp, TeleInt_revision); - printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.hfc.addr, cs->irq); - if (teleint_probe(card->cs, card) < 0) - return 0; - return 1; + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHFC; + cs->BC_Write_Reg = &WriteHFC; + cs->cardmsg = &TeleInt_card_msg; + cs->irq_func = &TeleInt_interrupt; + ISACVersion(cs, "TeleInt:"); + return (1); } diff -puN drivers/isdn/hisax/teles0.c~i4l drivers/isdn/hisax/teles0.c --- 25/drivers/isdn/hisax/teles0.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/teles0.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: teles0.c,v 2.13.6.2 2001/09/23 22:24:52 kai Exp $ +/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for Teles Memory IO isdn cards * @@ -23,97 +23,179 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.13.6.2 $"; +const char *teles0_revision = "$Revision: 2.15.2.4 $"; #define TELES_IOMEM_SIZE 0x400 #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static u8 -isac_read(struct IsdnCardState *cs, u8 off) +static inline u_char +readisac(unsigned long adr, u_char off) { - return readb(cs->hw.teles0.membase + - ((off & 1) ? 0x2ff : 0x100) + off); + return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off); } -static void -isac_write(struct IsdnCardState *cs, u8 off, u8 data) +static inline void +writeisac(unsigned long adr, u_char off, u_char data) { - writeb(data, cs->hw.teles0.membase + - ((off & 1) ? 0x2ff : 0x100) + off); mb(); + writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); } -static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +static inline u_char +readhscx(unsigned long adr, int hscx, u_char off) { - int i; - void *ad = cs->hw.teles0.membase + 0x100; + return readb(adr + (hscx ? 0x1c0 : 0x180) + + ((off & 1) ? 0x1ff : 0) + off); +} + +static inline void +writehscx(unsigned long adr, int hscx, u_char off, u_char data) +{ + writeb(data, adr + (hscx ? 0x1c0 : 0x180) + + ((off & 1) ? 0x1ff : 0) + off); mb(); +} + +static inline void +read_fifo_isac(unsigned long adr, u_char * data, int size) +{ + register int i; + register u_char *ad = (u_char *)adr + 0x100; for (i = 0; i < size; i++) data[i] = readb(ad); } -static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +static inline void +write_fifo_isac(unsigned long adr, u_char * data, int size) +{ + register int i; + register u_char *ad = (u_char *)adr + 0x100; + for (i = 0; i < size; i++) { + writeb(data[i], ad); mb(); + } +} + +static inline void +read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) +{ + register int i; + register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); + for (i = 0; i < size; i++) + data[i] = readb(ad); +} + +static inline void +write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { int i; - void *ad = cs->hw.teles0.membase + 0x100; + register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); for (i = 0; i < size; i++) { writeb(data[i], ad); mb(); } } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; +/* Interface functions */ -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 off) +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readb(cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); + return (readisac(cs->hw.teles0.membase, offset)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 data) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writeb(data, cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); mb(); + writeisac(cs->hw.teles0.membase, offset, value); } static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - int i; - void *ad = cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180); - for (i = 0; i < size; i++) - data[i] = readb(ad); + read_fifo_isac(cs->hw.teles0.membase, data, size); } static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { - int i; - void *ad = cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180); - for (i = 0; i < size; i++) { - writeb(data[i], ad); - } + write_fifo_isac(cs->hw.teles0.membase, data, size); } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readhscx(cs->hw.teles0.membase, hscx, offset)); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writehscx(cs->hw.teles0.membase, hscx, offset, value); +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + int count = 0; + + spin_lock_irqsave(&cs->lock, flags); + val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readisac(cs->hw.teles0.membase, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + count++; + val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); + if (val && count < 5) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readisac(cs->hw.teles0.membase, ISAC_ISTA); + if (val && count < 5) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +void +release_io_teles0(struct IsdnCardState *cs) +{ + if (cs->hw.teles0.cfg_reg) + release_region(cs->hw.teles0.cfg_reg, 8); + iounmap((unsigned char *)cs->hw.teles0.membase); + release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); +} static int -teles0_reset(struct IsdnCardState *cs) +reset_teles0(struct IsdnCardState *cs) { - u8 cfval; + u_char cfval; if (cs->hw.teles0.cfg_reg) { switch (cs->irq) { @@ -158,102 +240,129 @@ teles0_reset(struct IsdnCardState *cs) return(0); } -static struct card_ops teles0_ops = { - .init = inithscxisac, - .reset = teles0_reset, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - -static int __init -teles0_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->irq = card->para[0]; - /* 16.0 and 8.0 designed for IOM1 */ - test_and_set_bit(HW_IOM1, &cs->HW_Flags); - cs->hw.teles0.phymem = card->para[1]; - cs->hw.teles0.membase = request_mmio(&cs->rs, cs->hw.teles0.phymem, - TELES_IOMEM_SIZE, "teles iomem"); - if (!cs->hw.teles0.membase) - return -EBUSY; - - if (teles0_reset(cs)) { - printk(KERN_WARNING "Teles0: wrong IRQ\n"); - return -EBUSY; - } - cs->card_ops = &teles0_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - return -EBUSY; - - return 0; -} - -static int __init -teles16_0_probe(struct IsdnCardState *cs, struct IsdnCard *card) +static int +Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - u8 val; + u_long flags; - cs->hw.teles0.cfg_reg = card->para[2]; - if (!request_io(&cs->rs, cs->hw.teles0.cfg_reg, 8, "teles cfg")) - goto err; - - if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 0, val); - goto err; - } - if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 1, val); - goto err; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_teles0(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_teles0(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); } - val = bytein(cs->hw.teles0.cfg_reg + 2);/* 0x1e=without AB - * 0x1f=with AB - * 0x1c 16.3 ??? - */ - if (val != 0x1e && val != 0x1f) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 2, val); - goto err; - } - if (teles0_probe(cs, card) < 0) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -teles8_0_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->hw.teles0.cfg_reg = 0; - - if (teles0_probe(cs, card) < 0) - goto err; - - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return(0); } int __init setup_teles0(struct IsdnCard *card) { + u_char val; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, teles0_revision); - printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", - HiSax_getrev(tmp)); - - if (card->cs->typ == ISDN_CTYPE_16_0) { - if (teles16_0_probe(card->cs, card) < 0) - return 0; - } else { - if (teles8_0_probe(card->cs, card) < 0) - return 0; + printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp)); + if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0)) + return (0); + + if (cs->typ == ISDN_CTYPE_16_0) + cs->hw.teles0.cfg_reg = card->para[2]; + else /* 8.0 */ + cs->hw.teles0.cfg_reg = 0; + + if (card->para[1] < 0x10000) { + card->para[1] <<= 4; + printk(KERN_INFO + "Teles0: membase configured DOSish, assuming 0x%lx\n", + (unsigned long) card->para[1]); + } + cs->irq = card->para[0]; + if (cs->hw.teles0.cfg_reg) { + if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.teles0.cfg_reg, + cs->hw.teles0.cfg_reg + 8); + return (0); + } + } + if (cs->hw.teles0.cfg_reg) { + if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) { + printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", + cs->hw.teles0.cfg_reg + 0, val); + release_region(cs->hw.teles0.cfg_reg, 8); + return (0); + } + if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) { + printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", + cs->hw.teles0.cfg_reg + 1, val); + release_region(cs->hw.teles0.cfg_reg, 8); + return (0); + } + val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB + * 0x1f=with AB + * 0x1c 16.3 ??? + */ + if (val != 0x1e && val != 0x1f) { + printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", + cs->hw.teles0.cfg_reg + 2, val); + release_region(cs->hw.teles0.cfg_reg, 8); + return (0); + } + } + /* 16.0 and 8.0 designed for IOM1 */ + test_and_set_bit(HW_IOM1, &cs->HW_Flags); + cs->hw.teles0.phymem = card->para[1]; + if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) { + printk(KERN_WARNING + "HiSax: %s memory region %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.teles0.phymem, + cs->hw.teles0.phymem + TELES_IOMEM_SIZE); + if (cs->hw.teles0.cfg_reg) + release_region(cs->hw.teles0.cfg_reg, 8); + return (0); + } + cs->hw.teles0.membase = + (unsigned long) ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); + printk(KERN_INFO + "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n", + CardType[cs->typ], cs->irq, + cs->hw.teles0.membase, cs->hw.teles0.cfg_reg); + if (reset_teles0(cs)) { + printk(KERN_WARNING "Teles0: wrong IRQ\n"); + release_io_teles0(cs); + return (0); + } + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Teles_card_msg; + cs->irq_func = &teles0_interrupt; + ISACVersion(cs, "Teles0:"); + if (HscxVersion(cs, "Teles0:")) { + printk(KERN_WARNING + "Teles0: wrong HSCX versions check IO/MEM addresses\n"); + release_io_teles0(cs); + return (0); } - return 1; + return (1); } diff -puN drivers/isdn/hisax/teles3.c~i4l drivers/isdn/hisax/teles3.c --- 25/drivers/isdn/hisax/teles3.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/teles3.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: teles3.c,v 2.17.6.2 2001/09/23 22:24:52 kai Exp $ +/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $ * * low level stuff for Teles 16.3 & PNP isdn cards * @@ -21,102 +21,160 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.17.6.2 $"; +const char *teles3_revision = "$Revision: 2.19.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static inline u8 -readreg(unsigned int adr, u8 off) +static inline u_char +readreg(unsigned int adr, u_char off) { return (bytein(adr + off)); } static inline void -writereg(unsigned int adr, u8 off, u8 data) +writereg(unsigned int adr, u_char off, u_char data) { byteout(adr + off, data); } static inline void -read_fifo(unsigned int adr, u8 * data, int size) +read_fifo(unsigned int adr, u_char * data, int size) { insb(adr, data, size); } static void -write_fifo(unsigned int adr, u8 * data, int size) +write_fifo(unsigned int adr, u_char * data, int size) { outsb(adr, data, size); } -static u8 -isac_read(struct IsdnCardState *cs, u8 offset) +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) { - return readreg(cs->hw.teles3.isac, offset); + return (readreg(cs->hw.teles3.isac, offset)); } static void -isac_write(struct IsdnCardState *cs, u8 offset, u8 value) +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writereg(cs->hw.teles3.isac, offset, value); } static void -isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { read_fifo(cs->hw.teles3.isacfifo, data, size); } static void -isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { write_fifo(cs->hw.teles3.isacfifo, data, size); } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return readreg(cs->hw.teles3.hscx[hscx], offset); + return (readreg(cs->hw.teles3.hscx[hscx], offset)); } static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) { writereg(cs->hw.teles3.hscx[hscx], offset, value); } -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - read_fifo(cs->hw.teles3.hscxfifo[hscx], data, size); -} +/* + * fast interrupt HSCX stuff goes here + */ -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) -{ - write_fifo(cs->hw.teles3.hscxfifo[hscx], data, size); +#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) + +#include "hscx_irq.c" + +static irqreturn_t +teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ +#define MAXCOUNT 5 + struct IsdnCardState *cs = dev_id; + u_char val; + u_long flags; + int count = 0; + + spin_lock_irqsave(&cs->lock, flags); + val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.teles3.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + count++; + val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); + if (val && count < MAXCOUNT) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.teles3.isac, ISAC_ISTA); + if (val && count < MAXCOUNT) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (count >= MAXCOUNT) + printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count); + writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0); + writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); + writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_HANDLED; +} + +inline static void +release_ioregs(struct IsdnCardState *cs, int mask) +{ + if (mask & 1) + release_region(cs->hw.teles3.isac + 32, 32); + if (mask & 2) + release_region(cs->hw.teles3.hscx[0] + 32, 32); + if (mask & 4) + release_region(cs->hw.teles3.hscx[1] + 32, 32); +} + +void +release_io_teles3(struct IsdnCardState *cs) +{ + if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { + release_region(cs->hw.teles3.hscx[1], 96); + } else { + if (cs->hw.teles3.cfg_reg) { + if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { + release_region(cs->hw.teles3.cfg_reg, 1); + } else { + release_region(cs->hw.teles3.cfg_reg, 8); + } + } + release_ioregs(cs, 0x7); + } } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; - static int -teles3_reset(struct IsdnCardState *cs) +reset_teles3(struct IsdnCardState *cs) { - u8 irqcfg; + u_char irqcfg; if (cs->typ != ISDN_CTYPE_TELESPCMCIA) { if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { @@ -169,160 +227,33 @@ teles3_reset(struct IsdnCardState *cs) return(0); } -static struct card_ops teles3_ops = { - .init = inithscxisac, - .reset = teles3_reset, - .release = hisax_release_resources, - .irq_func = hscxisac_irq, -}; - static int -teles_hw_init(struct IsdnCardState *cs) +Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - - printk(KERN_INFO "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n", - CardType[cs->typ], cs->irq, - cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg); - printk(KERN_INFO "HiSax: hscx A:0x%X hscx B:0x%X\n", - cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32); + u_long flags; - if (teles3_reset(cs)) { - printk(KERN_WARNING "Teles3: wrong IRQ\n"); - return -EBUSY; + switch (mt) { + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + reset_teles3(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_RELEASE: + release_io_teles3(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); } - cs->card_ops = &teles3_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - return -EBUSY; - return 0; -} - -static void __init -teles_setup_io(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->irq = card->para[0]; - cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; - cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; - cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; -} - -static int __init -telespcmcia_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->hw.teles3.cfg_reg = 0; - cs->hw.teles3.hscx[0] = card->para[1] - 0x20; - cs->hw.teles3.hscx[1] = card->para[1]; - cs->hw.teles3.isac = card->para[1] + 0x20; - teles_setup_io(cs, card); - if (!request_io(&cs->rs, cs->hw.teles3.hscx[1], 96, - "HiSax Teles PCMCIA")) - goto err; - if (teles_hw_init(cs) < 0) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -teles_request_io(struct IsdnCardState *cs) -{ - if (!request_io(&cs->rs, cs->hw.teles3.isac + 32, 32, "HiSax isac")) - return -EBUSY; - if (!request_io(&cs->rs, cs->hw.teles3.hscx[0]+32, 32, "HiSax hscx A")) - return -EBUSY; - if (!request_io(&cs->rs, cs->hw.teles3.hscx[1]+32, 32, "HiSax hscx B")) - return -EBUSY; - return 0; -} - -static int __init -teles16_3_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - u8 val; - - cs->hw.teles3.cfg_reg = card->para[1]; - switch (cs->hw.teles3.cfg_reg) { - case 0x180: - case 0x280: - case 0x380: - cs->hw.teles3.cfg_reg |= 0xc00; - break; - } - cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420; - cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; - cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; - teles_setup_io(cs, card); - if (!request_io(&cs->rs, cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) - goto err; - if (teles_request_io(cs) < 0) - goto err; - if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 0, val); - goto err; - } - if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 1, val); - goto err; - } - /* 0x1e without AB, 0x1f with AB, 0x1c 16.3 ???, - * 0x39 16.3 1.1, 0x38 16.3 1.3, 0x46 16.3 with AB + Video */ - val = bytein(cs->hw.teles3.cfg_reg + 2); - if (val != 0x46 && val != 0x39 && val != 0x38 && - val != 0x1c && val != 0x1e && val != 0x1f) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 2, val); - goto err; - } - if (teles_hw_init(cs) < 0) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -compaq_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->hw.teles3.cfg_reg = card->para[3]; - cs->hw.teles3.isac = card->para[2] - 32; - cs->hw.teles3.hscx[0] = card->para[1] - 32; - cs->hw.teles3.hscx[1] = card->para[1]; - teles_setup_io(cs, card); - if (!request_io(&cs->rs, cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) - goto err; - if (teles_request_io(cs) < 0) - goto err; - if (teles_hw_init(cs) < 0) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; -} - -static int __init -telespnp_probe(struct IsdnCardState *cs, struct IsdnCard *card) -{ - cs->hw.teles3.cfg_reg = 0; - cs->hw.teles3.isac = card->para[1] - 32; - cs->hw.teles3.hscx[0] = card->para[2] - 32; - cs->hw.teles3.hscx[1] = card->para[2]; - teles_setup_io(cs, card); - if (teles_request_io(cs) < 0) - goto err; - if (teles_hw_init(cs) < 0) - goto err; - return 0; - err: - hisax_release_resources(cs); - return -EBUSY; + return(0); } #ifdef __ISAPNP__ + static struct isapnp_device_id teles_ids[] __initdata = { { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), @@ -336,80 +267,233 @@ static struct isapnp_device_id teles_ids { 0, } }; -static struct isapnp_device_id *tdev = &teles_ids[0]; +static struct isapnp_device_id *ipid __initdata = &teles_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif int __devinit setup_teles3(struct IsdnCard *card) { + u_char val; + struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, teles3_revision); printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp)); + if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP) + && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) + return (0); + #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { - struct pnp_card *pnp_card; - struct pnp_dev *pnp_dev; + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; - while(tdev->card_vendor) { - if ((pnp_card = pnp_find_card(tdev->card_vendor, - tdev->card_device, pnp_c))) { - pnp_c = pnp_card; - pnp_dev = NULL; - if ((pnp_dev = pnp_find_dev(pnp_card, - tdev->vendor, - tdev->function, - pnp_dev))) { printk(KERN_INFO "HiSax: %s detected\n", - (char *)tdev->driver_data); - if (pnp_device_attach(pnp_dev) < 0) { - printk(KERN_ERR "Teles PnP: attach failed\n"); - return 0; - } - if (pnp_activate_dev(pnp_dev) < 0) { - printk(KERN_ERR "Teles PnP: activate failed\n"); - pnp_device_detach(pnp_dev); - return 0; + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); } - if (!pnp_irq_valid(pnp_dev, 0) || - !pnp_port_valid(pnp_dev, 0) || - !pnp_port_valid(pnp_dev, 1)) { - printk(KERN_ERR "Teles PnP: some resources are missing %ld/%lx/%lx\n", - pnp_irq(pnp_dev, 0), pnp_port_start(pnp_dev, 0), pnp_port_start(pnp_dev, 1)); - pnp_device_detach(pnp_dev); - return 0; + card->para[3] = pnp_port_start(pnp_d, 2); + card->para[2] = pnp_port_start(pnp_d, 1); + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1] || !card->para[2]) { + printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n", + card->para[0], card->para[1], card->para[2]); + pnp_disable_dev(pnp_d); + return(0); } - card->para[3] = pnp_port_start(pnp_dev, 2); - card->para[2] = pnp_port_start(pnp_dev, 1); - card->para[1] = pnp_port_start(pnp_dev, 0); - card->para[0] = pnp_irq(pnp_dev, 0); break; } else { printk(KERN_ERR "Teles PnP: PnP error card found, no device\n"); } } - tdev++; - pnp_c=NULL; + ipid++; + pnp_c = NULL; } - if (!tdev->card_vendor) { + if (!ipid->card_vendor) { printk(KERN_INFO "Teles PnP: no ISAPnP card found\n"); return(0); } } #endif - if (card->cs->typ == ISDN_CTYPE_16_3) { - if (teles16_3_probe(card->cs, card) < 0) - return 0; - } else if (card->cs->typ == ISDN_CTYPE_TELESPCMCIA) { - if (telespcmcia_probe(card->cs, card) < 0) - return 0; - } else if (card->cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - if (compaq_probe(card->cs, card) < 0) - return 0; + if (cs->typ == ISDN_CTYPE_16_3) { + cs->hw.teles3.cfg_reg = card->para[1]; + switch (cs->hw.teles3.cfg_reg) { + case 0x180: + case 0x280: + case 0x380: + cs->hw.teles3.cfg_reg |= 0xc00; + break; + } + cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420; + cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; + cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; + } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { + cs->hw.teles3.cfg_reg = 0; + cs->hw.teles3.hscx[0] = card->para[1] - 0x20; + cs->hw.teles3.hscx[1] = card->para[1]; + cs->hw.teles3.isac = card->para[1] + 0x20; + } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { + cs->hw.teles3.cfg_reg = card->para[3]; + cs->hw.teles3.isac = card->para[2] - 32; + cs->hw.teles3.hscx[0] = card->para[1] - 32; + cs->hw.teles3.hscx[1] = card->para[1]; } else { /* PNP */ - if (telespnp_probe(card->cs, card) < 0) - return 0; + cs->hw.teles3.cfg_reg = 0; + cs->hw.teles3.isac = card->para[1] - 32; + cs->hw.teles3.hscx[0] = card->para[2] - 32; + cs->hw.teles3.hscx[1] = card->para[2]; + } + cs->irq = card->para[0]; + cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; + cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; + cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; + if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { + if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) { + printk(KERN_WARNING + "HiSax: %s ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.teles3.hscx[1], + cs->hw.teles3.hscx[1] + 96); + return (0); + } + } else { + if (cs->hw.teles3.cfg_reg) { + if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { + if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) { + printk(KERN_WARNING + "HiSax: %s config port %x already in use\n", + CardType[card->typ], + cs->hw.teles3.cfg_reg); + return (0); + } + } else { + if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.teles3.cfg_reg, + cs->hw.teles3.cfg_reg + 8); + return (0); + } + } + } + if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) { + printk(KERN_WARNING + "HiSax: %s isac ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.teles3.isac + 32, + cs->hw.teles3.isac + 64); + if (cs->hw.teles3.cfg_reg) { + if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { + release_region(cs->hw.teles3.cfg_reg, 1); + } else { + release_region(cs->hw.teles3.cfg_reg, 8); + } + } + return (0); + } + if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) { + printk(KERN_WARNING + "HiSax: %s hscx A ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.teles3.hscx[0] + 32, + cs->hw.teles3.hscx[0] + 64); + if (cs->hw.teles3.cfg_reg) { + if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { + release_region(cs->hw.teles3.cfg_reg, 1); + } else { + release_region(cs->hw.teles3.cfg_reg, 8); + } + } + release_ioregs(cs, 1); + return (0); + } + if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) { + printk(KERN_WARNING + "HiSax: %s hscx B ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.teles3.hscx[1] + 32, + cs->hw.teles3.hscx[1] + 64); + if (cs->hw.teles3.cfg_reg) { + if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { + release_region(cs->hw.teles3.cfg_reg, 1); + } else { + release_region(cs->hw.teles3.cfg_reg, 8); + } + } + release_ioregs(cs, 3); + return (0); + } + } + if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { + if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) { + printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", + cs->hw.teles3.cfg_reg + 0, val); + release_io_teles3(cs); + return (0); + } + if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) { + printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", + cs->hw.teles3.cfg_reg + 1, val); + release_io_teles3(cs); + return (0); + } + val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB + * 0x1f=with AB + * 0x1c 16.3 ??? + * 0x39 16.3 1.1 + * 0x38 16.3 1.3 + * 0x46 16.3 with AB + Video (Teles-Vision) + */ + if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) { + printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", + cs->hw.teles3.cfg_reg + 2, val); + release_io_teles3(cs); + return (0); + } + } + printk(KERN_INFO + "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n", + CardType[cs->typ], cs->irq, + cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg); + printk(KERN_INFO + "HiSax: hscx A:0x%X hscx B:0x%X\n", + cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32); + + setup_isac(cs); + if (reset_teles3(cs)) { + printk(KERN_WARNING "Teles3: wrong IRQ\n"); + release_io_teles3(cs); + return (0); + } + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Teles_card_msg; + cs->irq_func = &teles3_interrupt; + ISACVersion(cs, "Teles3:"); + if (HscxVersion(cs, "Teles3:")) { + printk(KERN_WARNING + "Teles3: wrong HSCX versions check IO address\n"); + release_io_teles3(cs); + return (0); } - return 1; + return (1); } diff -puN /dev/null drivers/isdn/hisax/teles_cs.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/isdn/hisax/teles_cs.c 2004-02-09 22:19:20.000000000 -0800 @@ -0,0 +1,549 @@ +/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */ +/*====================================================================== + + A teles S0 PCMCIA client driver + + Based on skeleton by David Hinds, dhinds@allegro.stanford.edu + Written by Christof Petig, christof.petig@wtal.de + + Also inspired by ELSA PCMCIA driver + by Klaus Lichtenwalder + + Extentions to new hisax_pcmcia by Karsten Keil + + minor changes to be compatible with kernel 2.4.x + by Jan.Schubert@GMX.li + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "hisax_cfg.h" + +MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards"); +MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de"); +MODULE_LICENSE("GPL"); + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"teles_cs.c 2.10 2002/07/30 22:23:34 kkeil"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from, the old way */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, 3 */ +static u_long irq_mask = 0xdeb8; + +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +static int protocol = 2; /* EURO-ISDN Default */ +MODULE_PARM(protocol, "i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the teles_cs event + handler. +*/ + +static void teles_cs_config(dev_link_t *link); +static void teles_cs_release(dev_link_t *link); +static int teles_cs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *teles_attach(void); +static void teles_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "teles_cs"; + +/* + A linked list of "instances" of the teles_cs device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + To simplify the data structure handling, we actually include the + dev_link_t structure in the device's private data structure. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. +*/ + +typedef struct local_info_t { + dev_link_t link; + dev_node_t node; + int busy; + int cardnr; +} local_info_t; + +/*====================================================================== + + teles_attach() creates an "instance" of the driver, allocatingx + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *teles_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "teles_attach()\n"); + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) return NULL; + memset(local, 0, sizeof(local_info_t)); + local->cardnr = -1; + link = &local->link; link->priv = local; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID|IRQ_SHARE_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->io.NumPorts1 = 96; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 5; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &teles_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = pcmcia_register_client(&link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + teles_detach(link); + return NULL; + } + + return link; +} /* teles_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void teles_detach(dev_link_t *link) +{ + dev_link_t **linkp; + local_info_t *info = link->priv; + int ret; + + DEBUG(0, "teles_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) + teles_cs_release(link); + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { + DEBUG(0, "teles_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) { + ret = pcmcia_deregister_client(link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure and free it */ + *linkp = link->next; + kfree(info); + +} /* teles_detach */ + +/*====================================================================== + + teles_cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ +static int get_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_tuple_data(handle, tuple); + if (i != CS_SUCCESS) return i; + return pcmcia_parse_tuple(handle, tuple, parse); +} + +static int first_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_first_tuple(handle, tuple); + if (i != CS_SUCCESS) return i; + return get_tuple(handle, tuple, parse); +} + +static int next_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_next_tuple(handle, tuple); + if (i != CS_SUCCESS) return i; + return get_tuple(handle, tuple, parse); +} + +static void teles_cs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + local_info_t *dev; + int i, j, last_fn; + u_short buf[128]; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + IsdnCard_t icard; + + DEBUG(0, "teles_config(0x%p)\n", link); + handle = link->handle; + dev = link->priv; + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 255; + tuple.TupleOffset = 0; + tuple.Attributes = 0; + i = first_tuple(handle, &tuple, &parse); + if (i != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if ( (cf->io.nwin > 0) && cf->io.win[0].base) { + printk(KERN_INFO "(teles_cs: looks like the 96 model)\n"); + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + i = pcmcia_request_io(link->handle, &link->io); + if (i == CS_SUCCESS) break; + } else { + printk(KERN_INFO "(teles_cs: looks like the 97 model)\n"); + link->conf.ConfigIndex = cf->index; + for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { + link->io.BasePort1 = j; + i = pcmcia_request_io(link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + last_fn = RequestIO; + goto cs_failed; + } + + i = pcmcia_request_irq(link->handle, &link->irq); + if (i != CS_SUCCESS) { + link->irq.AssignedIRQ = 0; + last_fn = RequestIRQ; + goto cs_failed; + } + + i = pcmcia_request_configuration(link->handle, &link->conf); + if (i != CS_SUCCESS) { + last_fn = RequestConfiguration; + goto cs_failed; + } + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. *//* */ + sprintf(dev->node.dev_name, "teles"); + dev->node.major = dev->node.minor = 0x0; + + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + + icard.para[0] = link->irq.AssignedIRQ; + icard.para[1] = link->io.BasePort1; + icard.protocol = protocol; + icard.typ = ISDN_CTYPE_TELESPCMCIA; + + i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard); + if (i < 0) { + printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n", + i, link->io.BasePort1); + teles_cs_release(link); + } else + ((local_info_t*)link->priv)->cardnr = i; + + return; +cs_failed: + cs_error(link->handle, last_fn, i); + teles_cs_release(link); +} /* teles_cs_config */ + +/*====================================================================== + + After a card is removed, teles_cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void teles_cs_release(dev_link_t *link) +{ + local_info_t *local = link->priv; + + DEBUG(0, "teles_cs_release(0x%p)\n", link); + + if (local) { + if (local->cardnr >= 0) { + /* no unregister function with hisax */ + HiSax_closecard(local->cardnr); + } + } + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + if (link->win) + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + teles_detach(link); + +} /* teles_cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int teles_cs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *dev = link->priv; + + DEBUG(1, "teles_cs_event(%d)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((local_info_t*)link->priv)->busy = 1; + teles_cs_release(link); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + teles_cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + dev->busy = 1; + if (link->state & DEV_CONFIG) + pcmcia_release_configuration(link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + pcmcia_request_configuration(link->handle, &link->conf); + dev->busy = 0; + break; + } + return 0; +} /* teles_cs_event */ + +static struct pcmcia_driver teles_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "teles_cs", + }, + .attach = teles_attach, + .detach = teles_detach, +}; + +static int __init init_teles_cs(void) +{ + return pcmcia_register_driver(&teles_cs_driver); +} + +static void __exit exit_teles_cs(void) +{ + pcmcia_unregister_driver(&teles_cs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) + teles_detach(dev_list); +} + +module_init(init_teles_cs); +module_exit(exit_teles_cs); diff -puN drivers/isdn/hisax/telespci.c~i4l drivers/isdn/hisax/telespci.c --- 25/drivers/isdn/hisax/telespci.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/telespci.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: telespci.c,v 2.16.6.5 2001/09/23 22:24:52 kai Exp $ +/* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $ * * low level stuff for Teles PCI isdn cards * @@ -21,7 +21,7 @@ #include extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.16.6.5 $"; +const char *telespci_revision = "$Revision: 2.23.2.3 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 @@ -39,233 +39,250 @@ const char *telespci_revision = "$Revisi #define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1) #define ZORAN_WAIT_NOBUSY do { \ - portdata = readl(adr); \ + portdata = readl(adr + 0x200); \ } while (portdata & ZORAN_PO_RQ_PEN) -static u8 -isac_read(struct IsdnCardState *cs, u8 off) +static inline u_char +readisac(unsigned long adr, u_char off) { - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; + register unsigned int portdata; ZORAN_WAIT_NOBUSY; /* set address for ISAC */ - writel(WRITE_ADDR_ISAC | off, adr); + writel(WRITE_ADDR_ISAC | off, adr + 0x200); ZORAN_WAIT_NOBUSY; /* read data from ISAC */ - writel(READ_DATA_ISAC, adr); + writel(READ_DATA_ISAC, adr + 0x200); ZORAN_WAIT_NOBUSY; - return((u8)(portdata & ZORAN_PO_DMASK)); + return((u_char)(portdata & ZORAN_PO_DMASK)); } -static void -isac_write(struct IsdnCardState *cs, u8 off, u8 data) +static inline void +writeisac(unsigned long adr, u_char off, u_char data) { - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; + register unsigned int portdata; ZORAN_WAIT_NOBUSY; /* set address for ISAC */ - writel(WRITE_ADDR_ISAC | off, adr); + writel(WRITE_ADDR_ISAC | off, adr + 0x200); ZORAN_WAIT_NOBUSY; /* write data to ISAC */ - writel(WRITE_DATA_ISAC | data, adr); + writel(WRITE_DATA_ISAC | data, adr + 0x200); ZORAN_WAIT_NOBUSY; } -static void -isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size) +static inline u_char +readhscx(unsigned long adr, int hscx, u_char off) { - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; - int i; + register unsigned int portdata; + + ZORAN_WAIT_NOBUSY; + /* set address for HSCX */ + writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); + ZORAN_WAIT_NOBUSY; + + /* read data from HSCX */ + writel(READ_DATA_HSCX, adr + 0x200); + ZORAN_WAIT_NOBUSY; + return ((u_char)(portdata & ZORAN_PO_DMASK)); +} + +static inline void +writehscx(unsigned long adr, int hscx, u_char off, u_char data) +{ + register unsigned int portdata; + + ZORAN_WAIT_NOBUSY; + /* set address for HSCX */ + writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); + ZORAN_WAIT_NOBUSY; + + /* write data to HSCX */ + writel(WRITE_DATA_HSCX | data, adr + 0x200); + ZORAN_WAIT_NOBUSY; +} + +static inline void +read_fifo_isac(unsigned long adr, u_char * data, int size) +{ + register unsigned int portdata; + register int i; ZORAN_WAIT_NOBUSY; /* read data from ISAC */ for (i = 0; i < size; i++) { /* set address for ISAC fifo */ - writel(WRITE_ADDR_ISAC | 0x1E, adr); + writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); ZORAN_WAIT_NOBUSY; - writel(READ_DATA_ISAC, adr); + writel(READ_DATA_ISAC, adr + 0x200); ZORAN_WAIT_NOBUSY; - data[i] = (u8)(portdata & ZORAN_PO_DMASK); + data[i] = (u_char)(portdata & ZORAN_PO_DMASK); } } static void -isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size) +write_fifo_isac(unsigned long adr, u_char * data, int size) { - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; - int i; + register unsigned int portdata; + register int i; ZORAN_WAIT_NOBUSY; /* write data to ISAC */ for (i = 0; i < size; i++) { /* set address for ISAC fifo */ - writel(WRITE_ADDR_ISAC | 0x1E, adr); + writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); ZORAN_WAIT_NOBUSY; - writel(WRITE_DATA_ISAC | data[i], adr); + writel(WRITE_DATA_ISAC | data[i], adr + 0x200); ZORAN_WAIT_NOBUSY; } } -static struct dc_hw_ops isac_ops = { - .read_reg = isac_read, - .write_reg = isac_write, - .read_fifo = isac_read_fifo, - .write_fifo = isac_write_fifo, -}; - -static u8 -hscx_read(struct IsdnCardState *cs, int hscx, u8 off) -{ - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - /* set address for HSCX */ - writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr); - ZORAN_WAIT_NOBUSY; - - /* read data from HSCX */ - writel(READ_DATA_HSCX, adr); - ZORAN_WAIT_NOBUSY; - return ((u8)(portdata & ZORAN_PO_DMASK)); -} - -static void -hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 data) +static inline void +read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - /* set address for HSCX */ - writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr); - ZORAN_WAIT_NOBUSY; - - /* write data to HSCX */ - writel(WRITE_DATA_HSCX | data, adr); - ZORAN_WAIT_NOBUSY; -} - -static void -hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size) -{ - void *adr = cs->hw.teles0.membase + 0x200; - unsigned int portdata; - int i; + register unsigned int portdata; + register int i; ZORAN_WAIT_NOBUSY; /* read data from HSCX */ for (i = 0; i < size; i++) { /* set address for HSCX fifo */ - writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr); + writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); ZORAN_WAIT_NOBUSY; - writel(READ_DATA_HSCX, adr); + writel(READ_DATA_HSCX, adr + 0x200); ZORAN_WAIT_NOBUSY; - data[i] = (u8) (portdata & ZORAN_PO_DMASK); + data[i] = (u_char) (portdata & ZORAN_PO_DMASK); } } -static void -hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size) +static inline void +write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { - void *adr = cs->hw.teles0.membase + 0x200; unsigned int portdata; - int i; + register int i; ZORAN_WAIT_NOBUSY; /* write data to HSCX */ for (i = 0; i < size; i++) { /* set address for HSCX fifo */ - writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr); + writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); ZORAN_WAIT_NOBUSY; - writel(WRITE_DATA_HSCX | data[i], adr); + writel(WRITE_DATA_HSCX | data[i], adr + 0x200); ZORAN_WAIT_NOBUSY; udelay(10); } } -static struct bc_hw_ops hscx_ops = { - .read_reg = hscx_read, - .write_reg = hscx_write, - .read_fifo = hscx_read_fifo, - .write_fifo = hscx_write_fifo, -}; +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + return (readisac(cs->hw.teles0.membase, offset)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writeisac(cs->hw.teles0.membase, offset, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + read_fifo_isac(cs->hw.teles0.membase, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + write_fifo_isac(cs->hw.teles0.membase, data, size); +} + +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readhscx(cs->hw.teles0.membase, hscx, offset)); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writehscx(cs->hw.teles0.membase, hscx, offset, value); +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) + +#include "hscx_irq.c" static irqreturn_t telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs) { -#define MAXCOUNT 20 struct IsdnCardState *cs = dev_id; - u8 val; + u_char hval, ival; + u_long flags; - spin_lock(&cs->lock); - val = hscx_read(cs, 1, HSCX_ISTA); - if (val) - hscx_int_main(cs, val); - val = isac_read(cs, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); + spin_lock_irqsave(&cs->lock, flags); + hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); + if (hval) + hscx_int_main(cs, hval); + ival = readisac(cs->hw.teles0.membase, ISAC_ISTA); + if ((hval | ival) == 0) { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; + } + if (ival) + isac_interrupt(cs, ival); /* Clear interrupt register for Zoran PCI controller */ writel(0x70000000, cs->hw.teles0.membase + 0x3C); - hscx_write(cs, 0, HSCX_MASK, 0xFF); - hscx_write(cs, 1, HSCX_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0xFF); - isac_write(cs, ISAC_MASK, 0x0); - hscx_write(cs, 0, HSCX_MASK, 0x0); - hscx_write(cs, 1, HSCX_MASK, 0x0); - spin_unlock(&cs->lock); + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static struct card_ops telespci_ops = { - .init = inithscxisac, - .release = hisax_release_resources, - .irq_func = telespci_interrupt, -}; - -static int __init -telespci_probe(struct IsdnCardState *cs, struct pci_dev *pdev) +void +release_io_telespci(struct IsdnCardState *cs) { - int rc; - - printk(KERN_INFO "TelesPCI: defined at %#lx IRQ %d\n", - pci_resource_start(pdev, 0), pdev->irq); - - rc = -EBUSY; - if (pci_enable_device(pdev)) - goto err; - - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.teles0.membase = request_mmio(&cs->rs, pci_resource_start(pdev, 0), 4096, "telespci"); - if (!cs->hw.teles0.membase) - goto err; - - /* Initialize Zoran PCI controller */ - writel(0x00000000, cs->hw.teles0.membase + 0x28); - writel(0x01000000, cs->hw.teles0.membase + 0x28); - writel(0x01000000, cs->hw.teles0.membase + 0x28); - writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C); - writel(0x70000000, cs->hw.teles0.membase + 0x3C); - writel(0x61000000, cs->hw.teles0.membase + 0x40); - /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ + iounmap((void *)cs->hw.teles0.membase); +} - cs->card_ops = &telespci_ops; - if (hscxisac_setup(cs, &isac_ops, &hscx_ops)) - goto err; - return 0; - err: - hisax_release_resources(cs); - return rc; +static int +TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + u_long flags; + + switch (mt) { + case CARD_RESET: + return(0); + case CARD_RELEASE: + release_io_telespci(cs); + return(0); + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + inithscxisac(cs, 3); + spin_unlock_irqrestore(&cs->lock, flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); } static struct pci_dev *dev_tel __initdata = NULL; @@ -273,21 +290,70 @@ static struct pci_dev *dev_tel __initdat int __init setup_telespci(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif strcpy(tmp, telespci_revision); - printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", - HiSax_getrev(tmp)); - dev_tel = pci_find_device(PCI_VENDOR_ID_ZORAN, - PCI_DEVICE_ID_ZORAN_36120, dev_tel); - if (dev_tel) { - if (telespci_probe(card->cs, dev_tel) < 0) - return 0; - return 1; + printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_TELESPCI) + return (0); +#if CONFIG_PCI + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { + if (pci_enable_device(dev_tel)) + return(0); + cs->irq = dev_tel->irq; + if (!cs->irq) { + printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0), + PAGE_SIZE); + printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", + pci_resource_start(dev_tel, 0), dev_tel->irq); + } else { + printk(KERN_WARNING "TelesPCI: No PCI card found\n"); + return(0); + } +#else + printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n"); + printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n"); + return (0); +#endif /* CONFIG_PCI */ + + /* Initialize Zoran PCI controller */ + writel(0x00000000, cs->hw.teles0.membase + 0x28); + writel(0x01000000, cs->hw.teles0.membase + 0x28); + writel(0x01000000, cs->hw.teles0.membase + 0x28); + writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C); + writel(0x70000000, cs->hw.teles0.membase + 0x3C); + writel(0x61000000, cs->hw.teles0.membase + 0x40); + /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ + + printk(KERN_INFO + "HiSax: %s config irq:%d mem:%lx\n", + CardType[cs->typ], cs->irq, + cs->hw.teles0.membase); + + setup_isac(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &TelesPCI_card_msg; + cs->irq_func = &telespci_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "TelesPCI:"); + if (HscxVersion(cs, "TelesPCI:")) { + printk(KERN_WARNING + "TelesPCI: wrong HSCX versions check IO/MEM addresses\n"); + release_io_telespci(cs); + return (0); } - printk(KERN_WARNING "TelesPCI: No PCI card found\n"); - return 0; + return (1); } diff -puN drivers/isdn/hisax/w6692.c~i4l drivers/isdn/hisax/w6692.c --- 25/drivers/isdn/hisax/w6692.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/w6692.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.12.6.6 2001/09/23 22:24:52 kai Exp $ +/* $Id: w6692.c,v 1.18.2.3 2004/01/13 14:31:26 keil Exp $ * * Winbond W6692 specific routines * @@ -41,60 +41,10 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.12.6.6 $"; +const char *w6692_revision = "$Revision: 1.18.2.3 $"; #define DBUSY_TIMER_VALUE 80 -static inline u8 -w6692_read_reg(struct IsdnCardState *cs, u8 offset) -{ - return (inb(cs->hw.w6692.iobase + offset)); -} - -static inline void -w6692_write_reg(struct IsdnCardState *cs, u8 offset, u8 value) -{ - outb(value, cs->hw.w6692.iobase + offset); -} - -static void -w6692_read_fifo(struct IsdnCardState *cs, u8 * data, int size) -{ - insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size); -} - -static inline void -w6692_write_fifo(struct IsdnCardState *cs, u8 * data, int size) -{ - outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size); -} - -static struct dc_hw_ops w6692_dc_hw_ops = { - .read_fifo = w6692_read_fifo, -}; - -static inline u8 -w6692_bc_read_reg(struct IsdnCardState *cs, int bchan, u8 offset) -{ - return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset)); -} - -static inline void -w6692_bc_write_reg(struct IsdnCardState *cs, int bchan, u8 offset, u8 value) -{ - outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset); -} - -static void -w6692_bc_read_fifo(struct IsdnCardState *cs, int bchan, u8 *data, int len) -{ - insb(cs->hw.w6692.iobase + W_B_RFIFO + (bchan ? 0x40:0), data, len); -} - -static struct bc_hw_ops w6692_bc_hw_ops = { - .read_fifo = w6692_bc_read_fifo, -}; - static char *W6692Ver[] __initdata = {"W6692 V00", "W6692 V01", "W6692 V10", "W6692 V11"}; @@ -104,7 +54,7 @@ W6692Version(struct IsdnCardState *cs, c { int val; - val = w6692_read_reg(cs, W_D_RBCH); + val = cs->readW6692(cs, W_D_RBCH); printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]); } @@ -113,7 +63,7 @@ ph_command(struct IsdnCardState *cs, uns { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_command %x", command); - w6692_write_reg(cs, W_CIX, command); + cs->writeisac(cs, W_CIX, command); } @@ -152,9 +102,8 @@ W6692_new_ph(struct IsdnCardState *cs) } static void -W6692_bh(void *data) +W6692_bh(struct IsdnCardState *cs) { - struct IsdnCardState *cs = data; struct PStack *stptr; if (!cs) @@ -164,7 +113,7 @@ W6692_bh(void *data) debugl1(cs, "D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - L1L2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -185,22 +134,58 @@ W6692_bh(void *data) static void W6692_empty_fifo(struct IsdnCardState *cs, int count) { - recv_empty_fifo_d(cs, count); - w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RACK); + u_char *ptr; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "W6692_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "W6692_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + cs->readW6692fifo(cs, ptr, count); + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "W6692_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } static void W6692_fill_fifo(struct IsdnCardState *cs) { int count, more; - unsigned char *p; + u_char *ptr; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "W6692_fill_fifo"); - p = xmit_fill_fifo_d(cs, W_D_FIFO_THRESH, &count, &more); - if (!p) + if (!cs->tx_skb) return; - w6692_write_fifo(cs, p, count); - w6692_write_reg(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME)); + count = cs->tx_skb->len; + if (count <= 0) + return; + + more = 0; + if (count > W_D_FIFO_THRESH) { + more = !0; + count = W_D_FIFO_THRESH; + } + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeW6692fifo(cs, ptr, count); + cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME)); if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { debugl1(cs, "W6692_fill_fifo dbusytimer running"); del_timer(&cs->dbusytimer); @@ -208,13 +193,43 @@ W6692_fill_fifo(struct IsdnCardState *cs init_timer(&cs->dbusytimer); cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); add_timer(&cs->dbusytimer); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "W6692_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } } static void W6692B_empty_fifo(struct BCState *bcs, int count) { - recv_empty_fifo_b(bcs, count); - w6692_bc_write_reg(bcs->cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + u_char *ptr; + struct IsdnCardState *cs = bcs->cs; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "W6692B_empty_fifo"); + + if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + bcs->hw.w6692.rcvidx = 0; + return; + } + ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx; + bcs->hw.w6692.rcvidx += count; + READW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "W6692B_empty_fifo %c cnt %d", + bcs->channel + '1', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static void @@ -222,33 +237,50 @@ W6692B_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; int more, count; - unsigned char *p; + u_char *ptr; - p = xmit_fill_fifo_b(bcs, W_B_FIFO_THRESH, &count, &more); - if (!p) + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) return; - WRITEW6692BFIFO(cs, bcs->channel, p, count); - w6692_bc_write_reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); -} - -static void -reset_xmit(struct BCState *bcs) -{ - w6692_bc_write_reg(bcs->cs, bcs->channel, W_B_CMDR, - W_B_CMDR_XRST | W_B_CMDR_RACT); + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > W_B_FIFO_THRESH) { + more = 1; + count = W_B_FIFO_THRESH; + } else + count = bcs->tx_skb->len; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " ": " last "), count); + + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.w6692.count += count; + WRITEW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "W6692B_fill_fifo %c cnt %d", + bcs->channel + '1', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } } static void -W6692B_interrupt(struct IsdnCardState *cs, u8 bchan) +W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) { - u8 val; - u8 r; + u_char val; + u_char r; struct BCState *bcs; + struct sk_buff *skb; int count; bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1); - val = w6692_bc_read_reg(cs, bchan, W_B_EXIR); + val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); if (!test_bit(BC_FLG_INIT, &bcs->Flag)) { @@ -256,8 +288,10 @@ W6692B_interrupt(struct IsdnCardState *c return; } if (val & W_B_EXI_RME) { /* RME */ - r = w6692_bc_read_reg(cs, bchan, W_B_STAR); - if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB | W_B_STAR_XDOW)) { + r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); + if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "W6692 B STAR %x", r); if ((r & W_B_STAR_RDOV) && bcs->mode) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B RDOV mode=%d", @@ -265,46 +299,124 @@ W6692B_interrupt(struct IsdnCardState *c if (r & W_B_STAR_CRCE) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B CRC error"); - w6692_bc_write_reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); - bcs->rcvidx = 0; + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } else { - count = w6692_bc_read_reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1); + count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1); if (count == 0) count = W_B_FIFO_THRESH; W6692B_empty_fifo(bcs, count); - recv_rme_b(bcs); + if ((count = bcs->hw.w6692.rcvidx) > 0) { + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "W6692 Bchan Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "W6692: Bchan receive out of memory\n"); + else { + memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } } + bcs->hw.w6692.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); } if (val & W_B_EXI_RMR) { /* RMR */ W6692B_empty_fifo(bcs, W_B_FIFO_THRESH); - recv_rpf_b(bcs); - } - if (val & W_B_EXI_XFR) { /* XFR */ - xmit_xpr_b(bcs); + r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); + if (r & W_B_STAR_RDOV) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "W6692 B RDOV(RMR) mode=%d",bcs->mode); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); + if (bcs->mode != L1_MODE_TRANS) + bcs->hw.w6692.rcvidx = 0; + } + if (bcs->mode == L1_MODE_TRANS) { + /* receive audio data */ + if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH))) + printk(KERN_WARNING "HiSax: receive out of memory\n"); + else { + memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.w6692.rcvidx = 0; + schedule_event(bcs, B_RCVBUFREADY); + } } if (val & W_B_EXI_XDUN) { /* XDUN */ - xmit_xdu_b(bcs, reset_xmit); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "W6692 B EXIR %x Lost TX", val); + if (bcs->mode == 1) + W6692B_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.w6692.count); + bcs->tx_cnt += bcs->hw.w6692.count; + bcs->hw.w6692.count = 0; + } + } + return; + } + if (val & W_B_EXI_XFR) { /* XFR */ + r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); + if (r & W_B_STAR_XDOW) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "W6692 B STAR %x XDOW", r); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + if (bcs->tx_skb && (bcs->mode != 1)) { + skb_push(bcs->tx_skb, bcs->hw.w6692.count); + bcs->tx_cnt += bcs->hw.w6692.count; + bcs->hw.w6692.count = 0; + } + } + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + W6692B_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count); + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.w6692.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.w6692.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + W6692B_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } } } static irqreturn_t -w6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) +W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) { - struct IsdnCardState *cs = dev_id; - u8 val, exval, v1; - unsigned int count; - int icnt = 5; - - spin_lock(&cs->lock); - - val = w6692_read_reg(cs, W_ISTA); - + struct IsdnCardState *cs = dev_id; + u_char val, exval, v1; + struct sk_buff *skb; + u_int count; + u_long flags; + int icnt = 5; + + spin_lock_irqsave(&cs->lock, flags); + val = cs->readW6692(cs, W_ISTA); + if (!val) { + spin_unlock_irqrestore(&cs->lock, flags); + return IRQ_NONE; + } StartW6692: if (cs->debug & L1_DEB_ISAC) debugl1(cs, "W6692 ISTA %x", val); if (val & W_INT_D_RME) { /* RME */ - exval = w6692_read_reg(cs, W_D_RSTA); + exval = cs->readW6692(cs, W_D_RSTA); if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { if (exval & W_D_RSTA_RDOV) if (cs->debug & L1_DEB_WARN) @@ -315,58 +427,100 @@ w6692_interrupt(int intno, void *dev_id, if (exval & W_D_RSTA_RMB) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 D-channel ABORT"); - w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); - cs->rcvidx = 0; + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); } else { - count = w6692_read_reg(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1); + count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1); if (count == 0) count = W_D_FIFO_THRESH; W6692_empty_fifo(cs, count); - recv_rme_d(cs); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } } + cs->rcvidx = 0; + schedule_event(cs, D_RCVBUFREADY); } if (val & W_INT_D_RMR) { /* RMR */ W6692_empty_fifo(cs, W_D_FIFO_THRESH); } if (val & W_INT_D_XFR) { /* XFR */ - xmit_xpr_d(cs); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + W6692_fill_fifo(cs); + goto afterXFR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + W6692_fill_fifo(cs); + } else + schedule_event(cs, D_XMTBUFREADY); } + afterXFR: if (val & (W_INT_XINT0 | W_INT_XINT1)) { /* XINT0/1 - never */ if (cs->debug & L1_DEB_ISAC) debugl1(cs, "W6692 spurious XINT!"); } if (val & W_INT_D_EXI) { /* EXI */ - exval = w6692_read_reg(cs, W_D_EXIR); + exval = cs->readW6692(cs, W_D_EXIR); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 D_EXIR %02x", exval); if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { /* Transmit underrun/collision */ - xmit_xdu_d(cs, NULL); + debugl1(cs, "W6692 D-chan underrun/collision"); + printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n"); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + schedule_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + W6692_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n"); + debugl1(cs, "W6692 XDUN/XCOL no skb"); + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); + } } if (exval & W_D_EXI_RDOV) { /* RDOV */ debugl1(cs, "W6692 D-channel RDOV"); printk(KERN_WARNING "HiSax: W6692 D-RDOV\n"); - w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RRST); + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST); } if (exval & W_D_EXI_TIN2) { /* TIN2 - never */ debugl1(cs, "W6692 spurious TIN2 interrupt"); } if (exval & W_D_EXI_MOC) { /* MOC - not supported */ debugl1(cs, "W6692 spurious MOC interrupt"); - v1 = w6692_read_reg(cs, W_MOSR); + v1 = cs->readW6692(cs, W_MOSR); debugl1(cs, "W6692 MOSR %02x", v1); } if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ - v1 = w6692_read_reg(cs, W_CIR); + v1 = cs->readW6692(cs, W_CIR); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "W6692 ISC CIR=0x%02X", v1); if (v1 & W_CIR_ICC) { cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state); - sched_d_event(cs, D_L1STATECHANGE); + schedule_event(cs, D_L1STATECHANGE); } if (v1 & W_CIR_SCC) { - v1 = w6692_read_reg(cs, W_SQR); + v1 = cs->readW6692(cs, W_SQR); debugl1(cs, "W6692 SCC SQR=0x%02X", v1); } } @@ -385,16 +539,16 @@ w6692_interrupt(int intno, void *dev_id, debugl1(cs, "W6692 B channel 2 interrupt"); W6692B_interrupt(cs, 1); } - val = w6692_read_reg(cs, W_ISTA); + val = cs->readW6692(cs, W_ISTA); if (val && icnt) { icnt--; goto StartW6692; } if (!icnt) { printk(KERN_WARNING "W6692 IRQ LOOP\n"); - w6692_write_reg(cs, W_IMASK, 0xff); + cs->writeW6692(cs, W_IMASK, 0xff); } - spin_unlock(&cs->lock); + spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } @@ -403,32 +557,87 @@ W6692_l1hw(struct PStack *st, int pr, vo { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; + u_long flags; int val; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_d(cs, skb); + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + W6692_fill_fifo(cs); + } + spin_unlock_irqrestore(&cs->lock, flags); break; - case (PH_PULL |INDICATION): - xmit_pull_ind_d(cs, skb); + case (PH_PULL | INDICATION): + spin_lock_irqsave(&cs->lock, flags); + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + W6692_fill_fifo(cs); + spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_d(st); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): - if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) + spin_lock_irqsave(&cs->lock, flags); + if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) { ph_command(cs, W_L1CMD_ECK); - else { + spin_unlock_irqrestore(&cs->lock, flags); + } else { ph_command(cs, W_L1CMD_RST); cs->dc.w6692.ph_state = W_L1CMD_RST; + spin_unlock_irqrestore(&cs->lock, flags); W6692_new_ph(cs); } break; case (HW_ENABLE | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, W_L1CMD_ECK); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): + spin_lock_irqsave(&cs->lock, flags); ph_command(cs, W_L1CMD_AR8); + spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): val = 0; @@ -448,7 +657,7 @@ W6692_l1hw(struct PStack *st, int pr, vo if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_d_event(cs, D_CLEARBUSY); + schedule_event(cs, D_CLEARBUSY); break; default: if (cs->debug & L1_DEB_WARN) @@ -457,11 +666,15 @@ W6692_l1hw(struct PStack *st, int pr, vo } } -static int +static void setstack_W6692(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = W6692_l1hw; - return 0; +} + +static void +DC_Close_W6692(struct IsdnCardState *cs) +{ } static void @@ -469,10 +682,12 @@ dbusy_timer_handler(struct IsdnCardState { struct PStack *stptr; int rbch, star; + u_long flags; + spin_lock_irqsave(&cs->lock, flags); if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = w6692_read_reg(cs, W_D_RBCH); - star = w6692_read_reg(cs, W_D_STAR); + rbch = cs->readW6692(cs, W_D_RBCH); + star = cs->readW6692(cs, W_D_STAR); if (cs->debug) debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x", rbch, star); @@ -480,7 +695,7 @@ dbusy_timer_handler(struct IsdnCardState test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); stptr = cs->stlist; while (stptr != NULL) { - L1L2(stptr, PH_PAUSE | INDICATION, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } else { @@ -494,10 +709,13 @@ dbusy_timer_handler(struct IsdnCardState printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n"); debugl1(cs, "D-Channel Busy no skb"); } - w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */ - cs->card_ops->irq_func(cs->irq, cs, NULL); /* FIXME? */ + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */ + spin_unlock_irqrestore(&cs->lock, flags); + cs->irq_func(cs->irq, cs, NULL); + return; } } + spin_unlock_irqrestore(&cs->lock, flags); } static void @@ -514,51 +732,79 @@ W6692Bmode(struct BCState *bcs, int mode switch (mode) { case (L1_MODE_NULL): - w6692_bc_write_reg(cs, bchan, W_B_MODE, 0); + cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0); break; case (L1_MODE_TRANS): - w6692_bc_write_reg(cs, bchan, W_B_MODE, W_B_MODE_MMS); + cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS); break; case (L1_MODE_HDLC): - w6692_bc_write_reg(cs, bchan, W_B_MODE, W_B_MODE_ITF); - w6692_bc_write_reg(cs, bchan, W_B_ADM1, 0xff); - w6692_bc_write_reg(cs, bchan, W_B_ADM2, 0xff); + cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF); + cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff); + cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff); break; } if (mode) - w6692_bc_write_reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST | + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST); - w6692_bc_write_reg(cs, bchan, W_B_EXIM, 0x00); + cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00); } static void W6692_l2l1(struct PStack *st, int pr, void *arg) { struct sk_buff *skb = arg; + struct BCState *bcs = st->l1.bcs; + u_long flags; switch (pr) { case (PH_DATA | REQUEST): - xmit_data_req_b(st->l1.bcs, skb); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->tx_skb) { + skb_queue_tail(&bcs->squeue, skb); + } else { + bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->hw.w6692.count = 0; + bcs->cs->BC_Send_Data(bcs); + } + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | INDICATION): - xmit_pull_ind_b(st->l1.bcs, skb); + if (bcs->tx_skb) { + printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n"); + break; + } + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->tx_skb = skb; + bcs->hw.w6692.count = 0; + bcs->cs->BC_Send_Data(bcs); + spin_unlock_irqrestore(&bcs->cs->lock, flags); break; case (PH_PULL | REQUEST): - xmit_pull_req_b(st); + if (!bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (PH_ACTIVATE | REQUEST): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - W6692Bmode(st->l1.bcs, st->l1.mode, st->l1.bc); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); + W6692Bmode(bcs, st->l1.mode, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | REQUEST): l1_msg_b(st, pr, arg); break; case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - W6692Bmode(st->l1.bcs, 0, st->l1.bc); - L1L2(st, PH_DEACTIVATE | CONFIRM, NULL); + spin_lock_irqsave(&bcs->cs->lock, flags); + test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + W6692Bmode(bcs, 0, st->l1.bc); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); break; } } @@ -567,13 +813,52 @@ static void close_w6692state(struct BCState *bcs) { W6692Bmode(bcs, 0, bcs->channel); - bc_close(bcs); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.w6692.rcvbuf) { + kfree(bcs->hw.w6692.rcvbuf); + bcs->hw.w6692.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } } static int open_w6692state(struct IsdnCardState *cs, struct BCState *bcs) { - return bc_open(bcs); + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for w6692.rcvbuf\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.w6692.rcvbuf); + bcs->hw.w6692.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.w6692.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); } static int @@ -583,166 +868,224 @@ setstack_w6692(struct PStack *st, struct if (open_w6692state(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; - st->l1.l2l1 = W6692_l2l1; + st->l2.l2l1 = W6692_l2l1; setstack_manager(st); bcs->st = st; setstack_l1_B(st); return (0); } -static int -w6692_reset(struct IsdnCardState *cs) +void resetW6692(struct IsdnCardState *cs) { - w6692_write_reg(cs, W_D_CTL, W_D_CTL_SRST); - schedule_timeout((10*HZ)/1000); - w6692_write_reg(cs, W_D_CTL, 0x00); - schedule_timeout((10*HZ)/1000); - w6692_write_reg(cs, W_IMASK, 0xff); - w6692_write_reg(cs, W_D_SAM, 0xff); - w6692_write_reg(cs, W_D_TAM, 0xff); - w6692_write_reg(cs, W_D_EXIM, 0x00); - w6692_write_reg(cs, W_D_MODE, W_D_MODE_RACT); - w6692_write_reg(cs, W_IMASK, 0x18); + cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); + mdelay(10); + cs->writeW6692(cs, W_D_CTL, 0x00); + mdelay(10); + cs->writeW6692(cs, W_IMASK, 0xff); + cs->writeW6692(cs, W_D_SAM, 0xff); + cs->writeW6692(cs, W_D_TAM, 0xff); + cs->writeW6692(cs, W_D_EXIM, 0x00); + cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); + cs->writeW6692(cs, W_IMASK, 0x18); if (cs->subtyp == W6692_USR) { /* seems that USR implemented some power control features * Pin 79 is connected to the oscilator circuit so we * have to handle it here */ - w6692_write_reg(cs, W_PCTL, 0x80); - w6692_write_reg(cs, W_XDATA, 0x00); + cs->writeW6692(cs, W_PCTL, 0x80); + cs->writeW6692(cs, W_XDATA, 0x00); } - return 0; } -static void -w6692_init(struct IsdnCardState *cs) +void __init initW6692(struct IsdnCardState *cs, int part) { - w6692_reset(cs); - ph_command(cs, W_L1CMD_RST); - cs->dc.w6692.ph_state = W_L1CMD_RST; - W6692_new_ph(cs); - ph_command(cs, W_L1CMD_ECK); - - W6692Bmode(cs->bcs, 0, 0); - W6692Bmode(cs->bcs + 1, 0, 0); + if (part & 1) { + cs->setstack_d = setstack_W6692; + cs->DC_Close = DC_Close_W6692; + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + resetW6692(cs); + ph_command(cs, W_L1CMD_RST); + cs->dc.w6692.ph_state = W_L1CMD_RST; + W6692_new_ph(cs); + ph_command(cs, W_L1CMD_ECK); - /* Reenable all IRQ */ - w6692_write_reg(cs, W_IMASK, 0x18); - w6692_write_reg(cs, W_D_EXIM, 0x00); - w6692_bc_write_reg(cs, 0, W_B_EXIM, 0x00); - w6692_bc_write_reg(cs, 1, W_B_EXIM, 0x00); - /* Reset D-chan receiver and transmitter */ - w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); + cs->bcs[0].BC_SetStack = setstack_w6692; + cs->bcs[1].BC_SetStack = setstack_w6692; + cs->bcs[0].BC_Close = close_w6692state; + cs->bcs[1].BC_Close = close_w6692state; + W6692Bmode(cs->bcs, 0, 0); + W6692Bmode(cs->bcs + 1, 0, 0); + } + if (part & 2) { + /* Reenable all IRQ */ + cs->writeW6692(cs, W_IMASK, 0x18); + cs->writeW6692(cs, W_D_EXIM, 0x00); + cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00); + cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00); + /* Reset D-chan receiver and transmitter */ + cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); + } } +/* Interface functions */ -static void -w6692_release(struct IsdnCardState *cs) +static u_char +ReadW6692(struct IsdnCardState *cs, u_char offset) { - w6692_write_reg(cs, W_IMASK, 0xff); - if (cs->subtyp == W6692_USR) - w6692_write_reg(cs, W_XDATA, 0x04); - hisax_release_resources(cs); + return (inb(cs->hw.w6692.iobase + offset)); } -static struct card_ops w6692_ops = { - .init = w6692_init, - .reset = w6692_reset, - .release = w6692_release, - .irq_func = w6692_interrupt, -}; - -static struct dc_l1_ops w6692_dc_l1_ops = { - .fill_fifo = W6692_fill_fifo, - .open = setstack_W6692, - .bh_func = W6692_bh, - .dbusy_func = dbusy_timer_handler, -}; - -static struct bc_l1_ops w6692_bc_l1_ops = { - .fill_fifo = W6692B_fill_fifo, - .open = setstack_w6692, - .close = close_w6692state, -}; +static void +WriteW6692(struct IsdnCardState *cs, u_char offset, u_char value) +{ + outb(value, cs->hw.w6692.iobase + offset); +} -static int id_idx ; +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size); +} -static struct pci_dev *dev_w6692 __initdata = NULL; +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size); +} -static int -w6692_hw_init(struct IsdnCardState *cs) +static u_char +ReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset) { - cs->card_ops = &w6692_ops; - cs->dc_hw_ops = &w6692_dc_hw_ops, - cs->bc_hw_ops = &w6692_bc_hw_ops; - dc_l1_init(cs, &w6692_dc_l1_ops); - cs->bc_l1_ops = &w6692_bc_l1_ops; - W6692Version(cs, "W6692:"); - printk(KERN_INFO "W6692 ISTA=0x%X\n", w6692_read_reg(cs, W_ISTA)); - printk(KERN_INFO "W6692 IMASK=0x%X\n", w6692_read_reg(cs, W_IMASK)); - printk(KERN_INFO "W6692 D_EXIR=0x%X\n", w6692_read_reg(cs, W_D_EXIR)); - printk(KERN_INFO "W6692 D_EXIM=0x%X\n", w6692_read_reg(cs, W_D_EXIM)); - printk(KERN_INFO "W6692 D_RSTA=0x%X\n", w6692_read_reg(cs, W_D_RSTA)); - return 0; + return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset)); } -static int __init -w6692_probe(struct IsdnCardState *cs, struct pci_dev *pdev) +static void +WriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value) { - int rc; + outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset); +} - printk(KERN_INFO "W6692: %s %s at %#lx IRQ %d\n", - id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, - pci_resource_start(pdev, 1), pdev->irq); - - rc = -EBUSY; - if (pci_enable_device(pdev)) - goto err; - - /* USR ISDN PCI card TA need some special handling */ - if (cs->subtyp == W6692_WINBOND) { - if (pdev->subsystem_vendor == W6692_SV_USR && - pdev->subsystem_device == W6692_SD_USR) { - cs->subtyp = W6692_USR; - } +static int +w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + resetW6692(cs); + return (0); + case CARD_RELEASE: + cs->writeW6692(cs, W_IMASK, 0xff); + release_region(cs->hw.w6692.iobase, 256); + if (cs->subtyp == W6692_USR) { + cs->writeW6692(cs, W_XDATA, 0x04); + } + return (0); + case CARD_INIT: + initW6692(cs, 3); + return (0); + case CARD_TEST: + return (0); } - cs->irq = pdev->irq; - cs->irq_flags |= SA_SHIRQ; - cs->hw.w6692.iobase = pci_resource_start(pdev, 1); - - if (!request_io(&cs->rs, cs->hw.w6692.iobase, 0x100, - id_list[cs->subtyp].card_name)) - goto err; - - w6692_hw_init(cs); - return 0; - err: - hisax_release_resources(cs); - return rc; + return (0); } +static int id_idx ; + +static struct pci_dev *dev_w6692 __initdata = NULL; + int __init setup_w6692(struct IsdnCard *card) { + struct IsdnCardState *cs = card->cs; char tmp[64]; + u_char found = 0; + u_char pci_irq = 0; + u_int pci_ioaddr = 0; -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif strcpy(tmp, w6692_revision); printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_W6692) + return (0); +#if CONFIG_PCI while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, dev_w6692); if (dev_w6692) { - card->cs->subtyp = id_idx; - if (w6692_probe(card->cs, dev_w6692) < 0) - return 0; - return 1; + if (pci_enable_device(dev_w6692)) + continue; + cs->subtyp = id_idx; + break; } id_idx++; } - printk(KERN_WARNING "W6692: No PCI card found\n"); - return 0; + if (dev_w6692) { + found = 1; + pci_irq = dev_w6692->irq; + /* I think address 0 is allways the configuration area */ + /* and address 1 is the real IO space KKe 03.09.99 */ + pci_ioaddr = pci_resource_start(dev_w6692, 1); + /* USR ISDN PCI card TA need some special handling */ + if (cs->subtyp == W6692_WINBOND) { + if ((W6692_SV_USR == dev_w6692->subsystem_vendor) && + (W6692_SD_USR == dev_w6692->subsystem_device)) { + cs->subtyp = W6692_USR; + } + } + } + if (!found) { + printk(KERN_WARNING "W6692: No PCI card found\n"); + return (0); + } + cs->irq = pci_irq; + if (!cs->irq) { + printk(KERN_WARNING "W6692: No IRQ for PCI card found\n"); + return (0); + } + if (!pci_ioaddr) { + printk(KERN_WARNING "W6692: NO I/O Base Address found\n"); + return (0); + } + cs->hw.w6692.iobase = pci_ioaddr; + printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n", + id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, + pci_ioaddr, pci_irq); + if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) { + printk(KERN_WARNING + "HiSax: %s I/O ports %x-%x already in use\n", + id_list[cs->subtyp].card_name, + cs->hw.w6692.iobase, + cs->hw.w6692.iobase + 255); + return (0); + } +#else + printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); + printk(KERN_WARNING "HiSax: W6692 unable to config\n"); + return (0); +#endif /* CONFIG_PCI */ + + printk(KERN_INFO + "HiSax: %s config irq:%d I/O:%x\n", + id_list[cs->subtyp].card_name, cs->irq, + cs->hw.w6692.iobase); + + INIT_WORK(&cs->tqueue, (void *)(void *) W6692_bh, cs); + cs->readW6692 = &ReadW6692; + cs->writeW6692 = &WriteW6692; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadW6692B; + cs->BC_Write_Reg = &WriteW6692B; + cs->BC_Send_Data = &W6692B_fill_fifo; + cs->cardmsg = &w6692_card_msg; + cs->irq_func = &W6692_interrupt; + cs->irq_flags |= SA_SHIRQ; + W6692Version(cs, "W6692:"); + printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA)); + printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK)); + printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR)); + printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM)); + printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA)); + return (1); } diff -puN drivers/isdn/hisax/w6692.h~i4l drivers/isdn/hisax/w6692.h --- 25/drivers/isdn/hisax/w6692.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/hisax/w6692.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: w6692.h,v 1.2.6.2 2001/09/23 22:24:52 kai Exp $ +/* $Id: w6692.h,v 1.4.2.2 2004/01/12 22:52:29 keil Exp $ * * Winbond W6692 specific defines * @@ -18,6 +18,9 @@ /* B-channel FIFO read/write routines */ +#define READW6692BFIFO(cs,bchan,ptr,count) \ + insb(cs->hw.w6692.iobase+W_B_RFIFO+(bchan?0x40:0),ptr,count) + #define WRITEW6692BFIFO(cs,bchan,ptr,count) \ outsb(cs->hw.w6692.iobase+W_B_XFIFO+(bchan?0x40:0),ptr,count) diff -puN drivers/isdn/i4l/isdn_audio.c~i4l drivers/isdn/i4l/isdn_audio.c --- 25/drivers/isdn/i4l/isdn_audio.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_audio.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,20 +1,21 @@ -/* Linux ISDN subsystem, audio conversion and compression +/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $ + * + * Linux ISDN subsystem, audio conversion and compression (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * 1996 by Christian Mock (cm@tahina.priv.at) - * 1998 by Armin Schindler (mac@gismo.telekom.de) + * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) + * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - * DTMF code by Christian Mock - * Silence detection by Armin Schindler */ #include #include "isdn_audio.h" #include "isdn_common.h" -#include "isdn_tty.h" + +char *isdn_audio_revision = "$Revision: 1.1.2.2 $"; /* * Misc. lookup-tables. @@ -168,39 +169,19 @@ static char isdn_audio_ulaw_to_alaw[] = 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a }; -#define NCOEFF 16 /* number of frequencies to be analyzed */ -#define DTMF_TRESH 25000 /* above this is dtmf */ +#define NCOEFF 8 /* number of frequencies to be analyzed */ +#define DTMF_TRESH 4000 /* above this is dtmf */ #define SILENCE_TRESH 200 /* below this is silence */ -#define H2_TRESH 20000 /* 2nd harmonic */ #define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */ #define LOGRP 0 #define HIGRP 1 -typedef struct { - int grp; /* low/high group */ - int k; /* k */ - int k2; /* k fuer 2. harmonic */ -} dtmf_t; - /* For DTMF recognition: * 2 * cos(2 * PI * k / N) precalculated for all k */ static int cos2pik[NCOEFF] = { - 55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517, - 38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279 -}; - -static dtmf_t dtmf_tones[8] = -{ - {LOGRP, 0, 1}, /* 697 Hz */ - {LOGRP, 2, 3}, /* 770 Hz */ - {LOGRP, 4, 5}, /* 852 Hz */ - {LOGRP, 6, 7}, /* 941 Hz */ - {HIGRP, 8, 9}, /* 1209 Hz */ - {HIGRP, 10, 11}, /* 1336 Hz */ - {HIGRP, 12, 13}, /* 1477 Hz */ - {HIGRP, 14, 15} /* 1633 Hz */ + 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332 }; static char dtmf_matrix[4][4] = @@ -226,10 +207,8 @@ isdn_audio_tlookup(const u_char *table, : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) : "memory", "ax"); #else - while (n--) { - *buff = table[*buff]; - buff++; - } + while (n--) + *buff = table[*(unsigned char *)buff], buff++; #endif } @@ -500,13 +479,25 @@ isdn_audio_goertzel(int *sample, modem_i sk2 = sk1; sk1 = sk; } + /* Avoid overflows */ + sk >>= 1; + sk2 >>= 1; + /* compute |X(k)|**2 */ + /* report overflows. This should not happen. */ + /* Comment this out if desired */ + if (sk < -32768 || sk > 32767) + printk(KERN_DEBUG + "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk); + if (sk2 < -32768 || sk2 > 32767) + printk(KERN_DEBUG + "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2); result[k] = ((sk * sk) >> AMP_BITS) - ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) + ((sk2 * sk2) >> AMP_BITS); } skb_queue_tail(&info->dtmf_queue, skb); - mod_timer(&info->read_timer, jiffies + 4); + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); } void @@ -517,31 +508,63 @@ isdn_audio_eval_dtmf(modem_info * info) dtmf_state *s; int silence; int i; + int di; + int ch; int grp[2]; char what; char *p; + int thresh; while ((skb = skb_dequeue(&info->dtmf_queue))) { result = (int *) skb->data; s = info->dtmf_state; - grp[LOGRP] = grp[HIGRP] = -2; + grp[LOGRP] = grp[HIGRP] = -1; silence = 0; - for (i = 0; i < 8; i++) { - if ((result[dtmf_tones[i].k] > DTMF_TRESH) && - (result[dtmf_tones[i].k2] < H2_TRESH)) - grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1; - else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) && - (result[dtmf_tones[i].k2] < SILENCE_TRESH)) + thresh = 0; + for (i = 0; i < NCOEFF; i++) { + if (result[i] > DTMF_TRESH) { + if (result[i] > thresh) + thresh = result[i]; + } + else if (result[i] < SILENCE_TRESH) silence++; } - if (silence == 8) + if (silence == NCOEFF) what = ' '; else { - if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { - what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4]; - if (s->last != ' ' && s->last != '.') - s->last = what; /* min. 1 non-DTMF between DTMF */ - } else + if (thresh > 0) { + thresh = thresh >> 4; /* touchtones must match within 12 dB */ + for (i = 0; i < NCOEFF; i++) { + if (result[i] < thresh) + continue; /* ignore */ + /* good level found. This is allowed only one time per group */ + if (i < NCOEFF / 2) { + /* lowgroup*/ + if (grp[LOGRP] >= 0) { + // Bad. Another tone found. */ + grp[LOGRP] = -1; + break; + } + else + grp[LOGRP] = i; + } + else { /* higroup */ + if (grp[HIGRP] >= 0) { // Bad. Another tone found. */ + grp[HIGRP] = -1; + break; + } + else + grp[HIGRP] = i - NCOEFF/2; + } + } + if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { + what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]]; + if (s->last != ' ' && s->last != '.') + s->last = what; /* min. 1 non-DTMF between DTMF */ + } else + what = '.'; + } + else what = '.'; } if ((what != s->last) && (what != ' ') && (what != '.')) { @@ -550,17 +573,16 @@ isdn_audio_eval_dtmf(modem_info * info) *p++ = 0x10; *p = what; skb_trim(skb, 2); - if ((size_t)skb_headroom(skb) < sizeof(isdnaudio_header)) { - printk(KERN_WARNING - "isdn_audio: insufficient skb_headroom, dropping\n"); - kfree_skb(skb); - return; - } ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; ISDN_AUDIO_SKB_LOCK(skb) = 0; - isdn_tty_queue_tail(info, skb, 2); - if (((get_isdn_dev())->modempoll) && (info->rcvsched)) - mod_timer(&info->read_timer, jiffies + 4); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); } else kfree_skb(skb); s->last = what; @@ -648,6 +670,8 @@ void isdn_audio_put_dle_code(modem_info * info, u_char code) { struct sk_buff *skb; + int di; + int ch; char *p; skb = dev_alloc_skb(2); @@ -660,18 +684,16 @@ isdn_audio_put_dle_code(modem_info * inf p = (char *) skb_put(skb, 2); p[0] = 0x10; p[1] = code; - if ((size_t)skb_headroom(skb) < sizeof(isdnaudio_header)) { - printk(KERN_WARNING - "isdn_audio: insufficient skb_headroom, dropping\n"); - kfree_skb(skb); - return; - } ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; ISDN_AUDIO_SKB_LOCK(skb) = 0; - isdn_tty_queue_tail(info, skb, 2); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; /* Schedule dequeuing */ - if (((get_isdn_dev())->modempoll) && (info->rcvsched)) - mod_timer(&info->read_timer, jiffies + 4); + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); } void @@ -682,7 +704,7 @@ isdn_audio_eval_silence(modem_info * inf what = ' '; - if (s->idx > (u_int)(info->emu.vpar[2] * 800)) { + if (s->idx > (info->emu.vpar[2] * 800)) { s->idx = 0; if (!s->state) { /* silence from beginning of rec */ what = 's'; @@ -690,9 +712,9 @@ isdn_audio_eval_silence(modem_info * inf what = 'q'; } } - if ((what == 's') || (what == 'q')) { - printk(KERN_DEBUG "ttyI%d: %s\n", info->line, - (what=='s') ? "silence":"quiet"); - isdn_audio_put_dle_code(info, what); - } + if ((what == 's') || (what == 'q')) { + printk(KERN_DEBUG "ttyI%d: %s\n", info->line, + (what=='s') ? "silence":"quiet"); + isdn_audio_put_dle_code(info, what); + } } diff -puN drivers/isdn/i4l/isdn_audio.h~i4l drivers/isdn/i4l/isdn_audio.h --- 25/drivers/isdn/i4l/isdn_audio.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_audio.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,6 @@ -/* Linux ISDN subsystem, audio conversion and compression +/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $ + * + * Linux ISDN subsystem, audio conversion and compression (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * @@ -18,6 +20,7 @@ typedef struct adpcm_state { typedef struct dtmf_state { char last; + char llast; int idx; int buf[DTMF_NPOINTS]; } dtmf_state; diff -puN -L drivers/isdn/i4l/isdn_ciscohdlck.c drivers/isdn/i4l/isdn_ciscohdlck.c~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ciscohdlck.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,452 +0,0 @@ -/* Linux ISDN subsystem, CISCO HDLC network interfaces - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * 2001 by Bjoern A. Zeeb - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For info on the protocol, see http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt - */ - -#include "isdn_common.h" -#include "isdn_net_lib.h" -#include "isdn_ciscohdlck.h" - -#include -#include - -/* - * Definitions for Cisco-HDLC header. - */ - -#define CISCO_ADDR_UNICAST 0x0f -#define CISCO_ADDR_BROADCAST 0x8f -#define CISCO_CTRL 0x00 -#define CISCO_TYPE_CDP 0x2000 -#define CISCO_TYPE_SLARP 0x8035 -#define CISCO_SLARP_REQUEST 0 -#define CISCO_SLARP_REPLY 1 -#define CISCO_SLARP_KEEPALIVE 2 - -/* - * CISCO HDLC keepalive specific stuff - */ -static struct sk_buff* -isdn_net_ciscohdlck_alloc_skb(isdn_net_dev *idev, int len) -{ - unsigned short hl = isdn_slot_hdrlen(idev->isdn_slot); - struct sk_buff *skb; - - skb = alloc_skb(hl + len, GFP_ATOMIC); - if (!skb) { - printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); - return NULL; - } - skb_reserve(skb, hl); - return skb; -} - -/* cisco hdlck device private ioctls */ -static int -isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - isdn_net_local *mlp = dev->priv; - struct inl_cisco *cisco = mlp->inl_priv; - unsigned long len = 0; - int period; - char debserint; - int rc = 0; - - if (mlp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK) - return -EINVAL; - - switch (cmd) { - /* get/set keepalive period */ - case SIOCGKEEPPERIOD: - len = sizeof(cisco->keepalive_period); - if (copy_to_user((char *)ifr->ifr_ifru.ifru_data, - (char *)&cisco->keepalive_period, len)) - rc = -EFAULT; - break; - case SIOCSKEEPPERIOD: - len = sizeof(cisco->keepalive_period); - if (copy_from_user((char *)&period, - (char *)ifr->ifr_ifru.ifru_data, len)) { - rc = -EFAULT; - break; - } - if (period <= 0 || period > 32767) { - rc = -EINVAL; - break; - } - mod_timer(&cisco->timer, jiffies + period * HZ); - printk(KERN_INFO "%s: Keepalive period set " - "to %d seconds.\n", dev->name, period); - cisco->keepalive_period = period; - break; - - /* get/set debugging */ - case SIOCGDEBSERINT: - len = sizeof(cisco->debserint); - if (copy_to_user((char *)ifr->ifr_ifru.ifru_data, - (char *)&cisco->debserint, len)) - rc = -EFAULT; - break; - case SIOCSDEBSERINT: - len = sizeof(cisco->debserint); - if (copy_from_user((char *)&debserint, - (char *)ifr->ifr_ifru.ifru_data, len)) { - rc = -EFAULT; - break; - } - if (debserint < 0 || debserint > 64) { - rc = -EINVAL; - break; - } - cisco->debserint = debserint; - break; - - default: - rc = -EINVAL; - break; - } - return (rc); -} - -/* called via cisco_timer.function */ -static void -isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) -{ - isdn_net_local *mlp = (isdn_net_local *) data; - isdn_net_dev *idev; - struct inl_cisco *cisco = mlp->inl_priv; - struct sk_buff *skb; - unsigned char *p; - unsigned long last_cisco_myseq = cisco->myseq; - int myseq_diff = 0; - - if (list_empty(&mlp->online)) { - isdn_BUG(); - return; - } - idev = list_entry(mlp->online.next, isdn_net_dev, online); - cisco->myseq++; - - myseq_diff = cisco->myseq - cisco->mineseen; - if (cisco->line_state && (myseq_diff >= 3 || myseq_diff <= -3)) { - /* line up -> down */ - cisco->line_state = 0; - printk (KERN_WARNING - "UPDOWN: Line protocol on Interface %s," - " changed state to down\n", idev->name); - /* should stop routing higher-level data accross */ - } else if (!cisco->line_state && - myseq_diff >= 0 && myseq_diff <= 2) { - /* line down -> up */ - cisco->line_state = 1; - printk (KERN_WARNING - "UPDOWN: Line protocol on Interface %s," - " changed state to up\n", idev->name); - /* restart routing higher-level data accross */ - } - - if (cisco->debserint) - printk (KERN_DEBUG "%s: HDLC " - "myseq %u, mineseen %u%c, yourseen %u, %s\n", - idev->name, cisco->myseq, cisco->mineseen, - (last_cisco_myseq == cisco->mineseen) ? '*' : 040, - cisco->yourseq, - (cisco->line_state) ? "line up" : "line down"); - - skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); - - /* slarp keepalive */ - p += put_u32(p, CISCO_SLARP_KEEPALIVE); - p += put_u32(p, cisco->myseq); - p += put_u32(p, cisco->yourseq); - p += put_u16(p, 0xffff); // reliablity, always 0xffff - - isdn_net_write_super(idev, skb); - - mod_timer(&cisco->timer, jiffies + cisco->keepalive_period * HZ); -} - -static void -isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *mlp) -{ - isdn_net_dev *idev; - struct sk_buff *skb; - unsigned char *p; - - if (list_empty(&mlp->online)) { - isdn_BUG(); - return; - } - idev = list_entry(mlp->online.next, isdn_net_dev, online); - - skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); - - /* slarp request */ - p += put_u32(p, CISCO_SLARP_REQUEST); - p += put_u32(p, 0); // address - p += put_u32(p, 0); // netmask - p += put_u16(p, 0); // unused - - isdn_net_write_super(idev, skb); -} - -static void -isdn_ciscohdlck_connected(isdn_net_dev *idev) -{ - isdn_net_local *lp = idev->mlp; - struct inl_cisco *cisco = lp->inl_priv; - - cisco->myseq = 0; - cisco->mineseen = 0; - cisco->yourseq = 0; - cisco->keepalive_period = 10; - cisco->last_slarp_in = 0; - cisco->line_state = 0; - cisco->debserint = 0; - - if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) { - /* send slarp request because interface/seq.no.s reset */ - isdn_net_ciscohdlck_slarp_send_request(lp); - - init_timer(&cisco->timer); - cisco->timer.data = (unsigned long) lp; - cisco->timer.function = isdn_net_ciscohdlck_slarp_send_keepalive; - cisco->timer.expires = jiffies + cisco->keepalive_period * HZ; - add_timer(&cisco->timer); - } - netif_wake_queue(&lp->dev); -} - -static void -isdn_ciscohdlck_disconnected(isdn_net_dev *idev) -{ - isdn_net_local *lp = idev->mlp; - struct inl_cisco *cisco = lp->inl_priv; - - if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) { - del_timer(&cisco->timer); - } -} - -static void -isdn_net_ciscohdlck_slarp_send_reply(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - struct sk_buff *skb; - unsigned char *p; - struct in_device *in_dev = NULL; - u32 addr = 0; /* local ipv4 address */ - u32 mask = 0; /* local netmask */ - - if ((in_dev = mlp->dev.ip_ptr) != NULL) { - /* take primary(first) address of interface */ - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL) { - addr = ifa->ifa_local; - mask = ifa->ifa_mask; - } - } - - skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); - - /* slarp reply, send own ip/netmask; if values are nonsense remote - * should think we are unable to provide it with an address via SLARP */ - p += put_u32(p, CISCO_SLARP_REPLY); - p += put_u32(p, addr); // address - p += put_u32(p, mask); // netmask - p += put_u16(p, 0); // unused - - isdn_net_write_super(idev, skb); -} - -static void -isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb) -{ - isdn_net_local *mlp = idev->mlp; - struct inl_cisco *cisco = mlp->inl_priv; - unsigned char *p; - int period; - u32 code; - u32 my_seq, addr; - u32 your_seq, mask; - u32 local; - u16 unused; - - if (skb->len < 14) - return; - - p = skb->data; - p += get_u32(p, &code); - - switch (code) { - case CISCO_SLARP_REQUEST: - cisco->yourseq = 0; - isdn_net_ciscohdlck_slarp_send_reply(idev); - break; - case CISCO_SLARP_REPLY: - addr = ntohl(*(u32 *)p); - mask = ntohl(*(u32 *)(p+4)); - if (mask != 0xfffffffc) - goto slarp_reply_out; - if ((addr & 3) == 0 || (addr & 3) == 3) - goto slarp_reply_out; - local = addr ^ 3; - printk(KERN_INFO "%s: got slarp reply: " - "remote ip: %d.%d.%d.%d, " - "local ip: %d.%d.%d.%d " - "mask: %d.%d.%d.%d\n", - idev->name, - HIPQUAD(addr), - HIPQUAD(local), - HIPQUAD(mask)); - break; - slarp_reply_out: - printk(KERN_INFO "%s: got invalid slarp " - "reply (%d.%d.%d.%d/%d.%d.%d.%d) " - "- ignored\n", idev->name, - HIPQUAD(addr), HIPQUAD(mask)); - break; - case CISCO_SLARP_KEEPALIVE: - period = (jiffies - cisco->last_slarp_in + HZ/2 - 1) / HZ; - if (cisco->debserint && - (period != cisco->keepalive_period) && - cisco->last_slarp_in) { - printk(KERN_DEBUG "%s: Keepalive period mismatch - " - "is %d but should be %d.\n", - idev->name, period, cisco->keepalive_period); - } - cisco->last_slarp_in = jiffies; - p += get_u32(p, &my_seq); - p += get_u32(p, &your_seq); - p += get_u16(p, &unused); - cisco->yourseq = my_seq; - cisco->mineseen = your_seq; - break; - } -} - -static void -isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb) -{ - struct inl_cisco *cisco = lp->inl_priv; - unsigned char *p; - u8 addr; - u8 ctrl; - u16 type; - - if (skb->len < 4) - goto out_free; - - p = skb->data; - p += get_u8 (p, &addr); - p += get_u8 (p, &ctrl); - p += get_u16(p, &type); - skb_pull(skb, 4); - - if ((addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) || - ctrl != CISCO_CTRL) { - printk(KERN_DEBUG "%s: Unknown Cisco header %#02x %#02x\n", - idev->name, addr, ctrl); - goto out_free; - } - - switch (type) { - case CISCO_TYPE_SLARP: - isdn_net_ciscohdlck_slarp_in(idev, skb); - goto out_free; - case CISCO_TYPE_CDP: - if (cisco->debserint) - printk(KERN_DEBUG "%s: Received CDP packet. use " - "\"no cdp enable\" on cisco.\n", idev->name); - goto out_free; - default: - /* no special cisco protocol */ - idev->huptimer = 0; - skb->protocol = htons(type); - netif_rx(skb); - return; - } - - out_free: - kfree_skb(skb); -} - -static int -isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - void *daddr, void *saddr, unsigned plen) -{ - unsigned char *p = skb_push(skb, 4); - - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, type); - - return 4; -} - -static int -isdn_ciscohdlck_open(isdn_net_local *lp) -{ - lp->inl_priv = kmalloc(sizeof(struct inl_cisco), GFP_KERNEL); - if (!lp->inl_priv) - return -ENOMEM; - - return 0; -} - -static void -isdn_ciscohdlck_close(isdn_net_local *lp) -{ - kfree(lp->inl_priv); -} - -struct isdn_netif_ops isdn_ciscohdlck_ops = { - .hard_start_xmit = isdn_net_start_xmit, - .hard_header = isdn_ciscohdlck_header, - .do_ioctl = isdn_ciscohdlck_dev_ioctl, - .flags = IFF_NOARP | IFF_POINTOPOINT, - .type = ARPHRD_CISCO, - .receive = isdn_ciscohdlck_receive, - .connected = isdn_ciscohdlck_connected, - .disconnected = isdn_ciscohdlck_disconnected, - .open = isdn_ciscohdlck_open, - .close = isdn_ciscohdlck_close, -}; diff -puN -L drivers/isdn/i4l/isdn_ciscohdlck.h drivers/isdn/i4l/isdn_ciscohdlck.h~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ciscohdlck.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,26 +0,0 @@ -/* Linux ISDN subsystem, CISCO HDLC network interfaces - * - * Copyright 1999-2002 by Kai Germaschewski - * 2001 by Bjoern A. Zeeb - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef ISDN_CISCOHDLCK_H -#define ISDN_CISCOHDLCK_H - -extern struct isdn_netif_ops isdn_ciscohdlck_ops; - -struct inl_cisco { - u32 myseq; /* local keepalive seq. for Cisco */ - u32 mineseen; /* returned keepalive seq. from remote */ - u32 yourseq; /* remote keepalive seq. for Cisco */ - int keepalive_period; /* keepalive period */ - int last_slarp_in; /* jiffie of last recvd keepalive pkt */ - char line_state; /* state of line */ - char debserint; /* debugging flags */ - struct timer_list timer; -}; - -#endif diff -puN drivers/isdn/i4l/isdn_common.c~i4l drivers/isdn/i4l/isdn_common.c --- 25/drivers/isdn/i4l/isdn_common.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_common.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,6 @@ -/* Linux ISDN subsystem, common used functions +/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ + * + * Linux ISDN subsystem, common used functions (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg @@ -6,6 +8,7 @@ * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ #include @@ -16,811 +19,463 @@ #include #include #include -#include #include "isdn_common.h" -#include "isdn_net_lib.h" -#include "isdn_net.h" #include "isdn_tty.h" +#include "isdn_net.h" #include "isdn_ppp.h" #ifdef CONFIG_ISDN_AUDIO #include "isdn_audio.h" #endif +#ifdef CONFIG_ISDN_DIVERSION_MODULE +#define CONFIG_ISDN_DIVERSION +#endif +#ifdef CONFIG_ISDN_DIVERSION #include -#include +#endif /* CONFIG_ISDN_DIVERSION */ +#include "isdn_v110.h" + +/* Debugflags */ +#undef ISDN_DEBUG_STATCALLB MODULE_DESCRIPTION("ISDN4Linux: link layer"); MODULE_AUTHOR("Fritz Elfert"); MODULE_LICENSE("GPL"); -static isdn_dev_t *isdndev; +isdn_dev *dev; -isdn_dev_t * -get_isdn_dev(void) { - return(isdndev); -} - -/* Description of hardware-level-driver */ -typedef struct isdn_driver { - int di; - char id[20]; - atomic_t refcnt; - unsigned long flags; /* Misc driver Flags */ - unsigned long features; - int channels; /* Number of channels */ - wait_queue_head_t st_waitq; /* Wait-Queue for status-reads */ - int maxbufsize; /* Maximum Buffersize supported*/ - int stavail; /* Chars avail on Status-device*/ - isdn_if *interface; /* Interface to driver */ - char msn2eaz[10][ISDN_MSNLEN]; /* MSN->EAZ */ - spinlock_t lock; - struct isdn_slot *slots; - struct fsm_inst fi; -} isdn_driver_t; - -static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; -static isdn_driver_t *drivers[ISDN_MAX_DRIVERS]; - -static void isdn_lock_driver(struct isdn_driver *drv); -static void isdn_unlock_driver(struct isdn_driver *drv); - -/* ====================================================================== */ - -static void drv_destroy(struct isdn_driver *drv); - -static inline struct isdn_driver * -get_drv(struct isdn_driver *drv) -{ - printk("get_drv %d: %d -> %d\n", drv->di, atomic_read(&drv->refcnt), - atomic_read(&drv->refcnt) + 1); - atomic_inc(&drv->refcnt); - return drv; -} +static char *isdn_revision = "$Revision: 1.1.2.3 $"; -static inline void -put_drv(struct isdn_driver *drv) -{ - printk("put_drv %d: %d -> %d\n", drv->di, atomic_read(&drv->refcnt), - atomic_read(&drv->refcnt) - 1); - if (atomic_dec_and_test(&drv->refcnt)) { - drv_destroy(drv); - } -} +extern char *isdn_net_revision; +extern char *isdn_tty_revision; +#ifdef CONFIG_ISDN_PPP +extern char *isdn_ppp_revision; +#else +static char *isdn_ppp_revision = ": none $"; +#endif +#ifdef CONFIG_ISDN_AUDIO +extern char *isdn_audio_revision; +#else +static char *isdn_audio_revision = ": none $"; +#endif +extern char *isdn_v110_revision; -/* ====================================================================== */ - -static struct fsm slot_fsm; -static void slot_debug(struct fsm_inst *fi, char *fmt, ...); - -static char *slot_st_str[] = { - "ST_SLOT_NULL", - "ST_SLOT_BOUND", - "ST_SLOT_IN", - "ST_SLOT_WAIT_DCONN", - "ST_SLOT_DCONN", - "ST_SLOT_WAIT_BCONN", - "ST_SLOT_ACTIVE", - "ST_SLOT_WAIT_BHUP", - "ST_SLOT_WAIT_DHUP", -}; +#ifdef CONFIG_ISDN_DIVERSION +static isdn_divert_if *divert_if; /* = NULL */ +#endif /* CONFIG_ISDN_DIVERSION */ -static char *ev_str[] = { - "EV_DRV_REGISTER", - "EV_STAT_RUN", - "EV_STAT_STOP", - "EV_STAT_UNLOAD", - "EV_STAT_STAVAIL", - "EV_STAT_ADDCH", - "EV_STAT_ICALL", - "EV_STAT_DCONN", - "EV_STAT_BCONN", - "EV_STAT_BHUP", - "EV_STAT_DHUP", - "EV_STAT_BSENT", - "EV_STAT_CINF", - "EV_STAT_CAUSE", - "EV_STAT_DISPLAY", - "EV_STAT_FAXIND", - "EV_STAT_AUDIO", - "EV_CMD_CLREAZ", - "EV_CMD_SETEAZ", - "EV_CMD_SETL2", - "EV_CMD_SETL3", - "EV_CMD_DIAL", - "EV_CMD_ACCEPTD", - "EV_CMD_ACCEPTB", - "EV_CMD_HANGUP", - "EV_DATA_REQ", - "EV_DATA_IND", - "EV_SLOT_BIND", - "EV_SLOT_UNBIND", -}; -static int __slot_command(struct isdn_slot *slot, isdn_ctrl *cmd); +static int isdn_writebuf_stub(int, int, const u_char *, int, int); +static void set_global_features(void); +static int isdn_wildmat(char *s, char *p); -static void isdn_v110_setl2(struct isdn_slot *slot, isdn_ctrl *cmd); -static void __isdn_v110_open(struct isdn_slot *slot); -static void __isdn_v110_close(struct isdn_slot *slot); -static void __isdn_v110_bsent(struct isdn_slot *slot, int pr, isdn_ctrl *cmd); -static int isdn_v110_data_ind(struct isdn_slot *slot, struct sk_buff *skb); -static int isdn_v110_data_req(struct isdn_slot *slot, struct sk_buff *skb); -static inline int -do_event_cb(struct isdn_slot *slot, int pr, void *arg) +static inline void +isdn_lock_driver(isdn_driver_t *drv) { - if (slot->event_cb) - return slot->event_cb(slot, pr, arg); - - return -ENXIO; + try_module_get(drv->interface->owner); + drv->locks++; } -static int -slot_bind(struct fsm_inst *fi, int pr, void *arg) +void +isdn_lock_drivers(void) { - struct isdn_slot *slot = fi->userdata; - - isdn_lock_driver(slot->drv); - fsm_change_state(fi, ST_SLOT_BOUND); + int i; - return 0; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) { + if (!dev->drv[i]) + continue; + isdn_lock_driver(dev->drv[i]); + } } -/* just pass through command */ -static int -slot_command(struct fsm_inst *fi, int pr, void *arg) +static inline void +isdn_unlock_driver(isdn_driver_t *drv) { - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *c = arg; - - return __slot_command(slot, c); + if (drv->locks > 0) { + drv->locks--; + module_put(drv->interface->owner); + } } -/* just pass through status */ -static int -slot_stat(struct fsm_inst *fi, int pr, void *arg) +void +isdn_unlock_drivers(void) { - struct isdn_slot *slot = fi->userdata; + int i; - do_event_cb(slot, pr, arg); - return 0; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) { + if (!dev->drv[i]) + continue; + isdn_unlock_driver(dev->drv[i]); + } } -/* just pass through command */ -static int -slot_setl2(struct fsm_inst *fi, int pr, void *arg) +#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) +void +isdn_dumppkt(char *s, u_char * p, int len, int dumplen) { - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *c = arg; - - isdn_v110_setl2(slot, c); + int dumpc; - return __slot_command(slot, c); + printk(KERN_DEBUG "%s(%d) ", s, len); + for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++) + printk(" %02x", *p++); + printk("\n"); } +#endif +/* + * I picked the pattern-matching-functions from an old GNU-tar version (1.10) + * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) + */ static int -slot_dial(struct fsm_inst *fi, int pr, void *arg) +isdn_star(char *s, char *p) { - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *ctrl = arg; - int retval; - - retval = __slot_command(slot, ctrl); - if (retval >= 0) - fsm_change_state(fi, ST_SLOT_WAIT_DCONN); - - return retval; + while (isdn_wildmat(s, p)) { + if (*++s == '\0') + return (2); + } + return (0); } -static int -slot_acceptd(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *ctrl = arg; - int retval; - - retval = __slot_command(slot, ctrl); - if (retval >= 0) - fsm_change_state(fi, ST_SLOT_WAIT_DCONN); - - return retval; -} +/* + * Shell-type Pattern-matching for incoming caller-Ids + * This function gets a string in s and checks, if it matches the pattern + * given in p. + * + * Return: + * 0 = match. + * 1 = no match. + * 2 = no match. Would eventually match, if s would be longer. + * + * Possible Patterns: + * + * '?' matches one character + * '*' matches zero or more characters + * [xyz] matches the set of characters in brackets. + * [^xyz] matches any single character not in the set of characters + */ static int -slot_acceptb(struct fsm_inst *fi, int pr, void *arg) +isdn_wildmat(char *s, char *p) { - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *ctrl = arg; - int retval; - - retval = __slot_command(slot, ctrl); - if (retval >= 0) - fsm_change_state(fi, ST_SLOT_WAIT_BCONN); + register int last; + register int matched; + register int reverse; + register int nostar = 1; - return retval; + if (!(*s) && !(*p)) + return(1); + for (; *p; s++, p++) + switch (*p) { + case '\\': + /* + * Literal match with following character, + * fall through. + */ + p++; + default: + if (*s != *p) + return (*s == '\0')?2:1; + continue; + case '?': + /* Match anything. */ + if (*s == '\0') + return (2); + continue; + case '*': + nostar = 0; + /* Trailing star matches everything. */ + return (*++p ? isdn_star(s, p) : 0); + case '[': + /* [^....] means inverse character class. */ + if ((reverse = (p[1] == '^'))) + p++; + for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) + matched = 1; + if (matched == reverse) + return (1); + continue; + } + return (*s == '\0')?0:nostar; } -static int -slot_actv_hangup(struct fsm_inst *fi, int pr, void *arg) +int isdn_msncmp( const char * msn1, const char * msn2 ) { - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *ctrl = arg; - int retval; + char TmpMsn1[ ISDN_MSNLEN ]; + char TmpMsn2[ ISDN_MSNLEN ]; + char *p; - retval = __slot_command(slot, ctrl); - if (retval >= 0) { - fsm_change_state(fi, ST_SLOT_WAIT_BHUP); - } - return retval; -} + for ( p = TmpMsn1; *msn1 && *msn1 != ':'; ) // Strip off a SPID + *p++ = *msn1++; + *p = '\0'; -static int -slot_dconn(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_slot *slot = fi->userdata; + for ( p = TmpMsn2; *msn2 && *msn2 != ':'; ) // Strip off a SPID + *p++ = *msn2++; + *p = '\0'; - fsm_change_state(fi, ST_SLOT_DCONN); - do_event_cb(slot, pr, arg); - return 0; + return isdn_wildmat( TmpMsn1, TmpMsn2 ); } -static int -slot_bconn(struct fsm_inst *fi, int pr, void *arg) +int +isdn_dc2minor(int di, int ch) { - struct isdn_slot *slot = fi->userdata; - - fsm_change_state(fi, ST_SLOT_ACTIVE); - __isdn_v110_open(slot); - - isdn_info_update(); - - do_event_cb(slot, pr, arg); - return 0; + int i; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (dev->chanmap[i] == ch && dev->drvmap[i] == di) + return i; + return -1; } -static int -slot_bhup(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_slot *slot = fi->userdata; - - __isdn_v110_close(slot); - fsm_change_state(fi, ST_SLOT_WAIT_DHUP); +static int isdn_timer_cnt1 = 0; +static int isdn_timer_cnt2 = 0; +static int isdn_timer_cnt3 = 0; - do_event_cb(slot, pr, arg); - return 0; -} - -static int -slot_dhup(struct fsm_inst *fi, int pr, void *arg) +static void +isdn_timer_funct(ulong dummy) { - struct isdn_slot *slot = fi->userdata; - - fsm_change_state(fi, ST_SLOT_BOUND); - - do_event_cb(slot, pr, arg); - return 0; + int tf = dev->tflags; + if (tf & ISDN_TIMER_FAST) { + if (tf & ISDN_TIMER_MODEMREAD) + isdn_tty_readmodem(); + if (tf & ISDN_TIMER_MODEMPLUS) + isdn_tty_modem_escape(); + if (tf & ISDN_TIMER_MODEMXMIT) + isdn_tty_modem_xmit(); + } + if (tf & ISDN_TIMER_SLOW) { + if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) { + isdn_timer_cnt1 = 0; + if (tf & ISDN_TIMER_NETDIAL) + isdn_net_dial(); + } + if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { + isdn_timer_cnt2 = 0; + if (tf & ISDN_TIMER_NETHANGUP) + isdn_net_autohup(); + if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) { + isdn_timer_cnt3 = 0; + if (tf & ISDN_TIMER_MODEMRING) + isdn_tty_modem_ring(); + } + if (tf & ISDN_TIMER_CARRIER) + isdn_tty_carrier_timeout(); + } + } + if (tf) + mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES); } -static int -slot_data_req(struct fsm_inst *fi, int pr, void *arg) +void +isdn_timer_ctrl(int tf, int onoff) { - struct isdn_slot *slot = fi->userdata; - struct sk_buff *skb = arg; + unsigned long flags; + int old_tflags; - return isdn_v110_data_req(slot, skb); + spin_lock_irqsave(&dev->timerlock, flags); + if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) { + /* If the slow-timer wasn't activated until now */ + isdn_timer_cnt1 = 0; + isdn_timer_cnt2 = 0; + } + old_tflags = dev->tflags; + if (onoff) + dev->tflags |= tf; + else + dev->tflags &= ~tf; + if (dev->tflags && !old_tflags) + mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES); + spin_unlock_irqrestore(&dev->timerlock, flags); } -static int -slot_data_ind(struct fsm_inst *fi, int pr, void *arg) +/* + * Receive a packet from B-Channel. (Called from low-level-module) + */ +static void +isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) { - struct isdn_slot *slot = fi->userdata; - struct sk_buff *skb = arg; + int i; + if ((i = isdn_dc2minor(di, channel)) == -1) { + dev_kfree_skb(skb); + return; + } /* Update statistics */ - slot->ibytes += skb->len; - - return isdn_v110_data_ind(slot, skb); -} - -static int -slot_bsent(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *ctrl = arg; - - __isdn_v110_bsent(slot, pr, ctrl); - return 0; -} - -static int -slot_icall(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_slot *slot = fi->userdata; - isdn_ctrl *ctrl = arg; - int retval; - - isdn_lock_driver(slot->drv); - fsm_change_state(fi, ST_SLOT_IN); - slot_debug(fi, "ICALL: %s\n", ctrl->parm.num); - if (isdndev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; + dev->ibytes[i] += skb->len; - strcpy(slot->num, ctrl->parm.setup.phone); - /* Try to find a network-interface which will accept incoming call */ - retval = isdn_net_find_icall(slot, &ctrl->parm.setup); - - /* already taken by net now? */ - if (fi->state != ST_SLOT_IN) - goto out; + /* First, try to deliver data to network-device */ + if (isdn_net_rcv_skb(i, skb)) + return; - retval = isdn_tty_find_icall(slot, &ctrl->parm.setup); - out: - return 0; + /* V.110 handling + * makes sense for async streams only, so it is + * called after possible net-device delivery. + */ + if (dev->v110[i]) { + atomic_inc(&dev->v110use[i]); + skb = isdn_v110_decode(dev->v110[i], skb); + atomic_dec(&dev->v110use[i]); + if (!skb) + return; + } + + /* No network-device found, deliver to tty or raw-channel */ + if (skb->len) { + if (isdn_tty_rcv_skb(i, di, channel, skb)) + return; + wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]); + } else + dev_kfree_skb(skb); } -/* should become broadcast later */ -static int -slot_in_dhup(struct fsm_inst *fi, int pr, void *arg) +/* + * Intercept command from Linklevel to Lowlevel. + * If layer 2 protocol is V.110 and this is not supported by current + * lowlevel-driver, use driver's transparent mode and handle V.110 in + * linklevel instead. + */ +int +isdn_command(isdn_ctrl *cmd) { - struct isdn_slot *slot = fi->userdata; - - isdn_unlock_driver(slot->drv); - fsm_change_state(fi, ST_SLOT_NULL); - do_event_cb(slot, pr, arg); - return 0; + if (cmd->driver == -1) { + printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command); + return(1); + } + if (cmd->command == ISDN_CMD_SETL2) { + int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255); + unsigned long l2prot = (cmd->arg >> 8) & 255; + unsigned long features = (dev->drv[cmd->driver]->interface->features + >> ISDN_FEATURE_L2_SHIFT) & + ISDN_FEATURE_L2_MASK; + unsigned long l2_feature = (1 << l2prot); + + switch (l2prot) { + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: + /* If V.110 requested, but not supported by + * HL-driver, set emulator-flag and change + * Layer-2 to transparent + */ + if (!(features & l2_feature)) { + dev->v110emu[idx] = l2prot; + cmd->arg = (cmd->arg & 255) | + (ISDN_PROTO_L2_TRANS << 8); + } else + dev->v110emu[idx] = 0; + } + } + return dev->drv[cmd->driver]->interface->command(cmd); } -static int -slot_unbind(struct fsm_inst *fi, int pr, void *arg) +void +isdn_all_eaz(int di, int ch) { - struct isdn_slot *slot = fi->userdata; isdn_ctrl cmd; - isdn_unlock_driver(slot->drv); - fsm_change_state(fi, ST_SLOT_NULL); - strcpy(slot->num, "???"); + if (di < 0) + return; + cmd.driver = di; + cmd.arg = ch; + cmd.command = ISDN_CMD_SETEAZ; cmd.parm.num[0] = '\0'; - isdn_slot_command(slot, ISDN_CMD_SETEAZ, &cmd); - slot->ibytes = 0; - slot->obytes = 0; - slot->usage = ISDN_USAGE_NONE; - put_drv(slot->drv); - isdn_info_update(); - return 0; + isdn_command(&cmd); } -static struct fsm_node slot_fn_tbl[] = { - { ST_SLOT_NULL, EV_SLOT_BIND, slot_bind }, - { ST_SLOT_NULL, EV_STAT_ICALL, slot_icall }, - - { ST_SLOT_BOUND, EV_CMD_CLREAZ, slot_command }, - { ST_SLOT_BOUND, EV_CMD_SETEAZ, slot_command }, - { ST_SLOT_BOUND, EV_CMD_SETL2, slot_setl2 }, - { ST_SLOT_BOUND, EV_CMD_SETL3, slot_command }, - { ST_SLOT_BOUND, EV_CMD_DIAL, slot_dial }, - { ST_SLOT_BOUND, EV_SLOT_UNBIND, slot_unbind }, - - { ST_SLOT_IN, EV_CMD_SETL2, slot_setl2 }, - { ST_SLOT_IN, EV_CMD_SETL3, slot_command }, - { ST_SLOT_IN, EV_CMD_ACCEPTD, slot_acceptd }, - { ST_SLOT_IN, EV_STAT_DHUP, slot_in_dhup }, - - { ST_SLOT_WAIT_DCONN, EV_STAT_DCONN, slot_dconn }, - { ST_SLOT_WAIT_DCONN, EV_STAT_DHUP, slot_dhup }, - - { ST_SLOT_DCONN, EV_CMD_ACCEPTB, slot_acceptb }, - { ST_SLOT_DCONN, EV_STAT_BCONN, slot_bconn }, - - { ST_SLOT_WAIT_BCONN, EV_STAT_BCONN, slot_bconn }, - - { ST_SLOT_ACTIVE, EV_DATA_REQ, slot_data_req }, - { ST_SLOT_ACTIVE, EV_DATA_IND, slot_data_ind }, - { ST_SLOT_ACTIVE, EV_CMD_HANGUP, slot_actv_hangup }, - { ST_SLOT_ACTIVE, EV_STAT_BSENT, slot_bsent }, - { ST_SLOT_ACTIVE, EV_STAT_BHUP, slot_bhup }, - { ST_SLOT_ACTIVE, EV_STAT_FAXIND, slot_stat }, - { ST_SLOT_ACTIVE, EV_STAT_AUDIO, slot_stat }, - - { ST_SLOT_WAIT_BHUP, EV_STAT_BHUP, slot_bhup }, - - { ST_SLOT_WAIT_DHUP, EV_STAT_DHUP, slot_dhup }, -}; - -static struct fsm slot_fsm = { - .st_cnt = ARRAY_SIZE(slot_st_str), - .st_str = slot_st_str, - .ev_cnt = ARRAY_SIZE(ev_str), - .ev_str = ev_str, - .fn_cnt = ARRAY_SIZE(slot_fn_tbl), - .fn_tbl = slot_fn_tbl, -}; - -static void slot_debug(struct fsm_inst *fi, char *fmt, ...) -{ - va_list args; - struct isdn_slot *slot = fi->userdata; - char buf[128]; - char *p = buf; +/* + * Begin of a CAPI like LL<->HL interface, currently used only for + * supplementary service (CAPI 2.0 part III) + */ +#include - va_start(args, fmt); - p += sprintf(p, "slot (%d:%d): ", slot->di, slot->ch); - p += vsprintf(p, fmt, args); - va_end(args); - printk(KERN_DEBUG "%s\n", buf); +int +isdn_capi_rec_hl_msg(capi_msg *cm) { + + int di; + int ch; + + di = (cm->adr.Controller & 0x7f) -1; + ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f); + switch(cm->Command) { + case CAPI_FACILITY: + /* in the moment only handled in tty */ + return(isdn_tty_capi_facility(cm)); + default: + return(-1); + } } -/* ====================================================================== */ - -static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED; - -static struct fsm drv_fsm; +static int +isdn_status_callback(isdn_ctrl * c) +{ + int di; + u_long flags; + int i; + int r; + int retval = 0; + isdn_ctrl cmd; + isdn_net_dev *p; -enum { - ST_DRV_NULL, - ST_DRV_LOADED, - ST_DRV_RUNNING, -}; - -static char *drv_st_str[] = { - "ST_DRV_NULL", - "ST_DRV_LOADED", - "ST_DRV_RUNNING", -}; - -#define DRV_FLAG_REJBUS 1 - -static int __drv_command(struct isdn_driver *drv, isdn_ctrl *cmd); - -static int -isdn_writebuf_skb(struct isdn_slot *slot, struct sk_buff *skb) -{ - struct sk_buff *skb2; - struct isdn_driver *drv = slot->drv; - int hl = drv->interface->hl_hdrlen; - int retval; - - if (skb_headroom(skb) >= hl) { - retval = drv->interface->writebuf_skb(slot->di, slot->ch, 1, skb); - goto out; - } - skb2 = skb_realloc_headroom(skb, hl); - if (!skb2) { - retval = -ENOMEM; - goto out; - } - retval = drv->interface->writebuf_skb(slot->di, slot->ch, 1, skb2); - if (retval < 0) - kfree_skb(skb2); - else - kfree_skb(skb); - - out: - if (retval > 0) - slot->obytes += retval; - - return retval; -} - -int -__isdn_drv_lookup(char *drvid) -{ - int drvidx; - - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { - if (!drivers[drvidx]) - continue; - - if (strcmp(drivers[drvidx]->id, drvid) == 0) - return drvidx; - } - return -1; -} - -int -isdn_drv_lookup(char *drvid) -{ - unsigned long flags; - int drvidx; - - spin_lock_irqsave(&drivers_lock, flags); - drvidx = __isdn_drv_lookup(drvid); - spin_unlock_irqrestore(&drivers_lock, flags); - return drvidx; -} - -static void -drv_destroy(struct isdn_driver *drv) -{ - kfree(drv->slots); - kfree(drv); -} - -static struct isdn_driver * -get_drv_by_nr(int di) -{ - unsigned long flags; - struct isdn_driver *drv; - - BUG_ON(di < 0 || di >= ISDN_MAX_DRIVERS); - - spin_lock_irqsave(&drivers_lock, flags); - drv = drivers[di]; - if (drv) - get_drv(drv); - spin_unlock_irqrestore(&drivers_lock, flags); - return drv; -} - -char * -isdn_drv_drvid(int di) -{ - if (!drivers[di]) { - isdn_BUG(); - return ""; - } - return drivers[di]->id; -} - -/* - * Helper keeping track of the features the drivers support - */ -static void -set_global_features(void) -{ - unsigned long flags; - int drvidx; - - isdndev->global_features = 0; - spin_lock_irqsave(&drivers_lock, flags); - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { - if (!drivers[drvidx]) - continue; - if (drivers[drvidx]->fi.state != ST_DRV_RUNNING) - continue; - isdndev->global_features |= drivers[drvidx]->features; - } - spin_unlock_irqrestore(&drivers_lock, flags); -} - -/* - * driver state machine - */ -static int isdn_add_channels(struct isdn_driver *, int); -static void isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb); -static int isdn_status_callback(isdn_ctrl * c); - -static void isdn_v110_add_features(struct isdn_driver *drv); - -static int -drv_register(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_driver *drv = fi->userdata; - isdn_if *iif = arg; - - fsm_change_state(fi, ST_DRV_LOADED); - drv->maxbufsize = iif->maxbufsize; - drv->interface = iif; - iif->channels = drv->di; - iif->rcvcallb_skb = isdn_receive_skb_callback; - iif->statcallb = isdn_status_callback; - - isdn_info_update(); - return(0); -} - -static int -drv_stat_run(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_driver *drv = fi->userdata; - fsm_change_state(fi, ST_DRV_RUNNING); - - drv->features = drv->interface->features; - isdn_v110_add_features(drv); - set_global_features(); - return(0); -} - -static int -drv_stat_stop(struct fsm_inst *fi, int pr, void *arg) -{ - fsm_change_state(fi, ST_DRV_LOADED); - set_global_features(); - return(0); -} - -static int -drv_stat_unload(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_driver *drv = fi->userdata; - unsigned long flags; - - spin_lock_irqsave(&drivers_lock, flags); - drivers[drv->di] = NULL; - spin_unlock_irqrestore(&drivers_lock, flags); - put_drv(drv); - - isdndev->channels -= drv->channels; - - isdn_info_update(); - return 0; -} - -static int -drv_stat_stavail(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_driver *drv = fi->userdata; - unsigned long flags; - isdn_ctrl *c = arg; - - spin_lock_irqsave(&stat_lock, flags); - drv->stavail += c->arg; - spin_unlock_irqrestore(&stat_lock, flags); - wake_up_interruptible(&drv->st_waitq); - return 0; -} - -static int -drv_to_slot(struct fsm_inst *fi, int pr, void *arg) -{ - struct isdn_driver *drv = fi->userdata; - isdn_ctrl *c = arg; - int ch = c->arg & 0xff; - - return fsm_event(&drv->slots[ch].fi, pr, arg); -} - -static struct fsm_node drv_fn_tbl[] = { - { ST_DRV_NULL, EV_DRV_REGISTER, drv_register }, - - { ST_DRV_LOADED, EV_STAT_RUN, drv_stat_run }, - { ST_DRV_LOADED, EV_STAT_STAVAIL, drv_stat_stavail }, - { ST_DRV_LOADED, EV_STAT_UNLOAD, drv_stat_unload }, - - { ST_DRV_RUNNING, EV_STAT_STOP, drv_stat_stop }, - { ST_DRV_RUNNING, EV_STAT_STAVAIL, drv_stat_stavail }, - { ST_DRV_RUNNING, EV_STAT_ICALL, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_DCONN, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_BCONN, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_BHUP, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_DHUP, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_BSENT, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_CINF, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_CAUSE, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_DISPLAY, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_FAXIND, drv_to_slot }, - { ST_DRV_RUNNING, EV_STAT_AUDIO, drv_to_slot }, -}; - -static struct fsm drv_fsm = { - .st_cnt = ARRAY_SIZE(drv_st_str), - .st_str = drv_st_str, - .ev_cnt = ARRAY_SIZE(ev_str), - .ev_str = ev_str, - .fn_cnt = ARRAY_SIZE(drv_fn_tbl), - .fn_tbl = drv_fn_tbl, -}; - -static void drv_debug(struct fsm_inst *fi, char *fmt, ...) -{ - va_list args; - struct isdn_driver *drv = fi->userdata; - char buf[128]; - char *p = buf; - - va_start(args, fmt); - p += sprintf(p, "%s: ", drv->id); - p += vsprintf(p, fmt, args); - va_end(args); - printk(KERN_DEBUG "%s\n", buf); -} - -/* ====================================================================== */ -/* callbacks from hardware driver */ -/* ====================================================================== */ - -/* Receive a packet from B-Channel. */ -static void -isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb) -{ - struct isdn_driver *drv; - - drv = get_drv_by_nr(di); - if (!drv) { - /* hardware driver is buggy - driver isn't registered */ - isdn_BUG(); - goto out; - } - /* we short-cut here instead of going through the driver fsm */ - if (drv->fi.state != ST_DRV_RUNNING) { - /* hardware driver is buggy - driver isn't running */ - isdn_BUG(); - goto out; - } - if (fsm_event(&drv->slots[ch].fi, EV_DATA_IND, skb)) - dev_kfree_skb(skb); - out: - put_drv(drv); -} - -/* Receive status indications */ -static int -isdn_status_callback(isdn_ctrl *c) -{ - struct isdn_driver *drv; - int rc; - - drv = get_drv_by_nr(c->driver); - if (!drv) { - /* hardware driver is buggy - driver isn't registered */ - isdn_BUG(); - return 1; - } - + di = c->driver; + i = isdn_dc2minor(di, c->arg); switch (c->command) { + case ISDN_STAT_BSENT: + if (i < 0) + return -1; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + if (isdn_net_stat_callback(i, c)) + return 0; + if (isdn_v110_stat_callback(i, c)) + return 0; + if (isdn_tty_stat_callback(i, c)) + return 0; + wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); + break; case ISDN_STAT_STAVAIL: - rc = fsm_event(&drv->fi, EV_STAT_STAVAIL, c); + dev->drv[di]->stavail += c->arg; + wake_up_interruptible(&dev->drv[di]->st_waitq); break; case ISDN_STAT_RUN: - rc = fsm_event(&drv->fi, EV_STAT_RUN, c); + dev->drv[di]->flags |= DRV_FLAG_RUNNING; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (dev->drvmap[i] == di) + isdn_all_eaz(di, dev->chanmap[i]); + set_global_features(); break; case ISDN_STAT_STOP: - rc = fsm_event(&drv->fi, EV_STAT_STOP, c); - break; - case ISDN_STAT_UNLOAD: - rc = fsm_event(&drv->fi, EV_STAT_UNLOAD, c); - break; - case ISDN_STAT_ADDCH: - rc = fsm_event(&drv->fi, EV_STAT_ADDCH, c); + dev->drv[di]->flags &= ~DRV_FLAG_RUNNING; break; case ISDN_STAT_ICALL: - rc = fsm_event(&drv->fi, EV_STAT_ICALL, c); - break; - case ISDN_STAT_DCONN: - rc = fsm_event(&drv->fi, EV_STAT_DCONN, c); - break; - case ISDN_STAT_BCONN: - rc = fsm_event(&drv->fi, EV_STAT_BCONN, c); - break; - case ISDN_STAT_BHUP: - rc = fsm_event(&drv->fi, EV_STAT_BHUP, c); - break; - case ISDN_STAT_DHUP: - rc = fsm_event(&drv->fi, EV_STAT_DHUP, c); - break; - case ISDN_STAT_BSENT: - rc = fsm_event(&drv->fi, EV_STAT_BSENT, c); - break; - case ISDN_STAT_CINF: - rc = fsm_event(&drv->fi, EV_STAT_CINF, c); - break; - case ISDN_STAT_CAUSE: - rc = fsm_event(&drv->fi, EV_STAT_CAUSE, c); - break; - case ISDN_STAT_DISPLAY: - rc = fsm_event(&drv->fi, EV_STAT_DISPLAY, c); - break; - case ISDN_STAT_FAXIND: - rc = fsm_event(&drv->fi, EV_STAT_FAXIND, c); - break; - case ISDN_STAT_AUDIO: - rc = fsm_event(&drv->fi, EV_STAT_AUDIO, c); - break; -#warning FIXME divert interface -#if 0 - case ISDN_STAT_ICALL: - /* Find any ttyI, waiting for D-channel setup */ - if (isdn_tty_stat_callback(i, c)) { + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num); +#endif + if (dev->global_flags & ISDN_GLOBAL_STOPPED) { cmd.driver = di; cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTB; + cmd.command = ISDN_CMD_HANGUP; isdn_command(&cmd); - break; + return 0; } - break; + /* Try to find a network-interface which will accept incoming call */ + r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup)); switch (r) { case 0: + /* No network-device replies. + * Try ttyI's. + * These return 0 on no match, 1 on match and + * 3 on eventually match, if CID is longer. + */ + if (c->command == ISDN_STAT_ICALL) + if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval); +#ifdef CONFIG_ISDN_DIVERSION if (divert_if) - if ((retval = divert_if->stat_callback(c))) - return(retval); /* processed */ - if ((!retval) && (drivers[di]->flags & DRV_FLAG_REJBUS)) { + if ((retval = divert_if->stat_callback(c))) + return(retval); /* processed */ +#endif /* CONFIG_ISDN_DIVERSION */ + if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) { /* No tty responding */ cmd.driver = di; cmd.arg = c->arg; @@ -829,7 +484,21 @@ isdn_status_callback(isdn_ctrl *c) retval = 2; } break; - case 1: /* incoming call accepted by net interface */ + case 1: + /* Schedule connection-setup */ + isdn_net_dial(); + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_ACCEPTD; + for ( p = dev->netdev; p; p = p->next ) + if ( p->local->isdn_channel == cmd.arg ) + { + strcpy( cmd.parm.setup.eazmsn, p->local->msn ); + isdn_command(&cmd); + retval = 1; + break; + } + break; case 2: /* For calling back, first reject incoming call ... */ case 3: /* Interface found, but down, reject call actively */ @@ -844,730 +513,716 @@ isdn_status_callback(isdn_ctrl *c) /* Fall through */ case 4: /* ... then start callback. */ + isdn_net_dial(); break; case 5: /* Number would eventually match, if longer */ retval = 3; break; } - dbg_statcallb("ICALL: ret=%d\n", retval); +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "ICALL: ret=%d\n", retval); +#endif return retval; break; + case ISDN_STAT_CINF: + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num); +#endif + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + if (strcmp(c->parm.num, "0")) + isdn_net_stat_callback(i, c); + isdn_tty_stat_callback(i, c); + break; + case ISDN_STAT_CAUSE: +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num); +#endif + printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n", + dev->drvid[di], c->arg, c->parm.num); + isdn_tty_stat_callback(i, c); +#ifdef CONFIG_ISDN_DIVERSION + if (divert_if) + divert_if->stat_callback(c); +#endif /* CONFIG_ISDN_DIVERSION */ + break; + case ISDN_STAT_DISPLAY: +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display); +#endif + isdn_tty_stat_callback(i, c); +#ifdef CONFIG_ISDN_DIVERSION + if (divert_if) + divert_if->stat_callback(c); +#endif /* CONFIG_ISDN_DIVERSION */ + break; + case ISDN_STAT_DCONN: + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "DCONN: %ld\n", c->arg); +#endif + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + /* Find any net-device, waiting for D-channel setup */ + if (isdn_net_stat_callback(i, c)) + break; + isdn_v110_stat_callback(i, c); + /* Find any ttyI, waiting for D-channel setup */ + if (isdn_tty_stat_callback(i, c)) { + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_ACCEPTB; + isdn_command(&cmd); + break; + } + break; case ISDN_STAT_DHUP: + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "DHUP: %ld\n", c->arg); +#endif + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + dev->drv[di]->online &= ~(1 << (c->arg)); + isdn_info_update(); + /* Signal hangup to network-devices */ + if (isdn_net_stat_callback(i, c)) + break; + isdn_v110_stat_callback(i, c); + if (isdn_tty_stat_callback(i, c)) + break; +#ifdef CONFIG_ISDN_DIVERSION if (divert_if) - divert_if->stat_callback(c); + divert_if->stat_callback(c); +#endif /* CONFIG_ISDN_DIVERSION */ + break; + break; + case ISDN_STAT_BCONN: + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "BCONN: %ld\n", c->arg); +#endif + /* Signal B-channel-connect to network-devices */ + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + dev->drv[di]->online |= (1 << (c->arg)); + isdn_info_update(); + if (isdn_net_stat_callback(i, c)) + break; + isdn_v110_stat_callback(i, c); + if (isdn_tty_stat_callback(i, c)) + break; + break; + case ISDN_STAT_BHUP: + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "BHUP: %ld\n", c->arg); +#endif + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + dev->drv[di]->online &= ~(1 << (c->arg)); + isdn_info_update(); +#ifdef CONFIG_ISDN_X25 + /* Signal hangup to network-devices */ + if (isdn_net_stat_callback(i, c)) + break; +#endif + isdn_v110_stat_callback(i, c); + if (isdn_tty_stat_callback(i, c)) + break; + break; + case ISDN_STAT_NODCH: + if (i < 0) + return -1; +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "NODCH: %ld\n", c->arg); +#endif + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + if (isdn_net_stat_callback(i, c)) + break; + if (isdn_tty_stat_callback(i, c)) + break; + break; + case ISDN_STAT_ADDCH: + spin_lock_irqsave(&dev->lock, flags); + if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) { + spin_unlock_irqrestore(&dev->lock, flags); + return -1; + } + spin_unlock_irqrestore(&dev->lock, flags); + isdn_info_update(); break; case ISDN_STAT_DISCH: - save_flags(flags); - cli(); + spin_lock_irqsave(&dev->lock, flags); for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if ((slots[i].di == di) && - (slots[i].ch == c->arg)) { - if (c->parm.num[0]) - slots[i].usage &= ~ISDN_USAGE_DISABLED; - else if (USG_NONE(isdn_slot_usage(i))) - slots[i].usage |= ISDN_USAGE_DISABLED; - else - retval = -1; - break; + if ((dev->drvmap[i] == di) && + (dev->chanmap[i] == c->arg)) { + if (c->parm.num[0]) + dev->usage[i] &= ~ISDN_USAGE_DISABLED; + else + if (USG_NONE(dev->usage[i])) { + dev->usage[i] |= ISDN_USAGE_DISABLED; + } + else + retval = -1; + break; } - restore_flags(flags); + spin_unlock_irqrestore(&dev->lock, flags); + isdn_info_update(); + break; + case ISDN_STAT_UNLOAD: + while (dev->drv[di]->locks > 0) { + isdn_unlock_driver(dev->drv[di]); + } + spin_lock_irqsave(&dev->lock, flags); + isdn_tty_stat_callback(i, c); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (dev->drvmap[i] == di) { + dev->drvmap[i] = -1; + dev->chanmap[i] = -1; + dev->usage[i] &= ~ISDN_USAGE_DISABLED; + } + dev->drivers--; + dev->channels -= dev->drv[di]->channels; + kfree(dev->drv[di]->rcverr); + kfree(dev->drv[di]->rcvcount); + for (i = 0; i < dev->drv[di]->channels; i++) + skb_queue_purge(&dev->drv[di]->rpqueue[i]); + kfree(dev->drv[di]->rpqueue); + kfree(dev->drv[di]->rcv_waitq); + kfree(dev->drv[di]); + dev->drv[di] = NULL; + dev->drvid[di][0] = '\0'; + isdn_info_update(); + set_global_features(); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; + case ISDN_STAT_L1ERR: break; case CAPI_PUT_MESSAGE: return(isdn_capi_rec_hl_msg(&c->parm.cmsg)); +#ifdef CONFIG_ISDN_TTY_FAX + case ISDN_STAT_FAXIND: + isdn_tty_stat_callback(i, c); + break; +#endif +#ifdef CONFIG_ISDN_AUDIO + case ISDN_STAT_AUDIO: + isdn_tty_stat_callback(i, c); + break; +#endif +#ifdef CONFIG_ISDN_DIVERSION case ISDN_STAT_PROT: case ISDN_STAT_REDIR: if (divert_if) - return(divert_if->stat_callback(c)); -#endif + return(divert_if->stat_callback(c)); +#endif /* CONFIG_ISDN_DIVERSION */ default: - rc = 1; + return -1; } - put_drv(drv); - return rc; + return 0; } -/* ====================================================================== */ - /* - * Register a new ISDN interface + * Get integer from char-pointer, set pointer to end of number */ int -register_isdn(isdn_if *iif) -{ - struct isdn_driver *drv; - unsigned long flags; - int drvidx; - - drv = kmalloc(sizeof(*drv), GFP_ATOMIC); - if (!drv) { - printk(KERN_WARNING "register_isdn: out of mem\n"); - goto fail; - } - memset(drv, 0, sizeof(*drv)); - - atomic_set(&drv->refcnt, 0); - spin_lock_init(&drv->lock); - init_waitqueue_head(&drv->st_waitq); - drv->fi.fsm = &drv_fsm; - drv->fi.state = ST_DRV_NULL; - drv->fi.debug = 1; - drv->fi.userdata = drv; - drv->fi.printdebug = drv_debug; - - spin_lock_irqsave(&drivers_lock, flags); - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) - if (!drivers[drvidx]) - break; - - if (drvidx == ISDN_MAX_DRIVERS) - goto fail_unlock; - - if (!strlen(iif->id)) - sprintf(iif->id, "line%d", drvidx); - - if (__isdn_drv_lookup(iif->id) >= 0) - goto fail_unlock; - - strcpy(drv->id, iif->id); - if (isdn_add_channels(drv, iif->channels)) - goto fail_unlock; - - drv->di = drvidx; - drivers[drvidx] = get_drv(drv); - spin_unlock_irqrestore(&drivers_lock, flags); - - fsm_event(&drv->fi, EV_DRV_REGISTER, iif); - return 1; - - fail_unlock: - spin_unlock_irqrestore(&drivers_lock, flags); - kfree(drv); - fail: - return 0; -} - -/* ====================================================================== */ - -#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE) -static isdn_divert_if *divert_if; /* = NULL */ -#else -#define divert_if ((isdn_divert_if *) NULL) -#endif - -static int isdn_wildmat(char *s, char *p); - -static void -isdn_lock_driver(struct isdn_driver *drv) -{ - // FIXME don't ignore return value - try_module_get(drv->interface->owner); -} - -static void -isdn_unlock_driver(struct isdn_driver *drv) -{ - module_put(drv->interface->owner); -} - -#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -void -isdn_dumppkt(char *s, u_char * p, int len, int dumplen) +isdn_getnum(char **p) { - int dumpc; + int v = -1; - printk(KERN_DEBUG "%s(%d) ", s, len); - for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++) - printk(" %02x", *p++); - printk("\n"); + while (*p[0] >= '0' && *p[0] <= '9') + v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0'); + return v; } -#endif -/* - * I picked the pattern-matching-functions from an old GNU-tar version (1.10) - * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) - */ -static int -isdn_star(char *s, char *p) -{ - while (isdn_wildmat(s, p)) { - if (*++s == '\0') - return (2); - } - return (0); -} +#define DLE 0x10 /* - * Shell-type Pattern-matching for incoming caller-Ids - * This function gets a string in s and checks, if it matches the pattern - * given in p. + * isdn_readbchan() tries to get data from the read-queue. + * It MUST be called with interrupts off. * - * Return: - * 0 = match. - * 1 = no match. - * 2 = no match. Would eventually match, if s would be longer. - * - * Possible Patterns: - * - * '?' matches one character - * '*' matches zero or more characters - * [xyz] matches the set of characters in brackets. - * [^xyz] matches any single character not in the set of characters + * Be aware that this is not an atomic operation when sleep != 0, even though + * interrupts are turned off! Well, like that we are currently only called + * on behalf of a read system call on raw device files (which are documented + * to be dangerous and for for debugging purpose only). The inode semaphore + * takes care that this is not called for the same minor device number while + * we are sleeping, but access is not serialized against simultaneous read() + * from the corresponding ttyI device. Can other ugly events, like changes + * of the mapping (di,ch)<->minor, happen during the sleep? --he */ - -static int -isdn_wildmat(char *s, char *p) +int +isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep) { - register int last; - register int matched; - register int reverse; - register int nostar = 1; + int count; + int count_pull; + int count_put; + int dflag; + struct sk_buff *skb; + u_char *cp; - if (!(*s) && !(*p)) - return(1); - for (; *p; s++, p++) - switch (*p) { - case '\\': - /* - * Literal match with following character, - * fall through. - */ - p++; - default: - if (*s != *p) - return (*s == '\0')?2:1; - continue; - case '?': - /* Match anything. */ - if (*s == '\0') - return (2); - continue; - case '*': - nostar = 0; - /* Trailing star matches everything. */ - return (*++p ? isdn_star(s, p) : 0); - case '[': - /* [^....] means inverse character class. */ - if ((reverse = (p[1] == '^'))) + if (!dev->drv[di]) + return 0; + if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) { + if (sleep) + interruptible_sleep_on(sleep); + else + return 0; + } + if (len > dev->drv[di]->rcvcount[channel]) + len = dev->drv[di]->rcvcount[channel]; + cp = buf; + count = 0; + while (len) { + if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) + break; +#ifdef CONFIG_ISDN_AUDIO + if (ISDN_AUDIO_SKB_LOCK(skb)) + break; + ISDN_AUDIO_SKB_LOCK(skb) = 1; + if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) { + char *p = skb->data; + unsigned long DLEmask = (1 << channel); + + dflag = 0; + count_pull = count_put = 0; + while ((count_pull < skb->len) && (len > 0)) { + len--; + if (dev->drv[di]->DLEflag & DLEmask) { + *cp++ = DLE; + dev->drv[di]->DLEflag &= ~DLEmask; + } else { + *cp++ = *p; + if (*p == DLE) { + dev->drv[di]->DLEflag |= DLEmask; + (ISDN_AUDIO_SKB_DLECOUNT(skb))--; + } p++; - for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) - /* This next line requires a good C compiler. */ - if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) - matched = 1; - if (matched == reverse) - return (1); - continue; + count_pull++; + } + count_put++; + } + if (count_pull >= skb->len) + dflag = 1; + } else { +#endif + /* No DLE's in buff, so simply copy it */ + dflag = 1; + if ((count_pull = skb->len) > len) { + count_pull = len; + dflag = 0; + } + count_put = count_pull; + memcpy(cp, skb->data, count_put); + cp += count_put; + len -= count_put; +#ifdef CONFIG_ISDN_AUDIO } - return (*s == '\0')?0:nostar; -} - -int isdn_msncmp( const char * msn1, const char * msn2 ) -{ - char TmpMsn1[ ISDN_MSNLEN ]; - char TmpMsn2[ ISDN_MSNLEN ]; - char *p; - - for ( p = TmpMsn1; *msn1 && *msn1 != ':'; ) // Strip off a SPID - *p++ = *msn1++; - *p = '\0'; - - for ( p = TmpMsn2; *msn2 && *msn2 != ':'; ) // Strip off a SPID - *p++ = *msn2++; - *p = '\0'; - - return isdn_wildmat( TmpMsn1, TmpMsn2 ); -} - -static int -__drv_command(struct isdn_driver *drv, isdn_ctrl *c) -{ -#ifdef ISDN_DEBUG_COMMAND - switch (c->command) { - case ISDN_CMD_SETL2: - printk(KERN_DEBUG "ISDN_CMD_SETL2 %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_SETL3: - printk(KERN_DEBUG "ISDN_CMD_SETL3 %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_DIAL: - printk(KERN_DEBUG "ISDN_CMD_DIAL %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_ACCEPTD: - printk(KERN_DEBUG "ISDN_CMD_ACCEPTD %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_ACCEPTB: - printk(KERN_DEBUG "ISDN_CMD_ACCEPTB %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_HANGUP: - printk(KERN_DEBUG "ISDN_CMD_HANGUP %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_CLREAZ: - printk(KERN_DEBUG "ISDN_CMD_CLREAZ %d/%ld\n", c->driver, c->arg & 0xff); break; - case ISDN_CMD_SETEAZ: - printk(KERN_DEBUG "ISDN_CMD_SETEAZ %d/%ld\n", c->driver, c->arg & 0xff); break; - default: - printk(KERN_DEBUG "%s: cmd = %d\n", __FUNCTION__, c->command); - } #endif - return drv->interface->command(c); -} - -static int -__slot_command(struct isdn_slot *slot, isdn_ctrl *cmd) -{ - struct isdn_driver *drv = slot->drv; - - return __drv_command(drv, cmd); -} - -/* - * Begin of a CAPI like LL<->HL interface, currently used only for - * supplementary service (CAPI 2.0 part III) - */ -#include - -int -isdn_capi_rec_hl_msg(capi_msg *cm) -{ - switch(cm->Command) { - case CAPI_FACILITY: - /* in the moment only handled in tty */ - return isdn_tty_capi_facility(cm); - default: - return -1; + count += count_put; + if (fp) { + memset(fp, 0, count_put); + fp += count_put; + } + if (dflag) { + /* We got all the data in this buff. + * Now we can dequeue it. + */ + if (fp) + *(fp - 1) = 0xff; +#ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif + skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); + dev_kfree_skb(skb); + } else { + /* Not yet emptied this buff, so it + * must stay in the queue, for further calls + * but we pull off the data we got until now. + */ + skb_pull(skb, count_pull); +#ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif + } + dev->drv[di]->rcvcount[channel] -= count_put; } + return count; } -/* - * Get integer from char-pointer, set pointer to end of number - */ -int -isdn_getnum(char **p) +static __inline int +isdn_minor2drv(int minor) { - int v = -1; - - while (*p[0] >= '0' && *p[0] <= '9') - v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0'); - return v; + return (dev->drvmap[minor]); } -static struct isdn_slot * -get_slot_by_minor(int minor) +static __inline int +isdn_minor2chan(int minor) { - int di, ch; - struct isdn_driver *drv; - - for (di = 0; di < ISDN_MAX_DRIVERS; di++) { - drv = get_drv_by_nr(di); - if (!drv) - continue; - - for (ch = 0; ch < drv->channels; ch++) { - if (minor-- == 0) - goto found; - } - put_drv(drv); - } - return NULL; - - found: - return drv->slots + ch; -} - -static inline void -put_slot(struct isdn_slot *slot) -{ - put_drv(slot->drv); + return (dev->chanmap[minor]); } static char * isdn_statstr(void) { static char istatbuf[2048]; - struct isdn_slot *slot; char *p; int i; sprintf(istatbuf, "idmap:\t"); p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - sprintf(p, "%s ", slot->drv->id); - put_slot(slot); - } else { - sprintf(p, "- "); - } + sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]); p = istatbuf + strlen(istatbuf); } sprintf(p, "\nchmap:\t"); p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - sprintf(p, "%d ", slot->ch); - put_slot(slot); - } else { - sprintf(p, "-1 "); - } + sprintf(p, "%d ", dev->chanmap[i]); p = istatbuf + strlen(istatbuf); } sprintf(p, "\ndrmap:\t"); p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - sprintf(p, "%d ", slot->di); - put_slot(slot); - } else { - sprintf(p, "-1 "); - } + sprintf(p, "%d ", dev->drvmap[i]); + p = istatbuf + strlen(istatbuf); } sprintf(p, "\nusage:\t"); p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - sprintf(p, "%d ", slot->usage); - put_slot(slot); - } else { - sprintf(p, "0 "); - } + sprintf(p, "%d ", dev->usage[i]); p = istatbuf + strlen(istatbuf); } sprintf(p, "\nflags:\t"); p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - sprintf(p, "0 "); - put_slot(slot); + if (dev->drv[i]) { + sprintf(p, "%ld ", dev->drv[i]->online); + p = istatbuf + strlen(istatbuf); } else { sprintf(p, "? "); + p = istatbuf + strlen(istatbuf); } - p = istatbuf + strlen(istatbuf); } sprintf(p, "\nphone:\t"); p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - sprintf(p, "%s ", slot->num); - put_slot(slot); - } else { - sprintf(p, " "); - } + sprintf(p, "%s ", dev->num[i]); p = istatbuf + strlen(istatbuf); } sprintf(p, "\n"); return istatbuf; } -/* - * /dev/isdninfo - */ +/* Module interface-code */ void isdn_info_update(void) { - infostruct *p = isdndev->infochain; - - while (p) { - *(p->private) = 1; - p = (infostruct *) p->next; - } - wake_up_interruptible(&(isdndev->info_waitq)); -} - -static int -isdn_status_open(struct inode *ino, struct file *filep) -{ - infostruct *p; - - p = kmalloc(sizeof(infostruct), GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->next = (char *) isdndev->infochain; - p->private = (char *) &(filep->private_data); - isdndev->infochain = p; - /* At opening we allow a single update */ - filep->private_data = (char *) 1; - - return 0; -} - -static int -isdn_status_release(struct inode *ino, struct file *filep) -{ - infostruct *p = isdndev->infochain; - infostruct *q = NULL; - - lock_kernel(); - - while (p) { - if (p->private == (char *) &(filep->private_data)) { - if (q) - q->next = p->next; - else - isdndev->infochain = (infostruct *) (p->next); - kfree(p); - goto out; - } - q = p; - p = (infostruct *) (p->next); - } - printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); + infostruct *p = dev->infochain; - out: - unlock_kernel(); - return 0; + while (p) { + *(p->private) = 1; + p = (infostruct *) p->next; + } + wake_up_interruptible(&(dev->info_waitq)); } static ssize_t -isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off) +isdn_read(struct file *file, char *buf, size_t count, loff_t * off) { + uint minor = MINOR(file->f_dentry->d_inode->i_rdev); + int len = 0; + int drvidx; + int chidx; int retval; - size_t len = 0; char *p; if (off != &file->f_pos) return -ESPIPE; - if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(&(isdndev->info_waitq)); - } lock_kernel(); - p = isdn_statstr(); - file->private_data = 0; - if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) { - retval = -EFAULT; + if (minor == ISDN_MINOR_STATUS) { + if (!file->private_data) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + interruptible_sleep_on(&(dev->info_waitq)); + } + p = isdn_statstr(); + file->private_data = 0; + if ((len = strlen(p)) <= count) { + if (copy_to_user(buf, p, len)) { + retval = -EFAULT; + goto out; + } + *off += len; + retval = len; + goto out; + } + retval = 0; + goto out; + } + if (!dev->drivers) { + retval = -ENODEV; + goto out; + } + if (minor <= ISDN_MINOR_BMAX) { + printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); + drvidx = isdn_minor2drv(minor); + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { + retval = -ENODEV; goto out; } + chidx = isdn_minor2chan(minor); + if (!(p = kmalloc(count, GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } + len = isdn_readbchan(drvidx, chidx, p, 0, count, + &dev->drv[drvidx]->rcv_waitq[chidx]); *off += len; + if (copy_to_user(buf,p,len)) + len = -EFAULT; + kfree(p); retval = len; goto out; } - retval = 0; - goto out; - + if (minor <= ISDN_MINOR_CTRLMAX) { + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + if (!dev->drv[drvidx]->stavail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); + } + if (dev->drv[drvidx]->interface->readstat) { + if (count > dev->drv[drvidx]->stavail) + count = dev->drv[drvidx]->stavail; + len = dev->drv[drvidx]->interface-> + readstat(buf, count, 1, drvidx, + isdn_minor2chan(minor)); + } else { + len = 0; + } + if (len) + dev->drv[drvidx]->stavail -= len; + else + dev->drv[drvidx]->stavail = 0; + *off += len; + retval = len; + goto out; + } +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count); + goto out; + } +#endif + retval = -ENODEV; out: unlock_kernel(); return retval; } static ssize_t -isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off) -{ - return -EPERM; -} - -static unsigned int -isdn_status_poll(struct file *file, poll_table *wait) -{ - unsigned int mask = 0; - - poll_wait(file, &(isdndev->info_waitq), wait); - lock_kernel(); - if (file->private_data) - mask |= POLLIN | POLLRDNORM; - unlock_kernel(); - return mask; -} - -static int -isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -{ - static unsigned long zero_ul = 0UL; - int ret; - struct isdn_slot *slot; - - switch (cmd) { - case IIOCGETDVR: - return (TTY_DV + - (NET_DV << 8) + - (INF_DV << 16)); - case IIOCGETCPS: - if (arg) { - ulong *p = (ulong *) arg; - int i; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) - return ret; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - slot = get_slot_by_minor(i); - if (slot) { - put_user(slot->ibytes, p++); - put_user(slot->obytes, p++); - put_slot(slot); - } else { - put_user(zero_ul, p++); - put_user(zero_ul, p++); - } - } - return 0; - } else - return -EINVAL; - break; - case IIOCNETGPN: - return isdn_net_ioctl(inode, file, cmd, arg); - default: - return -EINVAL; - } -} - -static struct file_operations isdn_status_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_status_read, - .write = isdn_status_write, - .poll = isdn_status_poll, - .ioctl = isdn_status_ioctl, - .open = isdn_status_open, - .release = isdn_status_release, -}; - -/* - * /dev/isdnctrlX - */ - -static int -isdn_ctrl_open(struct inode *ino, struct file *file) -{ - unsigned int minor = iminor(ino); - struct isdn_slot *slot = get_slot_by_minor(minor - ISDN_MINOR_CTRL); - - if (!slot) - return -ENODEV; - - isdn_lock_driver(slot->drv); - file->private_data = slot; - - return 0; -} - -static int -isdn_ctrl_release(struct inode *ino, struct file *file) -{ - struct isdn_slot *slot = file->private_data; - - if (isdndev->profd == current) - isdndev->profd = NULL; - - isdn_unlock_driver(slot->drv); - put_slot(slot); - - return 0; -} - -static ssize_t -isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off) +isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) { - struct isdn_slot *slot = file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - size_t len = 0; + uint minor = MINOR(file->f_dentry->d_inode->i_rdev); + int drvidx; + int chidx; + int retval; if (off != &file->f_pos) return -ESPIPE; - if (!slot->drv->interface->readstat) { - isdn_BUG(); - return 0; - } - add_wait_queue(&slot->drv->st_waitq, &wait); - for (;;) { - spin_lock_irqsave(&stat_lock, flags); - len = slot->drv->stavail; - spin_unlock_irqrestore(&stat_lock, flags); - if (len > 0) - break; - if (signal_pending(current)) { - len = -ERESTARTSYS; - break; + if (minor == ISDN_MINOR_STATUS) + return -EPERM; + if (!dev->drivers) + return -ENODEV; + + lock_kernel(); + if (minor <= ISDN_MINOR_BMAX) { + printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); + drvidx = isdn_minor2drv(minor); + if (drvidx < 0) { + retval = -ENODEV; + goto out; } - if (file->f_flags & O_NONBLOCK) { - len = -EAGAIN; - break; + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { + retval = -ENODEV; + goto out; } - schedule(); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&slot->drv->st_waitq, &wait); - - if (len < 0) - return len; - - if (count > len) - count = len; - - len = slot->drv->interface->readstat(buf, count, 1, slot->di, - slot->ch); - - spin_lock_irqsave(&stat_lock, flags); - if (len) { - slot->drv->stavail -= len; - } else { - isdn_BUG(); - slot->drv->stavail = 0; + chidx = isdn_minor2chan(minor); + while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) + interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); + retval = count; + goto out; } - spin_unlock_irqrestore(&stat_lock, flags); - - *off += len; - return len; -} - -static ssize_t -isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off) -{ - struct isdn_slot *slot = file->private_data; - int retval; - - if (off != &file->f_pos) { - retval = -ESPIPE; + if (minor <= ISDN_MINOR_CTRLMAX) { + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + /* + * We want to use the isdnctrl device to load the firmware + * + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) + return -ENODEV; + */ + if (dev->drv[drvidx]->interface->writecmd) + retval = dev->drv[drvidx]->interface-> + writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)); + else + retval = count; goto out; } - if (!slot->drv->interface->writecmd) { - retval = -EINVAL; +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count); goto out; } - retval = slot->drv->interface->writecmd(buf, count, 1, slot->di, - slot->ch); - +#endif + retval = -ENODEV; out: + unlock_kernel(); return retval; } static unsigned int -isdn_ctrl_poll(struct file *file, poll_table *wait) +isdn_poll(struct file *file, poll_table * wait) { - struct isdn_slot *slot = file->private_data; unsigned int mask = 0; + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - poll_wait(file, &slot->drv->st_waitq, wait); - mask = POLLOUT | POLLWRNORM; - if (slot->drv->stavail) - mask |= POLLIN | POLLRDNORM; - + lock_kernel(); + if (minor == ISDN_MINOR_STATUS) { + poll_wait(file, &(dev->info_waitq), wait); + /* mask = POLLOUT | POLLWRNORM; */ + if (file->private_data) { + mask |= POLLIN | POLLRDNORM; + } + goto out; + } + if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { + if (drvidx < 0) { + /* driver deregistered while file open */ + mask = POLLHUP; + goto out; + } + poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); + mask = POLLOUT | POLLWRNORM; + if (dev->drv[drvidx]->stavail) { + mask |= POLLIN | POLLRDNORM; + } + goto out; + } +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) { + mask = isdn_ppp_poll(file, wait); + goto out; + } +#endif + mask = POLLERR; + out: + unlock_kernel(); return mask; } static int -isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { + uint minor = MINOR(inode->i_rdev); isdn_ctrl c; int drvidx; + int chidx; int ret; int i; char *p; - /* save stack space */ - union { - char bname[20]; + char *s; + union iocpar { + char name[10]; + char bname[22]; isdn_ioctl_struct iocts; + isdn_net_ioctl_phone phone; + isdn_net_ioctl_cfg cfg; } iocpar; -#define iocts iocpar.iocts +#define name iocpar.name #define bname iocpar.bname +#define iocts iocpar.iocts +#define phone iocpar.phone +#define cfg iocpar.cfg + if (minor == ISDN_MINOR_STATUS) { + switch (cmd) { + case IIOCGETDVR: + return (TTY_DV + + (NET_DV << 8) + + (INF_DV << 16)); + case IIOCGETCPS: + if (arg) { + ulong *p = (ulong *) arg; + int i; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) + return ret; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + put_user(dev->ibytes[i], p++); + put_user(dev->obytes[i], p++); + } + return 0; + } else + return -EINVAL; + break; +#ifdef CONFIG_NETDEVICES + case IIOCNETGPN: + /* Get peer phone number of a connected + * isdn network interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); + } else + return -EINVAL; +#endif + default: + return -EINVAL; + } + } + if (!dev->drivers) + return -ENODEV; + if (minor <= ISDN_MINOR_BMAX) { + drvidx = isdn_minor2drv(minor); + if (drvidx < 0) + return -ENODEV; + chidx = isdn_minor2chan(minor); + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) + return -ENODEV; + return 0; + } + if (minor <= ISDN_MINOR_CTRLMAX) { /* * isdn net devices manage lots of configuration variables as linked lists. * Those lists must only be manipulated from user space. Some of the ioctl's @@ -1575,257 +1230,497 @@ isdn_ctrl_ioctl(struct inode *inode, str * manipulating the lists and ioctl's sleeping while accessing the lists * are serialized by means of a semaphore. */ - switch (cmd) { - case IIOCNETAIF: - case IIOCNETASL: - case IIOCNETDIF: - case IIOCNETSCF: - case IIOCNETGCF: - case IIOCNETANM: - case IIOCNETGNM: - case IIOCNETDNM: - case IIOCNETDIL: - case IIOCNETALN: - case IIOCNETDLN: - case IIOCNETHUP: - return isdn_net_ioctl(inode, file, cmd, arg); - case IIOCSETVER: - isdndev->net_verbose = arg; - printk(KERN_INFO "isdn: Verbose-Level is %d\n", isdndev->net_verbose); - return 0; - case IIOCSETGST: - if (arg) { - isdndev->global_flags |= ISDN_GLOBAL_STOPPED; - isdn_net_hangup_all(); - } else { - isdndev->global_flags &= ~ISDN_GLOBAL_STOPPED; - } - return 0; - case IIOCSETBRJ: - drvidx = -1; - if (arg) { - char *p; - if (copy_from_user((char *) &iocts, (char *) arg, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = isdn_drv_lookup(iocts.drvid); - } - } - if (drvidx == -1) - return -ENODEV; - if (iocts.arg) - drivers[drvidx]->flags |= DRV_FLAG_REJBUS; - else - drivers[drvidx]->flags &= ~DRV_FLAG_REJBUS; - return 0; - case IIOCSIGPRF: - isdndev->profd = current; - return 0; - break; - case IIOCGETPRF: - /* Get all Modem-Profiles */ - if (arg) { - char *p = (char *) arg; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_to_user(p, isdn_mdm.info[i].emu.profile, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_to_user(p, isdn_mdm.info[i].emu.pmsn, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - if (copy_to_user(p, isdn_mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - } - return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; - } else - return -EINVAL; - break; - case IIOCSETPRF: - /* Set all Modem-Profiles */ - if (arg) { - char *p = (char *) arg; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_from_user(isdn_mdm.info[i].emu.profile, p, - ISDN_MODEM_NUMREG)) + switch (cmd) { + case IIOCNETDWRSET: + printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); + return(-EINVAL); + case IIOCNETLCR: + printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); + return -ENODEV; +#ifdef CONFIG_NETDEVICES + case IIOCNETAIF: + /* Add a network-interface */ + if (arg) { + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + s = name; + } else { + s = NULL; + } + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + if ((s = isdn_net_new(s, NULL))) { + if (copy_to_user((char *) arg, s, strlen(s) + 1)){ + ret = -EFAULT; + } else { + ret = 0; + } + } else + ret = -ENODEV; + up(&dev->sem); + return ret; + case IIOCNETASL: + /* Add a slave to a network-interface */ + if (arg) { + if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) + return -EFAULT; + } else + return -EINVAL; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + if ((s = isdn_net_newslave(bname))) { + if (copy_to_user((char *) arg, s, strlen(s) + 1)){ + ret = -EFAULT; + } else { + ret = 0; + } + } else + ret = -ENODEV; + up(&dev->sem); + return ret; + case IIOCNETDIF: + /* Delete a network-interface */ + if (arg) { + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_rm(name); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETSCF: + /* Set configurable parameters of a network-interface */ + if (arg) { + if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) + return -EFAULT; + return isdn_net_setcfg(&cfg); + } else + return -EINVAL; + case IIOCNETGCF: + /* Get configurable parameters of a network-interface */ + if (arg) { + if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) + return -EFAULT; + if (!(ret = isdn_net_getcfg(&cfg))) { + if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) + return -EFAULT; + } + return ret; + } else + return -EINVAL; + case IIOCNETANM: + /* Add a phone-number to a network-interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_addphone(&phone); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETGNM: + /* Get list of phone-numbers of a network-interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_getphones(&phone, (char *) arg); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETDNM: + /* Delete a phone-number of a network-interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_delphone(&phone); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETDIL: + /* Force dialing of a network-interface */ + if (arg) { + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + return isdn_net_force_dial(name); + } else + return -EINVAL; +#ifdef CONFIG_ISDN_PPP + case IIOCNETALN: + if (!arg) + return -EINVAL; + if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_from_user(isdn_mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) + return isdn_ppp_dial_slave(name); + case IIOCNETDLN: + if (!arg) + return -EINVAL; + if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; - p += ISDN_LMSNLEN; - if (copy_from_user(isdn_mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) + return isdn_ppp_hangup_slave(name); +#endif + case IIOCNETHUP: + /* Force hangup of a network-interface */ + if (!arg) + return -EINVAL; + if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; - p += ISDN_MSNLEN; - } - return 0; - } else - return -EINVAL; - break; - case IIOCSETMAP: - case IIOCGETMAP: - /* Set/Get MSN->EAZ-Mapping for a driver */ - if (arg) { - - if (copy_from_user((char *) &iocts, - (char *) arg, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - drvidx = isdn_drv_lookup(iocts.drvid); - if (drvidx == -1) - return -ENODEV; - if (cmd == IIOCSETMAP) { - int loop = 1; - - p = (char *) iocts.arg; - i = 0; - while (loop) { - int j = 0; - - while (1) { - if ((ret = get_user(bname[j], p++))) - return ret; - switch (bname[j]) { - case '\0': - loop = 0; - /* Fall through */ - case ',': - bname[j] = '\0'; - strcpy(drivers[drvidx]->msn2eaz[i], bname); - j = ISDN_MSNLEN; - break; - default: - j++; - } - if (j >= ISDN_MSNLEN) - break; + return isdn_net_force_hangup(name); + break; +#endif /* CONFIG_NETDEVICES */ + case IIOCSETVER: + dev->net_verbose = arg; + printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); + return 0; + case IIOCSETGST: + if (arg) + dev->global_flags |= ISDN_GLOBAL_STOPPED; + else + dev->global_flags &= ~ISDN_GLOBAL_STOPPED; + printk(KERN_INFO "isdn: Global Mode %s\n", + (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); + return 0; + case IIOCSETBRJ: + drvidx = -1; + if (arg) { + int i; + char *p; + if (copy_from_user((char *) &iocts, (char *) arg, + sizeof(isdn_ioctl_struct))) + return -EFAULT; + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } } - if (++i > 9) - break; } - } else { - p = (char *) iocts.arg; - for (i = 0; i < 10; i++) { - sprintf(bname, "%s%s", - strlen(drivers[drvidx]->msn2eaz[i]) ? - drivers[drvidx]->msn2eaz[i] : "_", - (i < 9) ? "," : "\0"); - if (copy_to_user(p, bname, strlen(bname) + 1)) + if (drvidx == -1) + return -ENODEV; + if (iocts.arg) + dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; + else + dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; + return 0; + case IIOCSIGPRF: + dev->profd = current; + return 0; + break; + case IIOCGETPRF: + /* Get all Modem-Profiles */ + if (arg) { + char *p = (char *) arg; + int i; + + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) + * ISDN_MAX_CHANNELS))) + return ret; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (copy_to_user(p, dev->mdm.info[i].emu.profile, + ISDN_MODEM_NUMREG)) + return -EFAULT; + p += ISDN_MODEM_NUMREG; + if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) + return -EFAULT; + p += ISDN_MSNLEN; + if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; + } + return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; + } else + return -EINVAL; + break; + case IIOCSETPRF: + /* Set all Modem-Profiles */ + if (arg) { + char *p = (char *) arg; + int i; + + if ((ret = verify_area(VERIFY_READ, (void *) arg, + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) + * ISDN_MAX_CHANNELS))) + return ret; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (copy_from_user(dev->mdm.info[i].emu.profile, p, + ISDN_MODEM_NUMREG)) + return -EFAULT; + p += ISDN_MODEM_NUMREG; + if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; + if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) + return -EFAULT; + p += ISDN_MSNLEN; + } + return 0; + } else + return -EINVAL; + break; + case IIOCSETMAP: + case IIOCGETMAP: + /* Set/Get MSN->EAZ-Mapping for a driver */ + if (arg) { + + if (copy_from_user((char *) &iocts, + (char *) arg, + sizeof(isdn_ioctl_struct))) return -EFAULT; - p += strlen(bname); - } - } - return 0; - } else - return -EINVAL; - case IIOCDBGVAR: - if (arg) { - if (copy_to_user((char *) arg, (char *) &isdndev, sizeof(ulong))) - return -EFAULT; - return 0; - } else - return -EINVAL; - break; - default: - if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) - cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; - else - return -EINVAL; - if (arg) { - if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) - return -EFAULT; - drvidx = isdn_drv_lookup(iocts.drvid); - if (drvidx == -1) - return -ENODEV; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(isdn_ioctl_struct)))) - return ret; - c.driver = drvidx; - c.command = ISDN_CMD_IOCTL; - c.arg = cmd; - memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); - ret = __drv_command(drivers[drvidx], &c); - memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong)); - if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))) - return -EFAULT; - return ret; - } else - return -EINVAL; + if (strlen(iocts.drvid)) { + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } + } else + drvidx = 0; + if (drvidx == -1) + return -ENODEV; + if (cmd == IIOCSETMAP) { + int loop = 1; + + p = (char *) iocts.arg; + i = 0; + while (loop) { + int j = 0; + + while (1) { + if ((ret = verify_area(VERIFY_READ, p, 1))) + return ret; + get_user(bname[j], p++); + switch (bname[j]) { + case '\0': + loop = 0; + /* Fall through */ + case ',': + bname[j] = '\0'; + strcpy(dev->drv[drvidx]->msn2eaz[i], bname); + j = ISDN_MSNLEN; + break; + default: + j++; + } + if (j >= ISDN_MSNLEN) + break; + } + if (++i > 9) + break; + } + } else { + p = (char *) iocts.arg; + for (i = 0; i < 10; i++) { + sprintf(bname, "%s%s", + strlen(dev->drv[drvidx]->msn2eaz[i]) ? + dev->drv[drvidx]->msn2eaz[i] : "_", + (i < 9) ? "," : "\0"); + if (copy_to_user(p, bname, strlen(bname) + 1)) + return -EFAULT; + p += strlen(bname); + } + } + return 0; + } else + return -EINVAL; + case IIOCDBGVAR: + if (arg) { + if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))) + return -EFAULT; + return 0; + } else + return -EINVAL; + break; + default: + if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) + cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; + else + return -EINVAL; + if (arg) { + int i; + char *p; + if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) + return -EFAULT; + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } + } else + drvidx = 0; + if (drvidx == -1) + return -ENODEV; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(isdn_ioctl_struct)))) + return ret; + c.driver = drvidx; + c.command = ISDN_CMD_IOCTL; + c.arg = cmd; + memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); + ret = isdn_command(&c); + memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong)); + if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))) + return -EFAULT; + return ret; + } else + return -EINVAL; + } } -#undef iocts +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg)); +#endif + return -ENODEV; + +#undef name #undef bname +#undef iocts +#undef phone +#undef cfg } -static struct file_operations isdn_ctrl_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_ctrl_read, - .write = isdn_ctrl_write, - .poll = isdn_ctrl_poll, - .ioctl = isdn_ctrl_ioctl, - .open = isdn_ctrl_open, - .release = isdn_ctrl_release, -}; - - /* - * file_operations for major 45, /dev/isdn* - * stolen from drivers/char/misc.c + * Open the device code. */ - static int -isdn_open(struct inode * inode, struct file * file) +isdn_open(struct inode *ino, struct file *filep) { - int minor = iminor(inode); - int err = -ENODEV; - struct file_operations *old_fops, *new_fops = NULL; - - if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) - new_fops = fops_get(&isdn_ctrl_fops); + uint minor = MINOR(ino->i_rdev); + int drvidx; + int chidx; + int retval = -ENODEV; + + + if (minor == ISDN_MINOR_STATUS) { + infostruct *p; + + if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) { + p->next = (char *) dev->infochain; + p->private = (char *) &(filep->private_data); + dev->infochain = p; + /* At opening we allow a single update */ + filep->private_data = (char *) 1; + retval = 0; + goto out; + } else { + retval = -ENOMEM; + goto out; + } + } + if (!dev->channels) + goto out; + if (minor <= ISDN_MINOR_BMAX) { + printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); + drvidx = isdn_minor2drv(minor); + if (drvidx < 0) + goto out; + chidx = isdn_minor2chan(minor); + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) + goto out; + if (!(dev->drv[drvidx]->online & (1 << chidx))) + goto out; + isdn_lock_drivers(); + retval = 0; + goto out; + } + if (minor <= ISDN_MINOR_CTRLMAX) { + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) + goto out; + isdn_lock_drivers(); + retval = 0; + goto out; + } #ifdef CONFIG_ISDN_PPP - else if (minor >= ISDN_MINOR_PPP && minor <= ISDN_MINOR_PPPMAX) - new_fops = fops_get(&isdn_ppp_fops); + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); + if (retval == 0) + isdn_lock_drivers(); + goto out; + } #endif - else if (minor == ISDN_MINOR_STATUS) - new_fops = fops_get(&isdn_status_fops); + out: + return retval; +} - if (!new_fops) - goto out; +static int +isdn_close(struct inode *ino, struct file *filep) +{ + uint minor = MINOR(ino->i_rdev); - err = 0; - old_fops = file->f_op; - file->f_op = new_fops; - if (file->f_op->open) { - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); + lock_kernel(); + if (minor == ISDN_MINOR_STATUS) { + infostruct *p = dev->infochain; + infostruct *q = NULL; + + while (p) { + if (p->private == (char *) &(filep->private_data)) { + if (q) + q->next = p->next; + else + dev->infochain = (infostruct *) (p->next); + kfree(p); + goto out; + } + q = p; + p = (infostruct *) (p->next); } + printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); + goto out; + } + isdn_unlock_drivers(); + if (minor <= ISDN_MINOR_BMAX) + goto out; + if (minor <= ISDN_MINOR_CTRLMAX) { + if (dev->profd == current) + dev->profd = NULL; + goto out; } - fops_put(old_fops); - +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); +#endif + out: - return err; + unlock_kernel(); + return 0; } static struct file_operations isdn_fops = { - .owner = THIS_MODULE, - .open = isdn_open, + owner: THIS_MODULE, + llseek: no_llseek, + read: isdn_read, + write: isdn_write, + poll: isdn_poll, + ioctl: isdn_ioctl, + open: isdn_open, + release: isdn_close, }; char * isdn_map_eaz2msn(char *msn, int di) { - struct isdn_driver *this = drivers[di]; + isdn_driver_t *this = dev->drv[di]; int i; if (strlen(msn) == 1) { @@ -1841,118 +1736,281 @@ isdn_map_eaz2msn(char *msn, int di) * Find an unused ISDN-channel, whose feature-flags match the * given L2- and L3-protocols. */ -struct isdn_slot * -isdn_get_free_slot(int usage, int l2_proto, int l3_proto, - int pre_dev, int pre_chan, char *msn) -{ - struct isdn_driver *drv; - struct isdn_slot *slot; - int di, ch; - unsigned long flags; - unsigned long features; - - features = ((1 << l2_proto) | (0x10000 << l3_proto)); - - for (di = 0; di < ISDN_MAX_DRIVERS; di++) { - if (pre_dev >= 0 && pre_dev != di) - continue; - - drv = get_drv_by_nr(di); - if (!drv) - continue; - - if (drv->fi.state != ST_DRV_RUNNING) - goto put; - - if ((drv->features & features) != features) - goto put; - - spin_lock_irqsave(&drv->lock, flags); - for (ch = 0; ch < drv->channels; ch++) { - if (pre_chan >= 0 && pre_chan != ch) - continue; +#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038)) - slot = &drv->slots[ch]; +/* + * This function must be called with holding the dev->lock. + */ +int +isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev + ,int pre_chan, char *msn) +{ + int i; + ulong features; + ulong vfeatures; - if (!USG_NONE(slot->usage)) + features = ((1 << l2_proto) | (0x10000 << l3_proto)); + vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) & + ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038)); + /* If Layer-2 protocol is V.110, accept drivers with + * transparent feature even if these don't support V.110 + * because we can emulate this in linklevel. + */ + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (USG_NONE(dev->usage[i]) && + (dev->drvmap[i] != -1)) { + int d = dev->drvmap[i]; + if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && + ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) continue; - - if (slot->usage & ISDN_USAGE_DISABLED) + if (!strcmp(isdn_map_eaz2msn(msn, d), "-")) continue; + if (dev->usage[i] & ISDN_USAGE_DISABLED) + continue; /* usage not allowed */ + if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { + if (((dev->drv[d]->interface->features & features) == features) || + (((dev->drv[d]->interface->features & vfeatures) == vfeatures) && + (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) { + if ((pre_dev < 0) || (pre_chan < 0)) { + dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; + dev->usage[i] |= usage; + isdn_info_update(); + return i; + } else { + if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) { + dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; + dev->usage[i] |= usage; + isdn_info_update(); + return i; + } + } + } + } + } + return -1; +} - if (strcmp(isdn_map_eaz2msn(msn, drv->di), "-") == 0) - continue; +/* + * Set state of ISDN-channel to 'unused' + */ +void +isdn_free_channel(int di, int ch, int usage) +{ + int i; - goto found; - + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) && + (dev->drvmap[i] == di) && + (dev->chanmap[i] == ch)) { + dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE); + strcpy(dev->num[i], "???"); + dev->ibytes[i] = 0; + dev->obytes[i] = 0; +// 20.10.99 JIM, try to reinitialize v110 ! + dev->v110emu[i] = 0; + atomic_set(&(dev->v110use[i]), 0); + isdn_v110_close(dev->v110[i]); + dev->v110[i] = NULL; +// 20.10.99 JIM, try to reinitialize v110 ! + isdn_info_update(); + skb_queue_purge(&dev->drv[di]->rpqueue[ch]); } - spin_unlock_irqrestore(&drv->lock, flags); - - put: - put_drv(drv); - } - return NULL; +} - found: - slot->usage = usage; - spin_unlock_irqrestore(&drv->lock, flags); +/* + * Cancel Exclusive-Flag for ISDN-channel + */ +void +isdn_unexclusive_channel(int di, int ch) +{ + int i; - isdn_info_update(); - fsm_event(&slot->fi, EV_SLOT_BIND, NULL); - return slot; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if ((dev->drvmap[i] == di) && + (dev->chanmap[i] == ch)) { + dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE; + isdn_info_update(); + return; + } } /* - * Set state of ISDN-channel to 'unused' + * writebuf replacement for SKB_ABLE drivers */ -void -isdn_slot_free(struct isdn_slot *slot) +static int +isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len, + int user) { - fsm_event(&slot->fi, EV_SLOT_UNBIND, NULL); + int ret; + int hl = dev->drv[drvidx]->interface->hl_hdrlen; + struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC); + + if (!skb) + return 0; + skb_reserve(skb, hl); + if (user) + copy_from_user(skb_put(skb, len), buf, len); + else + memcpy(skb_put(skb, len), buf, len); + ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); + if (ret <= 0) + dev_kfree_skb(skb); + if (ret > 0) + dev->obytes[isdn_dc2minor(drvidx, chan)] += ret; + return ret; } /* * Return: length of data on success, -ERRcode on failure. */ int -isdn_slot_write(struct isdn_slot *slot, struct sk_buff *skb) +isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) { - return fsm_event(&slot->fi, EV_DATA_REQ, skb); + int ret; + struct sk_buff *nskb = NULL; + int v110_ret = skb->len; + int idx = isdn_dc2minor(drvidx, chan); + + if (dev->v110[idx]) { + atomic_inc(&dev->v110use[idx]); + nskb = isdn_v110_encode(dev->v110[idx], skb); + atomic_dec(&dev->v110use[idx]); + if (!nskb) + return 0; + v110_ret = *((int *)nskb->data); + skb_pull(nskb, sizeof(int)); + if (!nskb->len) { + dev_kfree_skb(nskb); + return v110_ret; + } + /* V.110 must always be acknowledged */ + ack = 1; + ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb); + } else { + int hl = dev->drv[drvidx]->interface->hl_hdrlen; + + if( skb_headroom(skb) < hl ){ + /* + * This should only occur when new HL driver with + * increased hl_hdrlen was loaded after netdevice + * was created and connected to the new driver. + * + * The V.110 branch (re-allocates on its own) does + * not need this + */ + struct sk_buff * skb_tmp; + + skb_tmp = skb_realloc_headroom(skb, hl); + printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed"); + if (!skb_tmp) return -ENOMEM; /* 0 better? */ + ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp); + if( ret > 0 ){ + dev_kfree_skb(skb); + } else { + dev_kfree_skb(skb_tmp); + } + } else { + ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb); + } + } + if (ret > 0) { + dev->obytes[idx] += ret; + if (dev->v110[idx]) { + atomic_inc(&dev->v110use[idx]); + dev->v110[idx]->skbuser++; + atomic_dec(&dev->v110use[idx]); + /* For V.110 return unencoded data length */ + ret = v110_ret; + /* if the complete frame was send we free the skb; + if not upper function will requeue the skb */ + if (ret == skb->len) + dev_kfree_skb(skb); + } + } else + if (dev->v110[idx]) + dev_kfree_skb(nskb); + return ret; } -static int -isdn_add_channels(struct isdn_driver *drv, int n) +int +isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) { - struct isdn_slot *slot; - int ch; + int j, k, m; - if (n < 1) - return 0; + init_waitqueue_head(&d->st_waitq); + if (d->flags & DRV_FLAG_RUNNING) + return -1; + if (n < 1) return 0; - if (isdndev->channels + n > ISDN_MAX_CHANNELS) { + m = (adding) ? d->channels + n : n; + + if (dev->channels + n > ISDN_MAX_CHANNELS) { printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", ISDN_MAX_CHANNELS); - return -EBUSY; + return -1; } - isdndev->channels += n; - drv->slots = kmalloc(sizeof(struct isdn_slot) * n, GFP_ATOMIC); - if (!drv->slots) - return -ENOMEM; - memset(drv->slots, 0, sizeof(struct isdn_slot) * n); - for (ch = 0; ch < n; ch++) { - slot = drv->slots + ch; - - slot->ch = ch; - slot->di = drv->di; - slot->drv = drv; - strcpy(slot->num, "???"); - slot->fi.fsm = &slot_fsm; - slot->fi.state = ST_SLOT_NULL; - slot->fi.debug = 1; - slot->fi.userdata = slot; - slot->fi.printdebug = slot_debug; + + if ((adding) && (d->rcverr)) + kfree(d->rcverr); + if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_ATOMIC))) { + printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); + return -1; + } + memset((char *) d->rcverr, 0, sizeof(int) * m); + + if ((adding) && (d->rcvcount)) + kfree(d->rcvcount); + if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) { + printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); + if (!adding) kfree(d->rcverr); + return -1; + } + memset((char *) d->rcvcount, 0, sizeof(int) * m); + + if ((adding) && (d->rpqueue)) { + for (j = 0; j < d->channels; j++) + skb_queue_purge(&d->rpqueue[j]); + kfree(d->rpqueue); + } + if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_ATOMIC))) { + printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); + if (!adding) { + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; } - drv->channels = n; + for (j = 0; j < m; j++) { + skb_queue_head_init(&d->rpqueue[j]); + } + + if ((adding) && (d->rcv_waitq)) + kfree(d->rcv_waitq); + d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_ATOMIC); + if (!d->rcv_waitq) { + printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); + if (!adding) { + kfree(d->rpqueue); + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; + } + d->snd_waitq = d->rcv_waitq + m; + for (j = 0; j < m; j++) { + init_waitqueue_head(&d->rcv_waitq[j]); + init_waitqueue_head(&d->snd_waitq[j]); + } + + dev->channels += n; + for (j = d->channels; j < m; j++) + for (k = 0; k < ISDN_MAX_CHANNELS; k++) + if (dev->chanmap[k] < 0) { + dev->chanmap[k] = j; + dev->drvmap[k] = drvidx; + break; + } + d->channels = m; return 0; } @@ -1960,63 +2018,68 @@ isdn_add_channels(struct isdn_driver *dr * Low-level-driver registration */ -#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE) +static void +set_global_features(void) +{ + int drvidx; + + dev->global_features = 0; + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { + if (!dev->drv[drvidx]) + continue; + if (dev->drv[drvidx]->interface) + dev->global_features |= dev->drv[drvidx]->interface->features; + } +} + +#ifdef CONFIG_ISDN_DIVERSION -/* - * map_drvname - */ static char *map_drvname(int di) { - if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) - return(NULL); - return(isdndev->drvid[di]); /* driver name */ -} + if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) + return(NULL); + return(dev->drvid[di]); /* driver name */ +} /* map_drvname */ -/* - * map_namedrv - */ static int map_namedrv(char *id) -{ - int i; +{ int i; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (!strcmp(dev->drvid[i],id)) - return(i); - } - return(-1); -} + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + { if (!strcmp(dev->drvid[i],id)) + return(i); + } + return(-1); +} /* map_namedrv */ -/* - * DIVERT_REG_NAME - */ int DIVERT_REG_NAME(isdn_divert_if *i_div) { - if (i_div->if_magic != DIVERT_IF_MAGIC) - return(DIVERT_VER_ERR); - switch (i_div->cmd) { - case DIVERT_CMD_REL: - if (divert_if != i_div) - return(DIVERT_REL_ERR); - divert_if = NULL; /* free interface */ - MOD_DEC_USE_COUNT; - return(DIVERT_NO_ERR); - case DIVERT_CMD_REG: - if (divert_if) - return(DIVERT_REG_ERR); - i_div->ll_cmd = isdn_command; /* set command function */ - i_div->drv_to_name = map_drvname; - i_div->name_to_drv = map_namedrv; - MOD_INC_USE_COUNT; - divert_if = i_div; /* remember interface */ - return(DIVERT_NO_ERR); - default: - return(DIVERT_CMD_ERR); - } -} + if (i_div->if_magic != DIVERT_IF_MAGIC) + return(DIVERT_VER_ERR); + switch (i_div->cmd) + { + case DIVERT_CMD_REL: + if (divert_if != i_div) + return(DIVERT_REL_ERR); + divert_if = NULL; /* free interface */ + return(DIVERT_NO_ERR); + + case DIVERT_CMD_REG: + if (divert_if) + return(DIVERT_REG_ERR); + i_div->ll_cmd = isdn_command; /* set command function */ + i_div->drv_to_name = map_drvname; + i_div->name_to_drv = map_namedrv; + divert_if = i_div; /* remember interface */ + return(DIVERT_NO_ERR); + + default: + return(DIVERT_CMD_ERR); + } +} /* DIVERT_REG_NAME */ EXPORT_SYMBOL(DIVERT_REG_NAME); -#endif +#endif /* CONFIG_ISDN_DIVERSION */ EXPORT_SYMBOL(register_isdn); @@ -2026,159 +2089,80 @@ EXPORT_SYMBOL(isdn_ppp_unregister_compre #endif int -isdn_slot_maxbufsize(struct isdn_slot *slot) -{ - return slot->drv->maxbufsize; -} - -int -isdn_slot_hdrlen(struct isdn_slot *slot) -{ - return slot->drv->interface->hl_hdrlen; -} - -char * -isdn_slot_map_eaz2msn(struct isdn_slot *slot, char *msn) -{ - return isdn_map_eaz2msn(msn, slot->di); -} - -int -isdn_slot_command(struct isdn_slot *slot, int cmd, isdn_ctrl *ctrl) +register_isdn(isdn_if * i) { - ctrl->command = cmd; - ctrl->driver = slot->di; + isdn_driver_t *d; + int j; + ulong flags; + int drvidx; - switch (cmd) { - case ISDN_CMD_SETL2: - case ISDN_CMD_SETL3: - case ISDN_CMD_PROT_IO: - ctrl->arg &= ~0xff; ctrl->arg |= slot->ch; - break; - case ISDN_CMD_DIAL: - if (isdndev->global_flags & ISDN_GLOBAL_STOPPED) - return -EBUSY; - - /* fall through */ - default: - ctrl->arg = slot->ch; - break; - } - switch (cmd) { - case ISDN_CMD_CLREAZ: - return fsm_event(&slot->fi, EV_CMD_CLREAZ, ctrl); - case ISDN_CMD_SETEAZ: - return fsm_event(&slot->fi, EV_CMD_SETEAZ, ctrl); - case ISDN_CMD_SETL2: - return fsm_event(&slot->fi, EV_CMD_SETL2, ctrl); - case ISDN_CMD_SETL3: - return fsm_event(&slot->fi, EV_CMD_SETL3, ctrl); - case ISDN_CMD_DIAL: - return fsm_event(&slot->fi, EV_CMD_DIAL, ctrl); - case ISDN_CMD_ACCEPTD: - return fsm_event(&slot->fi, EV_CMD_ACCEPTD, ctrl); - case ISDN_CMD_ACCEPTB: - return fsm_event(&slot->fi, EV_CMD_ACCEPTB, ctrl); - case ISDN_CMD_HANGUP: - return fsm_event(&slot->fi, EV_CMD_HANGUP, ctrl); + if (dev->drivers >= ISDN_MAX_DRIVERS) { + printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", + ISDN_MAX_DRIVERS); + return 0; } - HERE; - return -1; -} - -int -isdn_slot_dial(struct isdn_slot *slot, struct dial_info *dial) -{ - isdn_ctrl cmd; - int retval; - char *msn = isdn_slot_map_eaz2msn(slot, dial->msn); - - /* check for DOV */ - if (dial->si1 == 7 && tolower(dial->phone[0]) == 'v') { /* DOV call */ - dial->si1 = 1; - dial->phone++; /* skip v/V */ + if (!i->writebuf_skb) { + printk(KERN_WARNING "register_isdn: No write routine given.\n"); + return 0; } + if (!(d = kmalloc(sizeof(isdn_driver_t), GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); + return 0; + } + memset((char *) d, 0, sizeof(isdn_driver_t)); - strcpy(slot->num, dial->phone); - slot->usage |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - - retval = isdn_slot_command(slot, ISDN_CMD_CLREAZ, &cmd); - if (retval) - return retval; - - strcpy(cmd.parm.num, msn); - retval = isdn_slot_command(slot, ISDN_CMD_SETEAZ, &cmd); - - cmd.arg = dial->l2_proto << 8; - cmd.parm.fax = dial->fax; - retval = isdn_slot_command(slot, ISDN_CMD_SETL2, &cmd); - if (retval) - return retval; - - cmd.arg = dial->l3_proto << 8; - retval = isdn_slot_command(slot, ISDN_CMD_SETL3, &cmd); - if (retval) - return retval; - - cmd.parm.setup.si1 = dial->si1; - cmd.parm.setup.si2 = dial->si2; - strcpy(cmd.parm.setup.eazmsn, msn); - strcpy(cmd.parm.setup.phone, dial->phone); - - printk(KERN_INFO "ISDN: Dialing %s -> %s (SI %d/%d) (B %d/%d)\n", - cmd.parm.setup.eazmsn, cmd.parm.setup.phone, - cmd.parm.setup.si1, cmd.parm.setup.si2, - dial->l2_proto, dial->l3_proto); - - return isdn_slot_command(slot, ISDN_CMD_DIAL, &cmd); -} - -int -isdn_hard_header_len(void) -{ - int drvidx; - int max = 0; - - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { - if (drivers[drvidx] && - max < drivers[drvidx]->interface->hl_hdrlen) { - max = drivers[drvidx]->interface->hl_hdrlen; - } + d->maxbufsize = i->maxbufsize; + d->pktcount = 0; + d->stavail = 0; + d->flags = DRV_FLAG_LOADED; + d->online = 0; + d->interface = i; + d->channels = 0; + spin_lock_irqsave(&dev->lock, flags); + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) + if (!dev->drv[drvidx]) + break; + if (isdn_add_channels(d, drvidx, i->channels, 0)) { + spin_unlock_irqrestore(&dev->lock, flags); + kfree(d); + return 0; } - return max; + i->channels = drvidx; + i->rcvcallb_skb = isdn_receive_skb_callback; + i->statcallb = isdn_status_callback; + if (!strlen(i->id)) + sprintf(i->id, "line%d", drvidx); + for (j = 0; j < drvidx; j++) + if (!strcmp(i->id, dev->drvid[j])) + sprintf(i->id, "line%d", drvidx); + dev->drv[drvidx] = d; + strcpy(dev->drvid[drvidx], i->id); + isdn_info_update(); + dev->drivers++; + set_global_features(); + spin_unlock_irqrestore(&dev->lock, flags); + return 1; } -static void isdn_init_devfs(void) -{ - devfs_mk_dir("isdn"); +/* + ***************************************************************************** + * And now the modules code. + ***************************************************************************** + */ -#ifdef CONFIG_ISDN_PPP +static char * +isdn_getrev(const char *revision) { - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_PPP + i), - 0600 | S_IFCHR, "isdn/ippp%d", i); -} -#endif - - devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_STATUS), - 0600 | S_IFCHR, "isdn/isdninfo"); - devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_CTRL), - 0600 | S_IFCHR, "isdn/isdnctrl"); -} + char *rev; + char *p; -static void isdn_cleanup_devfs(void) -{ -#ifdef CONFIG_ISDN_PPP - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - devfs_remove("isdn/ippp%d", i); -#endif - devfs_remove("isdn/isdninfo"); - devfs_remove("isdn/isdnctrl"); - devfs_remove("isdn"); + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; } /* @@ -2186,64 +2170,72 @@ static void isdn_cleanup_devfs(void) */ static int __init isdn_init(void) { - int retval; - - retval = fsm_new(&slot_fsm); - if (retval) - goto err; - - retval = fsm_new(&drv_fsm); - if (retval) - goto err_slot_fsm; - - isdndev = vmalloc(sizeof(*isdndev)); - if (!isdndev) { - retval = -ENOMEM; - goto err_drv_fsm; - } - memset(isdndev, 0, sizeof(*isdndev)); - init_MUTEX(&isdndev->sem); - init_waitqueue_head(&isdndev->info_waitq); + int i; + char tmprev[50]; - retval = register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops); - if (retval) { + if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) { + printk(KERN_WARNING "isdn: Could not allocate device-struct.\n"); + return -EIO; + } + memset((char *) dev, 0, sizeof(isdn_dev)); + init_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; + spin_lock_init(&dev->lock); + spin_lock_init(&dev->timerlock); +#ifdef MODULE + dev->owner = THIS_MODULE; +#endif + init_MUTEX(&dev->sem); + init_waitqueue_head(&dev->info_waitq); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + dev->drvmap[i] = -1; + dev->chanmap[i] = -1; + dev->m_idx[i] = -1; + strcpy(dev->num[i], "???"); + init_waitqueue_head(&dev->mdm.info[i].open_wait); + init_waitqueue_head(&dev->mdm.info[i].close_wait); + } + if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { printk(KERN_WARNING "isdn: Could not register control devices\n"); - goto err_vfree; + vfree(dev); + return -EIO; } - isdn_init_devfs(); - retval = isdn_tty_init(); - if (retval < 0) { + if ((isdn_tty_modem_init()) < 0) { printk(KERN_WARNING "isdn: Could not register tty devices\n"); - goto err_cleanup_devfs; + vfree(dev); + unregister_chrdev(ISDN_MAJOR, "isdn"); + return -EIO; } #ifdef CONFIG_ISDN_PPP - retval = isdn_ppp_init(); - if (retval < 0) { + if (isdn_ppp_init() < 0) { printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n"); - goto err_tty_modem; + isdn_tty_exit(); + unregister_chrdev(ISDN_MAJOR, "isdn"); + vfree(dev); + return -EIO; } #endif /* CONFIG_ISDN_PPP */ - isdn_net_lib_init(); - printk(KERN_NOTICE "ISDN subsystem initialized\n"); - isdn_info_update(); - return 0; + strcpy(tmprev, isdn_revision); + printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev)); + strcpy(tmprev, isdn_tty_revision); + printk("%s/", isdn_getrev(tmprev)); + strcpy(tmprev, isdn_net_revision); + printk("%s/", isdn_getrev(tmprev)); + strcpy(tmprev, isdn_ppp_revision); + printk("%s/", isdn_getrev(tmprev)); + strcpy(tmprev, isdn_audio_revision); + printk("%s/", isdn_getrev(tmprev)); + strcpy(tmprev, isdn_v110_revision); + printk("%s", isdn_getrev(tmprev)); -#ifdef CONFIG_ISDN_PPP - err_tty_modem: - isdn_tty_exit(); +#ifdef MODULE + printk(" loaded\n"); +#else + printk("\n"); #endif - err_cleanup_devfs: - isdn_cleanup_devfs(); - unregister_chrdev(ISDN_MAJOR, "isdn"); - err_vfree: - vfree(isdndev); - err_drv_fsm: - fsm_free(&drv_fsm); - err_slot_fsm: - fsm_free(&slot_fsm); - err: - return retval; + isdn_info_update(); + return 0; } /* @@ -2254,141 +2246,17 @@ static void __exit isdn_exit(void) #ifdef CONFIG_ISDN_PPP isdn_ppp_cleanup(); #endif - isdn_net_lib_exit(); - + if (isdn_net_rmall() < 0) { + printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n"); + return; + } isdn_tty_exit(); unregister_chrdev(ISDN_MAJOR, "isdn"); - isdn_cleanup_devfs(); - vfree(isdndev); - fsm_free(&drv_fsm); - fsm_free(&slot_fsm); + del_timer(&dev->timer); + /* call vfree with interrupts enabled, else it will hang */ + vfree(dev); + printk(KERN_NOTICE "ISDN-subsystem unloaded\n"); } module_init(isdn_init); module_exit(isdn_exit); - -static void -isdn_v110_add_features(struct isdn_driver *drv) -{ - unsigned long features = drv->features >> ISDN_FEATURE_L2_SHIFT; - - if (features & ISDN_FEATURE_L2_TRANS) - drv->features |= (ISDN_FEATURE_L2_V11096| - ISDN_FEATURE_L2_V11019| - ISDN_FEATURE_L2_V11038) << - ISDN_FEATURE_L2_SHIFT; -} - -static void -__isdn_v110_open(struct isdn_slot *slot) -{ - if (!slot->iv110.v110emu) - return; - - isdn_v110_open(slot, &slot->iv110); -} - -static void -__isdn_v110_close(struct isdn_slot *slot) -{ - if (!slot->iv110.v110emu) - return; - - isdn_v110_close(slot, &slot->iv110); -} - -static void -__isdn_v110_bsent(struct isdn_slot *slot, int pr, isdn_ctrl *c) -{ - if (!slot->iv110.v110emu) { - do_event_cb(slot, pr, c); - return; - } - isdn_v110_bsent(slot, &slot->iv110); -} - -/* - * Intercept command from Linklevel to Lowlevel. - * If layer 2 protocol is V.110 and this is not supported by current - * lowlevel-driver, use driver's transparent mode and handle V.110 in - * linklevel instead. - */ -static void -isdn_v110_setl2(struct isdn_slot *slot, isdn_ctrl *cmd) -{ - struct isdn_driver *drv = slot->drv; - - unsigned long l2prot = (cmd->arg >> 8) & 255; - unsigned long l2_feature = 1 << l2prot; - unsigned long features = drv->interface->features >> - ISDN_FEATURE_L2_SHIFT; - - switch (l2prot) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - /* If V.110 requested, but not supported by - * HL-driver, set emulator-flag and change - * Layer-2 to transparent - */ - if (!(features & l2_feature)) { - slot->iv110.v110emu = l2prot; - cmd->arg = (cmd->arg & 255) | - (ISDN_PROTO_L2_TRANS << 8); - } else - slot->iv110.v110emu = 0; - } -} - -static int -isdn_v110_data_ind(struct isdn_slot *slot, struct sk_buff *skb) -{ - if (!slot->iv110.v110emu) - goto recv; - - skb = isdn_v110_decode(slot->iv110.v110, skb); - if (!skb) - return 0; - -recv: - if (slot->event_cb) - slot->event_cb(slot, EV_DATA_IND, skb); - return 0; -} - -static int -isdn_v110_data_req(struct isdn_slot *slot, struct sk_buff *skb) -{ - int retval, v110_ret; - struct sk_buff *nskb = NULL; - - if (!slot->iv110.v110emu) - return isdn_writebuf_skb(slot, skb); - - atomic_inc(&slot->iv110.v110use); - nskb = isdn_v110_encode(slot->iv110.v110, skb); - atomic_dec(&slot->iv110.v110use); - if (!nskb) - return -ENOMEM; - - v110_ret = *(int *)nskb->data; - skb_pull(nskb, sizeof(int)); - if (!nskb->len) { - dev_kfree_skb(nskb); - return v110_ret; - } - - retval = isdn_writebuf_skb(slot, nskb); - if (retval <= 0) { - dev_kfree_skb(nskb); - return retval; - } - dev_kfree_skb(skb); - - atomic_inc(&slot->iv110.v110use); - slot->iv110.v110->skbuser++; - atomic_dec(&slot->iv110.v110use); - - /* For V.110 return unencoded data length */ - return v110_ret; -} diff -puN drivers/isdn/i4l/isdn_common.h~i4l drivers/isdn/i4l/isdn_common.h --- 25/drivers/isdn/i4l/isdn_common.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_common.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,7 @@ -/* Linux ISDN subsystem, common used functions and debugging-switches +/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * header for Linux ISDN subsystem + * common used functions and debugging-switches (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg @@ -9,9 +12,6 @@ * */ -#include -#include "isdn_v110.h" - #undef ISDN_DEBUG_MODEM_OPEN #undef ISDN_DEBUG_MODEM_IOCTL #undef ISDN_DEBUG_MODEM_WAITSENT @@ -21,129 +21,27 @@ #undef ISDN_DEBUG_MODEM_VOICE #undef ISDN_DEBUG_AT #undef ISDN_DEBUG_NET_DUMP -#define ISDN_DEBUG_NET_DIAL -#define ISDN_DEBUG_NET_ICALL -#define ISDN_DEBUG_STATCALLB -#define ISDN_DEBUG_COMMAND - -#ifdef ISDN_DEBUG_NET_DIAL -#define dbg_net_dial(arg...) printk(KERN_DEBUG arg) -#else -#define dbg_net_dial(arg...) do {} while (0) -#endif - -#ifdef ISDN_DEBUG_NET_ICALL -#define dbg_net_icall(arg...) printk(KERN_DEBUG arg) -#else -#define dbg_net_icall(arg...) do {} while (0) -#endif - -#ifdef ISDN_DEBUG_STATCALLB -#define dbg_statcallb(arg...) printk(KERN_DEBUG arg) -#else -#define dbg_statcallb(arg...) do {} while (0) -#endif - -#define isdn_BUG() \ -do { printk(KERN_WARNING "ISDN BUG at %s:%d\n", __FILE__, __LINE__); \ -} while(0) - -#define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__) - -extern struct list_head isdn_net_devs; +#undef ISDN_DEBUG_NET_DIAL +#undef ISDN_DEBUG_NET_ICALL /* Prototypes */ -extern void isdn_MOD_INC_USE_COUNT(void); -extern void isdn_MOD_DEC_USE_COUNT(void); extern void isdn_lock_drivers(void); extern void isdn_unlock_drivers(void); +extern void isdn_free_channel(int di, int ch, int usage); +extern void isdn_all_eaz(int di, int ch); +extern int isdn_command(isdn_ctrl *); +extern int isdn_dc2minor(int di, int ch); extern void isdn_info_update(void); extern char *isdn_map_eaz2msn(char *msn, int di); -extern int isdn_getnum(char **); -extern int isdn_msncmp( const char *, const char *); +extern void isdn_timer_ctrl(int tf, int onoff); +extern void isdn_unexclusive_channel(int di, int ch); +extern int isdn_getnum(char **); +extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); +extern int isdn_get_free_channel(int, int, int, int, int, char *); +extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); +extern int register_isdn(isdn_if * i); +extern int isdn_msncmp( const char *, const char *); +extern int isdn_add_channels(isdn_driver_t *, int, int, int); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); -#else -static inline void isdn_dumppkt(char *s, u_char *d, int l, int m) { } #endif - -struct isdn_slot { - int di; /* driver index */ - struct isdn_driver *drv; /* driver */ - int ch; /* channel index (per driver) */ - int usage; /* how is it used */ - char num[ISDN_MSNLEN]; /* the current phone number */ - unsigned long ibytes; /* Statistics incoming bytes */ - unsigned long obytes; /* Statistics outgoing bytes */ - struct isdn_v110 iv110; /* For V.110 */ - void *priv; /* pointer to isdn_net_dev */ - int (*event_cb)(struct isdn_slot *, int pr, void *arg); - struct fsm_inst fi; -}; - -struct dial_info { - int l2_proto; - int l3_proto; - struct T30_s *fax; - unsigned char si1; - unsigned char si2; - unsigned char *msn; - unsigned char *phone; -}; - -struct isdn_slot *isdn_get_free_slot(int, int, int, int, int, char *); -void isdn_slot_free(struct isdn_slot *); -int isdn_slot_command(struct isdn_slot *, int cmd, isdn_ctrl *); -int isdn_slot_dial(struct isdn_slot *, struct dial_info *dial); -char *isdn_slot_map_eaz2msn(struct isdn_slot *, char *msn); -int isdn_slot_write(struct isdn_slot *, struct sk_buff *); -int isdn_slot_hdrlen(struct isdn_slot *); -int isdn_slot_maxbufsize(struct isdn_slot *); -int isdn_hard_header_len(void); - -int isdn_drv_lookup(char *drvid); -char *isdn_drv_drvid(int di); - -enum { - ST_SLOT_NULL, - ST_SLOT_BOUND, - ST_SLOT_IN, - ST_SLOT_WAIT_DCONN, - ST_SLOT_DCONN, - ST_SLOT_WAIT_BCONN, - ST_SLOT_ACTIVE, - ST_SLOT_WAIT_BHUP, - ST_SLOT_WAIT_DHUP, -}; - -enum { - EV_DRV_REGISTER, - EV_STAT_RUN, - EV_STAT_STOP, - EV_STAT_UNLOAD, - EV_STAT_STAVAIL, - EV_STAT_ADDCH, - EV_STAT_ICALL, - EV_STAT_DCONN, - EV_STAT_BCONN, - EV_STAT_BHUP, - EV_STAT_DHUP, - EV_STAT_BSENT, - EV_STAT_CINF, - EV_STAT_CAUSE, - EV_STAT_DISPLAY, - EV_STAT_FAXIND, - EV_STAT_AUDIO, - EV_CMD_CLREAZ, - EV_CMD_SETEAZ, - EV_CMD_SETL2, - EV_CMD_SETL3, - EV_CMD_DIAL, - EV_CMD_ACCEPTD, - EV_CMD_ACCEPTB, - EV_CMD_HANGUP, - EV_DATA_REQ, - EV_DATA_IND, - EV_SLOT_BIND, - EV_SLOT_UNBIND, -}; diff -puN drivers/isdn/i4l/isdn_concap.c~i4l drivers/isdn/i4l/isdn_concap.c --- 25/drivers/isdn/i4l/isdn_concap.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_concap.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,12 +1,16 @@ -/* Linux ISDN subsystem, protocol encapsulation +/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, protocol encapsulation * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ /* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. + * */ @@ -15,7 +19,7 @@ #include "isdn_net.h" #include #include "isdn_concap.h" -#include + /* The following set of device service operations are for encapsulation protocols that require for reliable datalink semantics. That means: @@ -35,8 +39,7 @@ */ -static int -isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) +int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) { struct net_device *ndev = concap -> net_dev; isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev; @@ -55,8 +58,7 @@ isdn_concap_dl_data_req(struct concap_pr } -static int -isdn_concap_dl_connect_req(struct concap_proto *concap) +int isdn_concap_dl_connect_req(struct concap_proto *concap) { struct net_device *ndev = concap -> net_dev; isdn_net_local *lp = (isdn_net_local *) ndev->priv; @@ -69,8 +71,7 @@ isdn_concap_dl_connect_req(struct concap return ret; } -static int -isdn_concap_dl_disconn_req(struct concap_proto *concap) +int isdn_concap_dl_disconn_req(struct concap_proto *concap) { IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name); @@ -97,8 +98,7 @@ struct concap_device_ops isdn_concap_dem this sourcefile does not need to include any protocol specific header files. For now: */ -struct concap_proto * -isdn_concap_new( int encap ) +struct concap_proto * isdn_concap_new( int encap ) { switch ( encap ) { case ISDN_NET_ENCAP_X25IFACE: @@ -106,146 +106,3 @@ isdn_concap_new( int encap ) } return NULL; } - -static int -isdn_x25_open(isdn_net_local *lp) -{ - struct net_device * dev = & lp -> netdev -> dev; - struct concap_proto * cprot = lp -> netdev -> ind_priv; - struct concap_proto * dops = lp -> inl_priv; - unsigned long flags; - - save_flags(flags); - cli(); /* Avoid glitch on writes to CMD regs */ - if( cprot -> pops && dops ) - cprot -> pops -> restart ( cprot, dev, dops ); - restore_flags(flags); - return 0; -} - -static void -isdn_x25_close(isdn_net_local *lp) -{ - struct concap_proto * cprot = lp -> netdev -> ind_priv; - - if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); -} - -static void -isdn_x25_connected(isdn_net_local *lp) -{ - struct concap_proto *cprot = lp -> netdev -> ind_priv; - struct concap_proto_ops *pops = cprot ? cprot -> pops : 0; - - /* try if there are generic concap receiver routines */ - if( pops ) - if( pops->connect_ind) - pops->connect_ind(cprot); - - isdn_net_device_wake_queue(lp); -} - -static void -isdn_x25_disconnected(isdn_net_local *lp) -{ - struct concap_proto *cprot = lp -> netdev -> ind_priv; - struct concap_proto_ops *pops = cprot ? cprot -> pops : 0; - - /* try if there are generic encap protocol - receiver routines and signal the closure of - the link */ - if( pops && pops -> disconn_ind ) - pops -> disconn_ind(cprot); -} - -static int -isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ -/* At this point hard_start_xmit() passes control to the encapsulation - protocol (if present). - For X.25 auto-dialing is completly bypassed because: - - It does not conform with the semantics of a reliable datalink - service as needed by X.25 PLP. - - I don't want that the interface starts dialing when the network layer - sends a message which requests to disconnect the lapb link (or if it - sends any other message not resulting in data transmission). - Instead, dialing will be initiated by the encapsulation protocol entity - when a dl_establish request is received from the upper layer. -*/ - isdn_net_local *lp = (isdn_net_local *) dev->priv; - struct concap_proto * cprot = lp -> netdev -> ind_priv; - int ret = cprot -> pops -> encap_and_xmit ( cprot , skb); - - if (ret) - netif_stop_queue(dev); - - return ret; -} - -static void -isdn_x25_receive(isdn_net_dev *p, isdn_net_local *olp, struct sk_buff *skb) -{ - isdn_net_local *lp = &p->local; - struct concap_proto *cprot = lp -> netdev -> ind_priv; - - /* try if there are generic sync_device receiver routines */ - if(cprot) - if(cprot -> pops) - if( cprot -> pops -> data_ind) { - cprot -> pops -> data_ind(cprot,skb); - return; - } -} - -static void -isdn_x25_init(struct net_device *dev) -{ - unsigned long flags; - - isdn_net_local *lp = dev->priv; - - /* ... , prepare for configuration of new one ... */ - switch ( lp->p_encap ){ - case ISDN_NET_ENCAP_X25IFACE: - lp -> inl_priv = &isdn_concap_reliable_dl_dops; - } - /* ... and allocate new one ... */ - p -> cprot = isdn_concap_new( cfg -> p_encap ); - /* p -> cprot == NULL now if p_encap is not supported - by means of the concap_proto mechanism */ - if (!p->cprot) - return -EINVAL; - - return 0; -} - -static void -isdn_x25_cleanup(isdn_net_dev *p) -{ - isdn_net_local *lp = &p->local; - struct concap_proto * cprot = p -> cprot; - unsigned long flags; - - /* delete old encapsulation protocol if present ... */ - save_flags(flags); - cli(); /* avoid races with incoming events trying to - call cprot->pops methods */ - if( cprot && cprot -> pops ) - cprot -> pops -> proto_del ( cprot ); - p -> cprot = NULL; - lp -> inl_priv = NULL; - restore_flags(flags); -} - -struct isdn_netif_ops isdn_x25_ops = { - .hard_start_xmit = isdn_x25_start_xmit, - .flags = IFF_NOARP | IFF_POINTOPOINT, - .type = ARPHRD_X25, - .receive = isdn_x25_receive, - .connected = isdn_x25_connected, - .disconnected = isdn_x25_disconnected, - .init = isdn_x25_init, - .cleanup = isdn_x25_cleanup, - .open = isdn_x25_open, - .close = isdn_x25_close, -}; diff -puN drivers/isdn/i4l/isdn_concap.h~i4l drivers/isdn/i4l/isdn_concap.h --- 25/drivers/isdn/i4l/isdn_concap.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_concap.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,12 +1,14 @@ -/* Linux ISDN subsystem, protocol encapsulation +/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, protocol encapsulation * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ extern struct concap_device_ops isdn_concap_reliable_dl_dops; extern struct concap_device_ops isdn_concap_demand_dial_dops; +extern struct concap_proto * isdn_concap_new( int ); -struct concap_proto *isdn_concap_new(int); -extern struct isdn_netif_ops isdn_x25_ops; diff -puN -L drivers/isdn/i4l/isdn_fsm.c drivers/isdn/i4l/isdn_fsm.c~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_fsm.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,166 +0,0 @@ -/* Linux ISDN subsystem, finite state machine - * - * Author Karsten Keil - * Copyright by Karsten Keil - * 2001-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Jan den Ouden - * Fritz Elfert - */ - -#include -#include -#include -#include -#include -#include - -int -fsm_new(struct fsm *fsm) -{ - int i; - int size = sizeof(fsm_fn) * fsm->st_cnt * fsm->ev_cnt; - - fsm->jumpmatrix = kmalloc(size, GFP_KERNEL); - if (!fsm->jumpmatrix) - return -ENOMEM; - - memset(fsm->jumpmatrix, 0, size); - - for (i = 0; i < fsm->fn_cnt; i++) { - if (fsm->fn_tbl[i].st >= fsm->st_cnt || - fsm->fn_tbl[i].ev >= fsm->ev_cnt) { - printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n", i, - fsm->fn_tbl[i].st, fsm->st_cnt, - fsm->fn_tbl[i].ev, fsm->ev_cnt); - continue; - } - fsm->jumpmatrix[fsm->st_cnt * fsm->fn_tbl[i].ev + fsm->fn_tbl[i].st] = fsm->fn_tbl[i].fn; - } - return 0; -} - -void -fsm_free(struct fsm *fsm) -{ - kfree(fsm->jumpmatrix); -} - -int -fsm_event(struct fsm_inst *fi, int event, void *arg) -{ - fsm_fn fn; - - if (fi->state >= fi->fsm->st_cnt || - event >= fi->fsm->ev_cnt) { - printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n", - fi->state, fi->fsm->st_cnt,event, - fi->fsm->ev_cnt); - return -EINVAL; - } - fn = fi->fsm->jumpmatrix[fi->fsm->st_cnt * event + fi->state]; - if (!fn) { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s no routine", - fi->fsm->st_str[fi->state], - fi->fsm->ev_str[event]); - return -ESRCH; - } - if (fi->debug) - fi->printdebug(fi, "State %s Event %s", - fi->fsm->st_str[fi->state], - fi->fsm->ev_str[event]); - - return fn(fi, event, arg); -} - -void -fsm_change_state(struct fsm_inst *fi, int newstate) -{ - fi->state = newstate; - if (fi->debug) - fi->printdebug(fi, "ChangeState %s", - fi->fsm->st_str[newstate]); -} - -#if 0 -static void -FsmExpireTimer(struct FsmTimer *ft) -{ -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); -#endif - FsmEvent(ft->fi, ft->event, ft->arg); -} - -void -FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) -{ - ft->fi = fi; - ft->tl.function = (void *) FsmExpireTimer; - ft->tl.data = (long) ft; -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft); -#endif - init_timer(&ft->tl); -} - -void -FsmDelTimer(struct FsmTimer *ft, int where) -{ -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where); -#endif - del_timer(&ft->tl); -} - -int -FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) { - printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); - ft->fi->printdebug(ft->fi, "FsmAddTimer already active!"); - return -1; - } - init_timer(&ft->tl); - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); - return 0; -} - -void -FsmRestartTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) - del_timer(&ft->tl); - init_timer(&ft->tl); - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); -} -#endif diff -puN drivers/isdn/i4l/isdn_net.c~i4l drivers/isdn/i4l/isdn_net.c --- 25/drivers/isdn/i4l/isdn_net.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_net.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,150 +1,3223 @@ -/* Linux ISDN subsystem, network interfaces and related functions (linklevel). +/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, network interfaces and related functions (linklevel). * * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski + * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg + * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * + * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 + * guy@traverse.com.au + * Outgoing calls - looks for a 'V' in first char of dialed number + * Incoming calls - checks first character of eaz as follows: + * Numeric - accept DATA only - original functionality + * 'V' - accept VOICE (DOV) only + * 'B' - accept BOTH DATA and DOV types + * + * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb + * for info on the protocol, see + * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt */ +#include #include -#include #include +#include +#include +#include #include "isdn_common.h" -#include "isdn_net_lib.h" #include "isdn_net.h" +#ifdef CONFIG_ISDN_PPP +#include "isdn_ppp.h" +#endif +#ifdef CONFIG_ISDN_X25 +#include +#include "isdn_concap.h" +#endif + + +/* + * Outline of new tbusy handling: + * + * Old method, roughly spoken, consisted of setting tbusy when entering + * isdn_net_start_xmit() and at several other locations and clearing + * it from isdn_net_start_xmit() thread when sending was successful. + * + * With 2.3.x multithreaded network core, to prevent problems, tbusy should + * only be set by the isdn_net_start_xmit() thread and only when a tx-busy + * condition is detected. Other threads (in particular isdn_net_stat_callb()) + * are only allowed to clear tbusy. + * + * -HE + */ + +/* + * About SOFTNET: + * Most of the changes were pretty obvious and basically done by HE already. + * + * One problem of the isdn net device code is that is uses struct net_device + * for masters and slaves. However, only master interface are registered to + * the network layer, and therefore, it only makes sense to call netif_* + * functions on them. + * + * --KG + */ + +/* + * Find out if the netdevice has been ifup-ed yet. + * For slaves, look at the corresponding master. + */ +static __inline__ int isdn_net_device_started(isdn_net_dev *n) +{ + isdn_net_local *lp = n->local; + struct net_device *dev; + + if (lp->master) + dev = lp->master; + else + dev = &n->dev; + return netif_running(dev); +} + +/* + * wake up the network -> net_device queue. + * For slaves, wake the corresponding master interface. + */ +static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) +{ + if (lp->master) + netif_wake_queue(lp->master); + else + netif_wake_queue(&lp->netdev->dev); +} + +/* + * stop the network -> net_device queue. + * For slaves, stop the corresponding master interface. + */ +static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) +{ + if (lp->master) + netif_stop_queue(lp->master); + else + netif_stop_queue(&lp->netdev->dev); +} + +/* + * find out if the net_device which this lp belongs to (lp can be + * master or slave) is busy. It's busy iff all (master and slave) + * queues are busy + */ +static __inline__ int isdn_net_device_busy(isdn_net_local *lp) +{ + isdn_net_local *nlp; + isdn_net_dev *nd; + unsigned long flags; + + if (!isdn_net_lp_busy(lp)) + return 0; + + if (lp->master) + nd = ((isdn_net_local *) lp->master->priv)->netdev; + else + nd = lp->netdev; + + spin_lock_irqsave(&nd->queue_lock, flags); + nlp = lp->next; + while (nlp != lp) { + if (!isdn_net_lp_busy(nlp)) { + spin_unlock_irqrestore(&nd->queue_lock, flags); + return 0; + } + nlp = nlp->next; + } + spin_unlock_irqrestore(&nd->queue_lock, flags); + return 1; +} + +static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp) +{ + atomic_inc(&lp->frame_cnt); + if (isdn_net_device_busy(lp)) + isdn_net_device_stop_queue(lp); +} + +static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp) +{ + atomic_dec(&lp->frame_cnt); + + if (!(isdn_net_device_busy(lp))) { + if (!skb_queue_empty(&lp->super_tx_queue)) { + schedule_work(&lp->tqueue); + } else { + isdn_net_device_wake_queue(lp); + } + } +} + +static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) +{ + atomic_set(&lp->frame_cnt, 0); +} + +/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just + * to be safe. + * For 2.3.x we push it up to 20 secs, because call establishment + * (in particular callback) may take such a long time, and we + * don't want confusing messages in the log. However, there is a slight + * possibility that this large timeout will break other things like MPPP, + * which might rely on the tx timeout. If so, we'll find out this way... + */ + +#define ISDN_NET_TX_TIMEOUT (20*HZ) + +/* Prototypes */ + +int isdn_net_force_dial_lp(isdn_net_local *); +static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); + +static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); +static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); + +char *isdn_net_revision = "$Revision: 1.1.2.2 $"; -// ISDN_NET_ENCAP_IPTYP -// ethernet type field -// ====================================================================== + /* + * Code for raw-networking over ISDN + */ +static void +isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) +{ + if(skb) { + + u_short proto = ntohs(skb->protocol); + + printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", + dev->name, + (reason != NULL) ? reason : "unknown", + (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); + + dst_link_failure(skb); + } + else { /* dial not triggered by rawIP packet */ + printk(KERN_DEBUG "isdn_net: %s: %s\n", + dev->name, + (reason != NULL) ? reason : "reason unknown"); + } +} + +static void +isdn_net_reset(struct net_device *dev) +{ +#ifdef CONFIG_ISDN_X25 + struct concap_device_ops * dops = + ( (isdn_net_local *) dev->priv ) -> dops; + struct concap_proto * cprot = + ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; +#endif +#ifdef CONFIG_ISDN_X25 + if( cprot && cprot -> pops && dops ) + cprot -> pops -> restart ( cprot, dev, dops ); +#endif +} + +/* Open/initialize the board. */ static int -isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned plen) +isdn_net_open(struct net_device *dev) +{ + int i; + struct net_device *p; + struct in_device *in_dev; + + /* moved here from isdn_net_reset, because only the master has an + interface associated which is supposed to be started. BTW: + we need to call netif_start_queue, not netif_wake_queue here */ + netif_start_queue(dev); + + isdn_net_reset(dev); + /* Fill in the MAC-level header (not needed, but for compatibility... */ + for (i = 0; i < ETH_ALEN - sizeof(u32); i++) + dev->dev_addr[i] = 0xfc; + if ((in_dev = dev->ip_ptr) != NULL) { + /* + * Any address will do - we take the first + */ + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL) + memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); + } + + /* If this interface has slaves, start them also */ + + if ((p = (((isdn_net_local *) dev->priv)->slave))) { + while (p) { + isdn_net_reset(p); + p = (((isdn_net_local *) p->priv)->slave); + } + } + isdn_lock_drivers(); + return 0; +} + +/* + * Assign an ISDN-channel to a net-interface + */ +static void +isdn_net_bind_channel(isdn_net_local * lp, int idx) { - put_u16(skb_push(skb, 2), type); - return 2; + lp->flags |= ISDN_NET_CONNECTED; + lp->isdn_device = dev->drvmap[idx]; + lp->isdn_channel = dev->chanmap[idx]; + dev->rx_netdev[idx] = lp->netdev; + dev->st_netdev[idx] = lp->netdev; } +/* + * unbind a net-interface (resets interface after an error) + */ static void -isdn_iptyp_receive(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb) +isdn_net_unbind_channel(isdn_net_local * lp) +{ + skb_queue_purge(&lp->super_tx_queue); + + if (!lp->master) { /* reset only master device */ + /* Moral equivalent of dev_purge_queues(): + BEWARE! This chunk of code cannot be called from hardware + interrupt handler. I hope it is true. --ANK + */ + qdisc_reset(lp->netdev->dev.qdisc); + } + lp->dialstate = 0; + dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; + dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; + isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); + lp->flags &= ~ISDN_NET_CONNECTED; + lp->isdn_device = -1; + lp->isdn_channel = -1; +} + +/* + * Perform auto-hangup and cps-calculation for net-interfaces. + * + * auto-hangup: + * Increment idle-counter (this counter is reset on any incoming or + * outgoing packet), if counter exceeds configured limit either do a + * hangup immediately or - if configured - wait until just before the next + * charge-info. + * + * cps-calculation (needed for dynamic channel-bundling): + * Since this function is called every second, simply reset the + * byte-counter of the interface after copying it to the cps-variable. + */ +unsigned long last_jiffies = -HZ; + +void +isdn_net_autohup() { - u16 protocol; + isdn_net_dev *p = dev->netdev; + int anymore; + + anymore = 0; + while (p) { + isdn_net_local *l = p->local; + if (jiffies == last_jiffies) + l->cps = l->transcount; + else + l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); + l->transcount = 0; + if (dev->net_verbose > 3) + printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps); + if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { + anymore = 1; + l->huptimer++; + /* + * if there is some dialmode where timeout-hangup + * should _not_ be done, check for that here + */ + if ((l->onhtime) && + (l->huptimer > l->onhtime)) + { + if (l->hupflags & ISDN_MANCHARGE && + l->hupflags & ISDN_CHARGEHUP) { + while (time_after(jiffies, l->chargetime + l->chargeint)) + l->chargetime += l->chargeint; + if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) + if (l->outgoing || l->hupflags & ISDN_INHUP) + isdn_net_hangup(&p->dev); + } else if (l->outgoing) { + if (l->hupflags & ISDN_CHARGEHUP) { + if (l->hupflags & ISDN_WAITCHARGE) { + printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", + l->name, l->hupflags); + isdn_net_hangup(&p->dev); + } else if (time_after(jiffies, l->chargetime + l->chargeint)) { + printk(KERN_DEBUG + "isdn_net: %s: chtime = %lu, chint = %d\n", + l->name, l->chargetime, l->chargeint); + isdn_net_hangup(&p->dev); + } + } else + isdn_net_hangup(&p->dev); + } else if (l->hupflags & ISDN_INHUP) + isdn_net_hangup(&p->dev); + } + + if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { + isdn_net_hangup(&p->dev); + break; + } + } + p = (isdn_net_dev *) p->next; + } + last_jiffies = jiffies; + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); +} - get_u16(skb->data, &protocol); - skb_pull(skb, 2); - isdn_netif_rx(idev, skb, protocol); +static void isdn_net_lp_disconnected(isdn_net_local *lp) +{ + isdn_net_rm_from_bundle(lp); } -struct isdn_netif_ops isdn_iptyp_ops = { - .hard_start_xmit = isdn_net_start_xmit, - .hard_header = isdn_iptyp_header, - .flags = IFF_NOARP | IFF_POINTOPOINT, - .type = ARPHRD_PPP, - .addr_len = 2, - .receive = isdn_iptyp_receive, -}; +/* + * Handle status-messages from ISDN-interfacecard. + * This function is called from within the main-status-dispatcher + * isdn_status_callback, which itself is called from the low-level driver. + * Return: 1 = Event handled, 0 = not for us or unknown Event. + */ +int +isdn_net_stat_callback(int idx, isdn_ctrl *c) +{ + isdn_net_dev *p = dev->st_netdev[idx]; + int cmd = c->command; -// ISDN_NET_ENCAP_UIHDLC -// HDLC with UI-Frames (for ispa with -h1 option) */ -// ====================================================================== + if (p) { + isdn_net_local *lp = p->local; +#ifdef CONFIG_ISDN_X25 + struct concap_proto *cprot = lp -> netdev -> cprot; + struct concap_proto_ops *pops = cprot ? cprot -> pops : 0; +#endif + switch (cmd) { + case ISDN_STAT_BSENT: + /* A packet has successfully been sent out */ + if ((lp->flags & ISDN_NET_CONNECTED) && + (!lp->dialstate)) { + isdn_net_dec_frame_cnt(lp); + lp->stats.tx_packets++; + lp->stats.tx_bytes += c->parm.length; + } + return 1; + case ISDN_STAT_DCONN: + /* D-Channel is up */ + switch (lp->dialstate) { + case 4: + case 7: + case 8: + lp->dialstate++; + return 1; + case 12: + lp->dialstate = 5; + return 1; + } + break; + case ISDN_STAT_DHUP: + /* Either D-Channel-hangup or error during dialout */ +#ifdef CONFIG_ISDN_X25 + /* If we are not connencted then dialing had + failed. If there are generic encap protocol + receiver routines signal the closure of + the link*/ + + if( !(lp->flags & ISDN_NET_CONNECTED) + && pops && pops -> disconn_ind ) + pops -> disconn_ind(cprot); +#endif /* CONFIG_ISDN_X25 */ + if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { + if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) + isdn_net_ciscohdlck_disconnected(lp); +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); +#endif + isdn_net_lp_disconnected(lp); + isdn_all_eaz(lp->isdn_device, lp->isdn_channel); + printk(KERN_INFO "%s: remote hangup\n", lp->name); + printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, + lp->charge); + isdn_net_unbind_channel(lp); + return 1; + } + break; +#ifdef CONFIG_ISDN_X25 + case ISDN_STAT_BHUP: + /* B-Channel-hangup */ + /* try if there are generic encap protocol + receiver routines and signal the closure of + the link */ + if( pops && pops -> disconn_ind ){ + pops -> disconn_ind(cprot); + return 1; + } + break; +#endif /* CONFIG_ISDN_X25 */ + case ISDN_STAT_BCONN: + /* B-Channel is up */ + isdn_net_zero_frame_cnt(lp); + switch (lp->dialstate) { + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 12: + if (lp->dialstate <= 6) { + dev->usage[idx] |= ISDN_USAGE_OUTGOING; + isdn_info_update(); + } else + dev->rx_netdev[idx] = p; + lp->dialstate = 0; + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); + if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) + isdn_net_ciscohdlck_connected(lp); + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { + if (lp->master) { /* is lp a slave? */ + isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; + isdn_net_add_to_bundle(nd, lp); + } + } + printk(KERN_INFO "isdn_net: %s connected\n", lp->name); + /* If first Chargeinfo comes before B-Channel connect, + * we correct the timestamp here. + */ + lp->chargetime = jiffies; + + /* reset dial-timeout */ + lp->dialstarted = 0; + lp->dialwait_timer = 0; + +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_wakeup_daemon(lp); +#endif +#ifdef CONFIG_ISDN_X25 + /* try if there are generic concap receiver routines */ + if( pops ) + if( pops->connect_ind) + pops->connect_ind(cprot); +#endif /* CONFIG_ISDN_X25 */ + /* ppp needs to do negotiations first */ + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) + isdn_net_device_wake_queue(lp); + return 1; + } + break; + case ISDN_STAT_NODCH: + /* No D-Channel avail. */ + if (lp->dialstate == 4) { + lp->dialstate--; + return 1; + } + break; + case ISDN_STAT_CINF: + /* Charge-info from TelCo. Calculate interval between + * charge-infos and set timestamp for last info for + * usage by isdn_net_autohup() + */ + lp->charge++; + if (lp->hupflags & ISDN_HAVECHARGE) { + lp->hupflags &= ~ISDN_WAITCHARGE; + lp->chargeint = jiffies - lp->chargetime - (2 * HZ); + } + if (lp->hupflags & ISDN_WAITCHARGE) + lp->hupflags |= ISDN_HAVECHARGE; + lp->chargetime = jiffies; + printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", + lp->name, lp->chargetime); + return 1; + } + } + return 0; +} +/* + * Perform dialout for net-interfaces and timeout-handling for + * D-Channel-up and B-Channel-up Messages. + * This function is initially called from within isdn_net_start_xmit() or + * or isdn_net_find_icall() after initializing the dialstate for an + * interface. If further calls are needed, the function schedules itself + * for a timer-callback via isdn_timer_function(). + * The dialstate is also affected by incoming status-messages from + * the ISDN-Channel which are handled in isdn_net_stat_callback() above. + */ +void +isdn_net_dial(void) +{ + isdn_net_dev *p = dev->netdev; + int anymore = 0; + int i; + isdn_ctrl cmd; + u_char *phone_number; + + while (p) { + isdn_net_local *lp = p->local; + +#ifdef ISDN_DEBUG_NET_DIAL + if (lp->dialstate) + printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate); +#endif + switch (lp->dialstate) { + case 0: + /* Nothing to do for this interface */ + break; + case 1: + /* Initiate dialout. Set phone-number-pointer to first number + * of interface. + */ + lp->dial = lp->phone[1]; + if (!lp->dial) { + printk(KERN_WARNING "%s: phone number deleted?\n", + lp->name); + isdn_net_hangup(&p->dev); + break; + } + anymore = 1; + + if(lp->dialtimeout > 0) + if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { + lp->dialstarted = jiffies; + lp->dialwait_timer = 0; + } + + lp->dialstate++; + /* Fall through */ + case 2: + /* Prepare dialing. Clear EAZ, then set EAZ. */ + cmd.driver = lp->isdn_device; + cmd.arg = lp->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + lp->dialretry = 0; + anymore = 1; + lp->dialstate++; + /* Fall through */ + case 3: + /* Setup interface, dial current phone-number, switch to next number. + * If list of phone-numbers is exhausted, increment + * retry-counter. + */ + if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { + char *s; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + s = "dial suppressed: isdn system stopped"; + else + s = "dial suppressed: dialmode `off'"; + isdn_net_unreachable(&p->dev, 0, s); + isdn_net_hangup(&p->dev); + break; + } + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); + isdn_command(&cmd); + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); + isdn_command(&cmd); + cmd.driver = lp->isdn_device; + cmd.arg = lp->isdn_channel; + if (!lp->dial) { + printk(KERN_WARNING "%s: phone number deleted?\n", + lp->name); + isdn_net_hangup(&p->dev); + break; + } + if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { + lp->dialstate = 4; + printk(KERN_INFO "%s: Open leased line ...\n", lp->name); + } else { + if(lp->dialtimeout > 0) + if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_unreachable(&p->dev, 0, "dial: timed out"); + isdn_net_hangup(&p->dev); + break; + } + + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_DIAL; + cmd.parm.setup.si2 = 0; + + /* check for DOV */ + phone_number = lp->dial->num; + if ((*phone_number == 'v') || + (*phone_number == 'V')) { /* DOV call */ + cmd.parm.setup.si1 = 1; + } else { /* DATA call */ + cmd.parm.setup.si1 = 7; + } + + strcpy(cmd.parm.setup.phone, phone_number); + /* + * Switch to next number or back to start if at end of list. + */ + if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { + lp->dial = lp->phone[1]; + lp->dialretry++; + + if (lp->dialretry > lp->dialmax) { + if (lp->dialtimeout == 0) { + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times"); + } + isdn_net_hangup(&p->dev); + break; + } + } + sprintf(cmd.parm.setup.eazmsn, "%s", + isdn_map_eaz2msn(lp->msn, cmd.driver)); + i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel); + if (i >= 0) { + strcpy(dev->num[i], cmd.parm.setup.phone); + dev->usage[i] |= ISDN_USAGE_OUTGOING; + isdn_info_update(); + } + printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name, + lp->dialretry, cmd.parm.setup.phone, + (cmd.parm.setup.si1 == 1) ? "DOV" : ""); + lp->dtimer = 0; +#ifdef ISDN_DEBUG_NET_DIAL + printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, + lp->isdn_channel); +#endif + isdn_command(&cmd); + } + lp->huptimer = 0; + lp->outgoing = 1; + if (lp->chargeint) { + lp->hupflags |= ISDN_HAVECHARGE; + lp->hupflags &= ~ISDN_WAITCHARGE; + } else { + lp->hupflags |= ISDN_WAITCHARGE; + lp->hupflags &= ~ISDN_HAVECHARGE; + } + anymore = 1; + lp->dialstate = + (lp->cbdelay && + (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4; + break; + case 4: + /* Wait for D-Channel-connect. + * If timeout, switch back to state 3. + * Dialmax-handling moved to state 3. + */ + if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) + lp->dialstate = 3; + anymore = 1; + break; + case 5: + /* Got D-Channel-Connect, send B-Channel-request */ + cmd.driver = lp->isdn_device; + cmd.arg = lp->isdn_channel; + cmd.command = ISDN_CMD_ACCEPTB; + anymore = 1; + lp->dtimer = 0; + lp->dialstate++; + isdn_command(&cmd); + break; + case 6: + /* Wait for B- or D-Channel-connect. If timeout, + * switch back to state 3. + */ +#ifdef ISDN_DEBUG_NET_DIAL + printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer); +#endif + if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) + lp->dialstate = 3; + anymore = 1; + break; + case 7: + /* Got incoming Call, setup L2 and L3 protocols, + * then wait for D-Channel-connect + */ +#ifdef ISDN_DEBUG_NET_DIAL + printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); +#endif + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); + isdn_command(&cmd); + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); + isdn_command(&cmd); + if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15) + isdn_net_hangup(&p->dev); + else { + anymore = 1; + lp->dialstate++; + } + break; + case 9: + /* Got incoming D-Channel-Connect, send B-Channel-request */ + cmd.driver = lp->isdn_device; + cmd.arg = lp->isdn_channel; + cmd.command = ISDN_CMD_ACCEPTB; + isdn_command(&cmd); + anymore = 1; + lp->dtimer = 0; + lp->dialstate++; + break; + case 8: + case 10: + /* Wait for B- or D-channel-connect */ +#ifdef ISDN_DEBUG_NET_DIAL + printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); +#endif + if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) + isdn_net_hangup(&p->dev); + else + anymore = 1; + break; + case 11: + /* Callback Delay */ + if (lp->dtimer++ > lp->cbdelay) + lp->dialstate = 1; + anymore = 1; + break; + case 12: + /* Remote does callback. Hangup after cbdelay, then wait for incoming + * call (in state 4). + */ + if (lp->dtimer++ > lp->cbdelay) + { + printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name); + lp->dtimer = 0; + lp->dialstate = 4; + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_HANGUP; + cmd.arg = lp->isdn_channel; + isdn_command(&cmd); + isdn_all_eaz(lp->isdn_device, lp->isdn_channel); + } + anymore = 1; + break; + default: + printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", + lp->dialstate, lp->name); + } + p = (isdn_net_dev *) p->next; + } + isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore); +} + +/* + * Perform hangup for a net-interface. + */ +void +isdn_net_hangup(struct net_device *d) +{ + isdn_net_local *lp = (isdn_net_local *) d->priv; + isdn_ctrl cmd; +#ifdef CONFIG_ISDN_X25 + struct concap_proto *cprot = lp -> netdev -> cprot; + struct concap_proto_ops *pops = cprot ? cprot -> pops : 0; +#endif + + if (lp->flags & ISDN_NET_CONNECTED) { + if (lp->slave != NULL) { + isdn_net_local *slp = (isdn_net_local *)lp->slave->priv; + if (slp->flags & ISDN_NET_CONNECTED) { + printk(KERN_INFO + "isdn_net: hang up slave %s before %s\n", + slp->name, lp->name); + isdn_net_hangup(lp->slave); + } + } + printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); +#endif + isdn_net_lp_disconnected(lp); +#ifdef CONFIG_ISDN_X25 + /* try if there are generic encap protocol + receiver routines and signal the closure of + the link */ + if( pops && pops -> disconn_ind ) + pops -> disconn_ind(cprot); +#endif /* CONFIG_ISDN_X25 */ + + cmd.driver = lp->isdn_device; + cmd.command = ISDN_CMD_HANGUP; + cmd.arg = lp->isdn_channel; + isdn_command(&cmd); + printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); + isdn_all_eaz(lp->isdn_device, lp->isdn_channel); + } + isdn_net_unbind_channel(lp); +} + +typedef struct { + unsigned short source; + unsigned short dest; +} ip_ports; + +static void +isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) +{ + u_char *p = skb->nh.raw; /* hopefully, this was set correctly */ + unsigned short proto = ntohs(skb->protocol); + int data_ofs; + ip_ports *ipp; + char addinfo[100]; + + addinfo[0] = '\0'; + /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ + if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) { + /* fall back to old isdn_net_log_packet method() */ + char * buf = skb->data; + + printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name); + p = buf; + proto = ETH_P_IP; + switch (lp->p_encap) { + case ISDN_NET_ENCAP_IPTYP: + proto = ntohs(*(unsigned short *) &buf[0]); + p = &buf[2]; + break; + case ISDN_NET_ENCAP_ETHER: + proto = ntohs(*(unsigned short *) &buf[12]); + p = &buf[14]; + break; + case ISDN_NET_ENCAP_CISCOHDLC: + proto = ntohs(*(unsigned short *) &buf[2]); + p = &buf[4]; + break; +#ifdef CONFIG_ISDN_PPP + case ISDN_NET_ENCAP_SYNCPPP: + proto = ntohs(skb->protocol); + p = &buf[IPPP_MAX_HEADER]; + break; +#endif + } + } + data_ofs = ((p[0] & 15) * 4); + switch (proto) { + case ETH_P_IP: + switch (p[9]) { + case 1: + strcpy(addinfo, " ICMP"); + break; + case 2: + strcpy(addinfo, " IGMP"); + break; + case 4: + strcpy(addinfo, " IPIP"); + break; + case 6: + ipp = (ip_ports *) (&p[data_ofs]); + sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source), + ntohs(ipp->dest)); + break; + case 8: + strcpy(addinfo, " EGP"); + break; + case 12: + strcpy(addinfo, " PUP"); + break; + case 17: + ipp = (ip_ports *) (&p[data_ofs]); + sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source), + ntohs(ipp->dest)); + break; + case 22: + strcpy(addinfo, " IDP"); + break; + } + printk(KERN_INFO + "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n", + + p[12], p[13], p[14], p[15], + p[16], p[17], p[18], p[19], + addinfo); + break; + case ETH_P_ARP: + printk(KERN_INFO + "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", + p[14], p[15], p[16], p[17], + p[24], p[25], p[26], p[27]); + break; + } +} + +/* + * this function is used to send supervisory data, i.e. data which was + * not received from the network layer, but e.g. frames from ipppd, CCP + * reset frames etc. + */ +void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) +{ + if (in_irq()) { + // we can't grab the lock from irq context, + // so we just queue the packet + skb_queue_tail(&lp->super_tx_queue, skb); + schedule_work(&lp->tqueue); + return; + } + + spin_lock_bh(&lp->xmit_lock); + if (!isdn_net_lp_busy(lp)) { + isdn_net_writebuf_skb(lp, skb); + } else { + skb_queue_tail(&lp->super_tx_queue, skb); + } + spin_unlock_bh(&lp->xmit_lock); +} + +/* + * called from tq_immediate + */ +static void isdn_net_softint(void *private) +{ + isdn_net_local *lp = private; + struct sk_buff *skb; + + spin_lock_bh(&lp->xmit_lock); + while (!isdn_net_lp_busy(lp)) { + skb = skb_dequeue(&lp->super_tx_queue); + if (!skb) + break; + isdn_net_writebuf_skb(lp, skb); + } + spin_unlock_bh(&lp->xmit_lock); +} + +/* + * all frames sent from the (net) LL to a HL driver should go via this function + * it's serialized by the caller holding the lp->xmit_lock spinlock + */ +void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb) +{ + int ret; + int len = skb->len; /* save len */ + + /* before obtaining the lock the caller should have checked that + the lp isn't busy */ + if (isdn_net_lp_busy(lp)) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + goto error; + } + + if (!(lp->flags & ISDN_NET_CONNECTED)) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + goto error; + } + ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); + if (ret != len) { + /* we should never get here */ + printk(KERN_WARNING "%s: HL driver queue full\n", lp->name); + goto error; + } + + lp->transcount += len; + isdn_net_inc_frame_cnt(lp); + return; + + error: + dev_kfree_skb(skb); + lp->stats.tx_errors++; + +} + + +/* + * Helper function for isdn_net_start_xmit. + * When called, the connection is already established. + * Based on cps-calculation, check if device is overloaded. + * If so, and if a slave exists, trigger dialing for it. + * If any slave is online, deliver packets using a simple round robin + * scheme. + * + * Return: 0 on success, !0 on failure. + */ + +static int +isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) +{ + isdn_net_dev *nd; + isdn_net_local *slp; + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + int retv = 0; + + if (((isdn_net_local *) (ndev->priv))->master) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + dev_kfree_skb(skb); + return 0; + } + + /* For the other encaps the header has already been built */ +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { + return isdn_ppp_xmit(skb, ndev); + } +#endif + nd = ((isdn_net_local *) ndev->priv)->netdev; + lp = isdn_net_get_locked_lp(nd); + if (!lp) { + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); + return 1; + } + /* we have our lp locked from now on */ + + /* Reset hangup-timeout */ + lp->huptimer = 0; // FIXME? + isdn_net_writebuf_skb(lp, skb); + spin_unlock_bh(&lp->xmit_lock); + + /* the following stuff is here for backwards compatibility. + * in future, start-up and hangup of slaves (based on current load) + * should move to userspace and get based on an overall cps + * calculation + */ + if (lp->cps > lp->triggercps) { + if (lp->slave) { + if (!lp->sqfull) { + /* First time overload: set timestamp only */ + lp->sqfull = 1; + lp->sqfull_stamp = jiffies; + } else { + /* subsequent overload: if slavedelay exceeded, start dialing */ + if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { + slp = lp->slave->priv; + if (!(slp->flags & ISDN_NET_CONNECTED)) { + isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + } + } + } + } + } else { + if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) { + lp->sqfull = 0; + } + /* this is a hack to allow auto-hangup for slaves on moderate loads */ + nd->queue = nd->local; + } + + return retv; + +} + +static void +isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) +{ + isdn_net_local *lp = (isdn_net_local *) dev->priv; + if (!skb) + return; + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { + int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN; + if (pullsize > 0) { + printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize); + skb_pull(skb, pullsize); + } + } +} + + +void isdn_net_tx_timeout(struct net_device * ndev) +{ + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + + printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate); + if (!lp->dialstate){ + lp->stats.tx_errors++; + /* + * There is a certain probability that this currently + * works at all because if we always wake up the interface, + * then upper layer will try to send the next packet + * immediately. And then, the old clean_up logic in the + * driver will hopefully continue to work as it used to do. + * + * This is rather primitive right know, we better should + * clean internal queues here, in particular for multilink and + * ppp, and reset HL driver's channel, too. --HE + * + * actually, this may not matter at all, because ISDN hardware + * should not see transmitter hangs at all IMO + * changed KERN_DEBUG to KERN_WARNING to find out if this is + * ever called --KG + */ + } + ndev->trans_start = jiffies; + netif_wake_queue(ndev); +} + +/* + * Try sending a packet. + * If this interface isn't connected to a ISDN-Channel, find a free channel, + * and start dialing. + */ +static int +isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + isdn_net_local *lp = (isdn_net_local *) ndev->priv; +#ifdef CONFIG_ISDN_X25 + struct concap_proto * cprot = lp -> netdev -> cprot; +/* At this point hard_start_xmit() passes control to the encapsulation + protocol (if present). + For X.25 auto-dialing is completly bypassed because: + - It does not conform with the semantics of a reliable datalink + service as needed by X.25 PLP. + - I don't want that the interface starts dialing when the network layer + sends a message which requests to disconnect the lapb link (or if it + sends any other message not resulting in data transmission). + Instead, dialing will be initiated by the encapsulation protocol entity + when a dl_establish request is received from the upper layer. +*/ + if (cprot && cprot -> pops) { + int ret = cprot -> pops -> encap_and_xmit ( cprot , skb); + + if (ret) + netif_stop_queue(ndev); + return ret; + } else +#endif + /* auto-dialing xmit function */ + { +#ifdef ISDN_DEBUG_NET_DUMP + u_char *buf; +#endif + isdn_net_adjust_hdr(skb, ndev); +#ifdef ISDN_DEBUG_NET_DUMP + buf = skb->data; + isdn_dumppkt("S:", buf, skb->len, 40); +#endif + + if (!(lp->flags & ISDN_NET_CONNECTED)) { + int chi; + /* only do autodial if allowed by config */ + if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { + isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); + dev_kfree_skb(skb); + return 0; + } + if (lp->phone[1]) { + ulong flags; + + if(lp->dialwait_timer <= 0) + if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) + lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; + + if(lp->dialwait_timer > 0) { + if(time_before(jiffies, lp->dialwait_timer)) { + isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); + dev_kfree_skb(skb); + return 0; + } else + lp->dialwait_timer = 0; + } + /* Grab a free ISDN-Channel */ + spin_lock_irqsave(&dev->lock, flags); + if (((chi = + isdn_get_free_channel( + ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel, + lp->msn) + ) < 0) && + ((chi = + isdn_get_free_channel( + ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel^1, + lp->msn) + ) < 0)) { + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_unreachable(ndev, skb, + "No channel"); + dev_kfree_skb(skb); + return 0; + } + /* Log packet, which triggered dialing */ + if (dev->net_verbose) + isdn_net_log_skb(skb, lp); + lp->dialstate = 1; + /* Connect interface with channel */ + isdn_net_bind_channel(lp, chi); +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { + /* no 'first_skb' handling for syncPPP */ + if (isdn_ppp_bind(lp) < 0) { + dev_kfree_skb(skb); + isdn_net_unbind_channel(lp); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; /* STN (skb to nirvana) ;) */ + } +#ifdef CONFIG_IPPP_FILTER + if (isdn_ppp_autodial_filter(skb, lp)) { + isdn_ppp_free(lp); + isdn_net_unbind_channel(lp); + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); + dev_kfree_skb(skb); + return 0; + } +#endif + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_dial(); /* Initiate dialing */ + netif_stop_queue(ndev); + return 1; /* let upper layer requeue skb packet */ + } +#endif + /* Initiate dialing */ + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_dial(); + isdn_net_device_stop_queue(lp); + return 1; + } else { + isdn_net_unreachable(ndev, skb, + "No phone number"); + dev_kfree_skb(skb); + return 0; + } + } else { + /* Device is connected to an ISDN channel */ + ndev->trans_start = jiffies; + if (!lp->dialstate) { + /* ISDN connection is established, try sending */ + int ret; + ret = (isdn_net_xmit(ndev, skb)); + if(ret) netif_stop_queue(ndev); + return ret; + } else + netif_stop_queue(ndev); + } + } + return 1; +} + +/* + * Shutdown a net-interface. + */ static int -isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned plen) +isdn_net_close(struct net_device *dev) +{ + struct net_device *p; +#ifdef CONFIG_ISDN_X25 + struct concap_proto * cprot = + ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */ +#endif + +#ifdef CONFIG_ISDN_X25 + if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); +#endif + netif_stop_queue(dev); + if ((p = (((isdn_net_local *) dev->priv)->slave))) { + /* If this interface has slaves, stop them also */ + while (p) { +#ifdef CONFIG_ISDN_X25 + cprot = ( (isdn_net_local *) p->priv ) + -> netdev -> cprot; + if( cprot && cprot -> pops ) + cprot -> pops -> close( cprot ); +#endif + isdn_net_hangup(p); + p = (((isdn_net_local *) p->priv)->slave); + } + } + isdn_net_hangup(dev); + isdn_unlock_drivers(); + return 0; +} + +/* + * Get statistics + */ +static struct net_device_stats * +isdn_net_get_stats(struct net_device *dev) +{ + isdn_net_local *lp = (isdn_net_local *) dev->priv; + return &lp->stats; +} + +/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN + * instead of dev->hard_header_len off. This is done because the + * lowlevel-driver has already pulled off its stuff when we get + * here and this routine only gets called with p_encap == ETHER. + * Determine the packet's protocol ID. The rule here is that we + * assume 802.3 if the type field is short enough to be a length. + * This is normal practice and works for any 'now in use' protocol. + */ + +static unsigned short +isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct ethhdr *eth; + unsigned char *rawp; + + skb->mac.raw = skb->data; + skb_pull(skb, ETH_HLEN); + eth = skb->mac.ethernet; + + if (*eth->h_dest & 1) { + if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } + /* + * This ALLMULTI check should be redundant by 1.4 + * so don't forget to remove it. + */ + + else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) { + if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + } + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + /* + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ + if (*(unsigned short *) rawp == 0xFFFF) + return htons(ETH_P_802_3); + /* + * Real 802.2 LLC + */ + return htons(ETH_P_802_2); +} + + +/* + * CISCO HDLC keepalive specific stuff + */ +static struct sk_buff* +isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) { - put_u16(skb_push(skb, 2), 0x0103); - return 2; + unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; + struct sk_buff *skb; + + skb = alloc_skb(hl + len, GFP_ATOMIC); + if (!skb) { + printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); + return 0; + } + skb_reserve(skb, hl); + return skb; +} + +/* cisco hdlck device private ioctls */ +int +isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + isdn_net_local *lp = (isdn_net_local *) dev->priv; + unsigned long len = 0; + unsigned long expires = 0; + int tmp = 0; + int period = lp->cisco_keepalive_period; + char debserint = lp->cisco_debserint; + int rc = 0; + + if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK) + return -EINVAL; + + switch (cmd) { + /* get/set keepalive period */ + case SIOCGKEEPPERIOD: + len = (unsigned long)sizeof(lp->cisco_keepalive_period); + if (copy_to_user((char *)ifr->ifr_ifru.ifru_data, + (int *)&lp->cisco_keepalive_period, len)) + rc = -EFAULT; + break; + case SIOCSKEEPPERIOD: + tmp = lp->cisco_keepalive_period; + len = (unsigned long)sizeof(lp->cisco_keepalive_period); + if (copy_from_user((int *)&period, + (char *)ifr->ifr_ifru.ifru_data, len)) + rc = -EFAULT; + if ((period > 0) && (period <= 32767)) + lp->cisco_keepalive_period = period; + else + rc = -EINVAL; + if (!rc && (tmp != lp->cisco_keepalive_period)) { + expires = (unsigned long)(jiffies + + lp->cisco_keepalive_period * HZ); + mod_timer(&lp->cisco_timer, expires); + printk(KERN_INFO "%s: Keepalive period set " + "to %d seconds.\n", + lp->name, lp->cisco_keepalive_period); + } + break; + + /* get/set debugging */ + case SIOCGDEBSERINT: + len = (unsigned long)sizeof(lp->cisco_debserint); + if (copy_to_user((char *)ifr->ifr_ifru.ifru_data, + (char *)&lp->cisco_debserint, len)) + rc = -EFAULT; + break; + case SIOCSDEBSERINT: + len = (unsigned long)sizeof(lp->cisco_debserint); + if (copy_from_user((char *)&debserint, + (char *)ifr->ifr_ifru.ifru_data, len)) + rc = -EFAULT; + if ((debserint >= 0) && (debserint <= 64)) + lp->cisco_debserint = debserint; + else + rc = -EINVAL; + break; + + default: + rc = -EINVAL; + break; + } + return (rc); } +/* called via cisco_timer.function */ static void -isdn_uihdlc_receive(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb) +isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) { - skb_pull(skb, 2); - isdn_netif_rx(idev, skb, htons(ETH_P_IP)); + isdn_net_local *lp = (isdn_net_local *) data; + struct sk_buff *skb; + unsigned char *p; + unsigned long last_cisco_myseq = lp->cisco_myseq; + int myseq_diff = 0; + + if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + return; + } + lp->cisco_myseq++; + + myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen); + if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) { + /* line up -> down */ + lp->cisco_line_state = 0; + printk (KERN_WARNING + "UPDOWN: Line protocol on Interface %s," + " changed state to down\n", lp->name); + /* should stop routing higher-level data accross */ + } else if ((!lp->cisco_line_state) && + (myseq_diff >= 0) && (myseq_diff <= 2)) { + /* line down -> up */ + lp->cisco_line_state = 1; + printk (KERN_WARNING + "UPDOWN: Line protocol on Interface %s," + " changed state to up\n", lp->name); + /* restart routing higher-level data accross */ + } + + if (lp->cisco_debserint) + printk (KERN_DEBUG "%s: HDLC " + "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n", + lp->name, last_cisco_myseq, lp->cisco_mineseen, + ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040), + lp->cisco_yourseq, + ((lp->cisco_line_state) ? "line up" : "line down")); + + skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); + if (!skb) + return; + + p = skb_put(skb, 4 + 14); + + /* cisco header */ + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, CISCO_TYPE_SLARP); + + /* slarp keepalive */ + p += put_u32(p, CISCO_SLARP_KEEPALIVE); + p += put_u32(p, lp->cisco_myseq); + p += put_u32(p, lp->cisco_yourseq); + p += put_u16(p, 0xffff); // reliablity, always 0xffff + + isdn_net_write_super(lp, skb); + + lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; + + add_timer(&lp->cisco_timer); } -struct isdn_netif_ops isdn_uihdlc_ops = { - .hard_start_xmit = isdn_net_start_xmit, - .hard_header = isdn_uihdlc_header, - .flags = IFF_NOARP | IFF_POINTOPOINT, - .type = ARPHRD_HDLC, - .addr_len = 2, - .receive = isdn_uihdlc_receive, -}; +static void +isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp) +{ + struct sk_buff *skb; + unsigned char *p; -// ISDN_NET_ENCAP_RAWIP -// RAW-IP without MAC-Header -// ====================================================================== + skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); + if (!skb) + return; + + p = skb_put(skb, 4 + 14); + + /* cisco header */ + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, CISCO_TYPE_SLARP); + + /* slarp request */ + p += put_u32(p, CISCO_SLARP_REQUEST); + p += put_u32(p, 0); // address + p += put_u32(p, 0); // netmask + p += put_u16(p, 0); // unused + + isdn_net_write_super(lp, skb); +} + +static void +isdn_net_ciscohdlck_connected(isdn_net_local *lp) +{ + lp->cisco_myseq = 0; + lp->cisco_mineseen = 0; + lp->cisco_yourseq = 0; + lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT; + lp->cisco_last_slarp_in = 0; + lp->cisco_line_state = 0; + lp->cisco_debserint = 0; + + /* send slarp request because interface/seq.no.s reset */ + isdn_net_ciscohdlck_slarp_send_request(lp); + + init_timer(&lp->cisco_timer); + lp->cisco_timer.data = (unsigned long) lp; + lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive; + lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; + add_timer(&lp->cisco_timer); +} + +static void +isdn_net_ciscohdlck_disconnected(isdn_net_local *lp) +{ + del_timer(&lp->cisco_timer); +} static void -isdn_rawip_receive(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb) +isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) { - idev->huptimer = 0; - skb->protocol = htons(ETH_P_IP); + struct sk_buff *skb; + unsigned char *p; + struct in_device *in_dev = NULL; + u32 addr = 0; /* local ipv4 address */ + u32 mask = 0; /* local netmask */ + + if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) { + /* take primary(first) address of interface */ + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL) { + addr = ifa->ifa_local; + mask = ifa->ifa_mask; + } + } + + skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); + if (!skb) + return; + + p = skb_put(skb, 4 + 14); + + /* cisco header */ + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, CISCO_TYPE_SLARP); + + /* slarp reply, send own ip/netmask; if values are nonsense remote + * should think we are unable to provide it with an address via SLARP */ + p += put_u32(p, CISCO_SLARP_REPLY); + p += put_u32(p, addr); // address + p += put_u32(p, mask); // netmask + p += put_u16(p, 0); // unused + + isdn_net_write_super(lp, skb); +} + +static void +isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) +{ + unsigned char *p; + int period; + u32 code; + u32 my_seq, addr; + u32 your_seq, mask; + u32 local; + u16 unused; + + if (skb->len < 14) + return; + + p = skb->data; + p += get_u32(p, &code); + + switch (code) { + case CISCO_SLARP_REQUEST: + lp->cisco_yourseq = 0; + isdn_net_ciscohdlck_slarp_send_reply(lp); + break; + case CISCO_SLARP_REPLY: + addr = ntohl(*(u32 *)p); + mask = ntohl(*(u32 *)(p+4)); + if (mask != 0xfffffffc) + goto slarp_reply_out; + if ((addr & 3) == 0 || (addr & 3) == 3) + goto slarp_reply_out; + local = addr ^ 3; + printk(KERN_INFO "%s: got slarp reply: " + "remote ip: %d.%d.%d.%d, " + "local ip: %d.%d.%d.%d " + "mask: %d.%d.%d.%d\n", + lp->name, + HIPQUAD(addr), + HIPQUAD(local), + HIPQUAD(mask)); + break; + slarp_reply_out: + printk(KERN_INFO "%s: got invalid slarp " + "reply (%d.%d.%d.%d/%d.%d.%d.%d) " + "- ignored\n", lp->name, + HIPQUAD(addr), HIPQUAD(mask)); + break; + case CISCO_SLARP_KEEPALIVE: + period = (int)((jiffies - lp->cisco_last_slarp_in + + HZ/2 - 1) / HZ); + if (lp->cisco_debserint && + (period != lp->cisco_keepalive_period) && + lp->cisco_last_slarp_in) { + printk(KERN_DEBUG "%s: Keepalive period mismatch - " + "is %d but should be %d.\n", + lp->name, period, lp->cisco_keepalive_period); + } + lp->cisco_last_slarp_in = jiffies; + p += get_u32(p, &my_seq); + p += get_u32(p, &your_seq); + p += get_u16(p, &unused); + lp->cisco_yourseq = my_seq; + lp->cisco_mineseen = your_seq; + break; + } +} + +static void +isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) +{ + unsigned char *p; + u8 addr; + u8 ctrl; + u16 type; + + if (skb->len < 4) + goto out_free; + + p = skb->data; + p += get_u8 (p, &addr); + p += get_u8 (p, &ctrl); + p += get_u16(p, &type); + skb_pull(skb, 4); + + if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { + printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", + lp->name, addr); + goto out_free; + } + if (ctrl != CISCO_CTRL) { + printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", + lp->name, ctrl); + goto out_free; + } + + switch (type) { + case CISCO_TYPE_SLARP: + isdn_net_ciscohdlck_slarp_in(lp, skb); + goto out_free; + case CISCO_TYPE_CDP: + if (lp->cisco_debserint) + printk(KERN_DEBUG "%s: Received CDP packet. use " + "\"no cdp enable\" on cisco.\n", lp->name); + goto out_free; + default: + /* no special cisco protocol */ + skb->protocol = htons(type); + netif_rx(skb); + return; + } + + out_free: + kfree_skb(skb); +} + +/* + * Got a packet from ISDN-Channel. + */ +static void +isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) +{ + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *olp = lp; /* original 'lp' */ +#ifdef CONFIG_ISDN_X25 + struct concap_proto *cprot = lp -> netdev -> cprot; +#endif + lp->transcount += skb->len; + + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + if (lp->master) { + /* Bundling: If device is a slave-device, deliver to master, also + * handle master's statistics and hangup-timeout + */ + ndev = lp->master; + lp = (isdn_net_local *) ndev->priv; + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + } + skb->dev = ndev; + skb->pkt_type = PACKET_HOST; + skb->mac.raw = skb->data; +#ifdef ISDN_DEBUG_NET_DUMP + isdn_dumppkt("R:", skb->data, skb->len, 40); +#endif + switch (lp->p_encap) { + case ISDN_NET_ENCAP_ETHER: + /* Ethernet over ISDN */ + olp->huptimer = 0; + lp->huptimer = 0; + skb->protocol = isdn_net_type_trans(skb, ndev); + break; + case ISDN_NET_ENCAP_UIHDLC: + /* HDLC with UI-frame (for ispa with -h1 option) */ + olp->huptimer = 0; + lp->huptimer = 0; + skb_pull(skb, 2); + /* Fall through */ + case ISDN_NET_ENCAP_RAWIP: + /* RAW-IP without MAC-Header */ + olp->huptimer = 0; + lp->huptimer = 0; + skb->protocol = htons(ETH_P_IP); + break; + case ISDN_NET_ENCAP_CISCOHDLCK: + isdn_net_ciscohdlck_receive(lp, skb); + return; + case ISDN_NET_ENCAP_CISCOHDLC: + /* CISCO-HDLC IP with type field and fake I-frame-header */ + skb_pull(skb, 2); + /* Fall through */ + case ISDN_NET_ENCAP_IPTYP: + /* IP with type field */ + olp->huptimer = 0; + lp->huptimer = 0; + skb->protocol = *(unsigned short *) &(skb->data[0]); + skb_pull(skb, 2); + if (*(unsigned short *) skb->data == 0xFFFF) + skb->protocol = htons(ETH_P_802_3); + break; +#ifdef CONFIG_ISDN_PPP + case ISDN_NET_ENCAP_SYNCPPP: + /* huptimer is done in isdn_ppp_push_higher */ + isdn_ppp_receive(lp->netdev, olp, skb); + return; +#endif + + default: +#ifdef CONFIG_ISDN_X25 + /* try if there are generic sync_device receiver routines */ + if(cprot) if(cprot -> pops) + if( cprot -> pops -> data_ind){ + cprot -> pops -> data_ind(cprot,skb); + return; + }; +#endif /* CONFIG_ISDN_X25 */ + printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", + lp->name); + kfree_skb(skb); + return; + } + netif_rx(skb); + return; } -struct isdn_netif_ops isdn_rawip_ops = { - .hard_start_xmit = isdn_net_start_xmit, - .flags = IFF_NOARP | IFF_POINTOPOINT, - .type = ARPHRD_PPP, - .receive = isdn_rawip_receive, -}; +/* + * A packet arrived via ISDN. Search interface-chain for a corresponding + * interface. If found, deliver packet to receiver-function and return 1, + * else return 0. + */ +int +isdn_net_rcv_skb(int idx, struct sk_buff *skb) +{ + isdn_net_dev *p = dev->rx_netdev[idx]; + + if (p) { + isdn_net_local *lp = p->local; + if ((lp->flags & ISDN_NET_CONNECTED) && + (!lp->dialstate)) { + isdn_net_receive(&p->dev, skb); + return 1; + } + } + return 0; +} + +static int +my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ + struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); + + /* + * Set the protocol type. For a packet of type ETH_P_802_3 we + * put the length here instead. It is up to the 802.2 layer to + * carry protocol information. + */ + + if (type != ETH_P_802_3) + eth->h_proto = htons(type); + else + eth->h_proto = htons(len); + + /* + * Set the source hardware address. + */ + if (saddr) + memcpy(eth->h_source, saddr, dev->addr_len); + else + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + + /* + * Anyway, the loopback-device should never use this function... + */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + memset(eth->h_dest, 0, dev->addr_len); + return ETH_HLEN /*(dev->hard_header_len)*/; + } + if (daddr) { + memcpy(eth->h_dest, daddr, dev->addr_len); + return ETH_HLEN /*dev->hard_header_len*/; + } + return -ETH_HLEN /*dev->hard_header_len*/; +} + +/* + * build an header + * depends on encaps that is being used. + */ + +static int +isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, + void *daddr, void *saddr, unsigned plen) +{ + isdn_net_local *lp = dev->priv; + unsigned char *p; + ushort len = 0; + + switch (lp->p_encap) { + case ISDN_NET_ENCAP_ETHER: + len = my_eth_header(skb, dev, type, daddr, saddr, plen); + break; +#ifdef CONFIG_ISDN_PPP + case ISDN_NET_ENCAP_SYNCPPP: + /* stick on a fake header to keep fragmentation code happy. */ + len = IPPP_MAX_HEADER; + skb_push(skb,len); + break; +#endif + case ISDN_NET_ENCAP_RAWIP: + printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n"); + len = 0; + break; + case ISDN_NET_ENCAP_IPTYP: + /* ethernet type field */ + *((ushort *) skb_push(skb, 2)) = htons(type); + len = 2; + break; + case ISDN_NET_ENCAP_UIHDLC: + /* HDLC with UI-Frames (for ispa with -h1 option) */ + *((ushort *) skb_push(skb, 2)) = htons(0x0103); + len = 2; + break; + case ISDN_NET_ENCAP_CISCOHDLC: + case ISDN_NET_ENCAP_CISCOHDLCK: + p = skb_push(skb, 4); + p += put_u8 (p, CISCO_ADDR_UNICAST); + p += put_u8 (p, CISCO_CTRL); + p += put_u16(p, type); + len = 4; + break; +#ifdef CONFIG_ISDN_X25 + default: + /* try if there are generic concap protocol routines */ + if( lp-> netdev -> cprot ){ + printk(KERN_WARNING "isdn_net_header called with concap_proto!\n"); + len = 0; + break; + } + break; +#endif /* CONFIG_ISDN_X25 */ + } + return len; +} + +/* We don't need to send arp, because we have point-to-point connections. */ +static int +isdn_net_rebuild_header(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + isdn_net_local *lp = dev->priv; + int ret = 0; + + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { + struct ethhdr *eth = (struct ethhdr *) skb->data; + + /* + * Only ARP/IP is currently supported + */ + + if (eth->h_proto != htons(ETH_P_IP)) { + printk(KERN_WARNING + "isdn_net: %s don't know how to resolve type %d addresses?\n", + dev->name, (int) eth->h_proto); + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + return 0; + } + /* + * Try to get ARP to resolve the header. + */ +#ifdef CONFIG_INET + ret = arp_find(eth->h_dest, skb); +#endif + } + return ret; +} -// ISDN_NET_ENCAP_ETHER -// Ethernet over ISDN -// ====================================================================== +/* + * Interface-setup. (just after registering a new interface) + */ +static int +isdn_net_init(struct net_device *ndev) +{ + ushort max_hlhdr_len = 0; + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + int drvidx, i; + + ether_setup(ndev); + lp->org_hhc = ndev->hard_header_cache; + lp->org_hcu = ndev->header_cache_update; + + /* Setup the generic properties */ + + ndev->hard_header = NULL; + ndev->hard_header_cache = NULL; + ndev->header_cache_update = NULL; + ndev->mtu = 1500; + ndev->flags = IFF_NOARP|IFF_POINTOPOINT; + ndev->type = ARPHRD_ETHER; + ndev->addr_len = ETH_ALEN; + + /* for clients with MPPP maybe higher values better */ + ndev->tx_queue_len = 30; + + for (i = 0; i < ETH_ALEN; i++) + ndev->broadcast[i] = 0xff; + + /* The ISDN-specific entries in the device structure. */ + ndev->open = &isdn_net_open; + ndev->hard_start_xmit = &isdn_net_start_xmit; + + /* + * up till binding we ask the protocol layer to reserve as much + * as we might need for HL layer + */ + + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) + if (dev->drv[drvidx]) + if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen) + max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; + + ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; + ndev->stop = &isdn_net_close; + ndev->get_stats = &isdn_net_get_stats; + ndev->rebuild_header = &isdn_net_rebuild_header; + ndev->do_ioctl = NULL; + return 0; +} + +static void +isdn_net_swapbind(int drvidx) +{ + isdn_net_dev *p; + +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx); +#endif + p = dev->netdev; + while (p) { + if (p->local->pre_device == drvidx) + switch (p->local->pre_channel) { + case 0: + p->local->pre_channel = 1; + break; + case 1: + p->local->pre_channel = 0; + break; + } + p = (isdn_net_dev *) p->next; + } +} static void -isdn_ether_receive(isdn_net_local *lp, isdn_net_dev *idev, - struct sk_buff *skb) +isdn_net_swap_usage(int i1, int i2) +{ + int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE; + int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE; + +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2); +#endif + dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE; + dev->usage[i1] |= u2; + dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE; + dev->usage[i2] |= u1; + isdn_info_update(); +} + +/* + * An incoming call-request has arrived. + * Search the interface-chain for an appropriate interface. + * If found, connect the interface to the ISDN-channel and initiate + * D- and B-Channel-setup. If secure-flag is set, accept only + * configured phone-numbers. If callback-flag is set, initiate + * callback-dialing. + * + * Return-Value: 0 = No appropriate interface for this call. + * 1 = Call accepted + * 2 = Reject call, wait cbdelay, then call back + * 3 = Reject call + * 4 = Wait cbdelay, then call back + * 5 = No appropriate interface for this call, + * would eventually match if CID was longer. + */ + +int +isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) { - isdn_netif_rx(idev, skb, eth_type_trans(skb, &lp->dev)); + char *eaz; + int si1; + int si2; + int ematch; + int wret; + int swapped; + int sidx = 0; + u_long flags; + isdn_net_dev *p; + isdn_net_phone *n; + char nr[32]; + char *my_eaz; + + /* Search name in netdev-chain */ + if (!setup->phone[0]) { + nr[0] = '0'; + nr[1] = '\0'; + printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); + } else + strcpy(nr, setup->phone); + si1 = (int) setup->si1; + si2 = (int) setup->si2; + if (!setup->eazmsn[0]) { + printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); + eaz = "0"; + } else + eaz = setup->eazmsn; + if (dev->net_verbose > 1) + printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); + /* Accept DATA and VOICE calls at this stage + * local eaz is checked later for allowed call types + */ + if ((si1 != 7) && (si1 != 1)) { + if (dev->net_verbose > 1) + printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n"); + return 0; + } + n = (isdn_net_phone *) 0; + p = dev->netdev; + ematch = wret = swapped = 0; +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, + dev->usage[idx]); +#endif + while (p) { + int matchret; + isdn_net_local *lp = p->local; + + /* If last check has triggered as binding-swap, revert it */ + switch (swapped) { + case 2: + isdn_net_swap_usage(idx, sidx); + /* fall through */ + case 1: + isdn_net_swapbind(di); + break; + } + swapped = 0; + /* check acceptable call types for DOV */ + my_eaz = isdn_map_eaz2msn(lp->msn, di); + if (si1 == 1) { /* it's a DOV call, check if we allow it */ + if (*my_eaz == 'v' || *my_eaz == 'V' || + *my_eaz == 'b' || *my_eaz == 'B') + my_eaz++; /* skip to allow a match */ + else + my_eaz = 0; /* force non match */ + } else { /* it's a DATA call, check if we allow it */ + if (*my_eaz == 'b' || *my_eaz == 'B') + my_eaz++; /* skip to allow a match */ + } + if (my_eaz) + matchret = isdn_msncmp(eaz, my_eaz); + else + matchret = 1; + if (!matchret) + ematch = 1; + + /* Remember if more numbers eventually can match */ + if (matchret > wret) + wret = matchret; +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", + lp->name, lp->msn, lp->flags, lp->dialstate); +#endif + if ((!matchret) && /* EAZ is matching */ + (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ + (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ + ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ + (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ + ))) + { +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", + lp->pre_device, lp->pre_channel); +#endif + if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) { + if ((lp->pre_channel != ch) || + (lp->pre_device != di)) { + /* Here we got a problem: + * If using an ICN-Card, an incoming call is always signaled on + * on the first channel of the card, if both channels are + * down. However this channel may be bound exclusive. If the + * second channel is free, this call should be accepted. + * The solution is horribly but it runs, so what: + * We exchange the exclusive bindings of the two channels, the + * corresponding variables in the interface-structs. + */ + if (ch == 0) { + sidx = isdn_dc2minor(di, 1); +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: ch is 0\n"); +#endif + if (USG_NONE(dev->usage[sidx])) { + /* Second Channel is free, now see if it is bound + * exclusive too. */ + if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) { +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n"); +#endif + /* Yes, swap bindings only, if the original + * binding is bound to channel 1 of this driver */ + if ((lp->pre_device == di) && + (lp->pre_channel == 1)) { + isdn_net_swapbind(di); + swapped = 1; + } else { + /* ... else iterate next device */ + p = (isdn_net_dev *) p->next; + continue; + } + } else { +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n"); +#endif + /* No, swap always and swap excl-usage also */ + isdn_net_swap_usage(idx, sidx); + isdn_net_swapbind(di); + swapped = 2; + } + /* Now check for exclusive binding again */ +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: final check\n"); +#endif + if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) && + ((lp->pre_channel != ch) || + (lp->pre_device != di))) { +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: final check failed\n"); +#endif + p = (isdn_net_dev *) p->next; + continue; + } + } + } else { + /* We are already on the second channel, so nothing to do */ +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: already on 2nd channel\n"); +#endif + } + } + } +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: match2\n"); +#endif + n = lp->phone[0]; + if (lp->flags & ISDN_NET_SECURE) { + while (n) { + if (!isdn_msncmp(nr, n->num)) + break; + n = (isdn_net_phone *) n->next; + } + } + if (n || (!(lp->flags & ISDN_NET_SECURE))) { +#ifdef ISDN_DEBUG_NET_ICALL + printk(KERN_DEBUG "n_fi: match3\n"); +#endif + /* matching interface found */ + + /* + * Is the state STOPPED? + * If so, no dialin is allowed, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", + lp->name); + return 3; + } + /* + * Is the interface up? + * If not, reject the call actively. + */ + if (!isdn_net_device_started(p)) { + printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", + lp->name); + return 3; + } + /* Interface is up, now see if it's a slave. If so, see if + * it's master and parent slave is online. If not, reject the call. + */ + if (lp->master) { + isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; + printk(KERN_DEBUG "ICALLslv: %s\n", lp->name); + printk(KERN_DEBUG "master=%s\n", mlp->name); + if (mlp->flags & ISDN_NET_CONNECTED) { + printk(KERN_DEBUG "master online\n"); + /* Master is online, find parent-slave (master if first slave) */ + while (mlp->slave) { + if ((isdn_net_local *) mlp->slave->priv == lp) + break; + mlp = (isdn_net_local *) mlp->slave->priv; + } + } else + printk(KERN_DEBUG "master offline\n"); + /* Found parent, if it's offline iterate next device */ + printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED); + if (!(mlp->flags & ISDN_NET_CONNECTED)) { + p = (isdn_net_dev *) p->next; + continue; + } + } + if (lp->flags & ISDN_NET_CALLBACK) { + int chi; + /* + * Is the state MANUAL? + * If so, no callback can be made, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", + lp->name); + return 3; + } + printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", + lp->name, nr, eaz); + if (lp->phone[1]) { + /* Grab a free ISDN-Channel */ + spin_lock_irqsave(&dev->lock, flags); + if ((chi = + isdn_get_free_channel( + ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel, + lp->msn) + ) < 0) { + + printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; + } + /* Setup dialstate. */ + lp->dtimer = 0; + lp->dialstate = 11; + /* Connect interface with channel */ + isdn_net_bind_channel(lp, chi); +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (isdn_ppp_bind(lp) < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_unbind_channel(lp); + return 0; + } +#endif + spin_unlock_irqrestore(&dev->lock, flags); + /* Initiate dialing by returning 2 or 4 */ + return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; + } else + printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name); + return 0; + } else { + printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr, + eaz); + /* if this interface is dialing, it does it probably on a different + device, so free this device */ + if ((lp->dialstate == 4) || (lp->dialstate == 12)) { +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); +#endif + isdn_net_lp_disconnected(lp); + isdn_free_channel(lp->isdn_device, lp->isdn_channel, + ISDN_USAGE_NET); + } + spin_lock_irqsave(&dev->lock, flags); + dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; + dev->usage[idx] |= ISDN_USAGE_NET; + strcpy(dev->num[idx], nr); + isdn_info_update(); + dev->st_netdev[idx] = lp->netdev; + lp->isdn_device = di; + lp->isdn_channel = ch; + lp->ppp_slot = -1; + lp->flags |= ISDN_NET_CONNECTED; + lp->dialstate = 7; + lp->dtimer = 0; + lp->outgoing = 0; + lp->huptimer = 0; + lp->hupflags |= ISDN_WAITCHARGE; + lp->hupflags &= ~ISDN_HAVECHARGE; +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { + if (isdn_ppp_bind(lp) < 0) { + isdn_net_unbind_channel(lp); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; + } + } +#endif + spin_unlock_irqrestore(&dev->lock, flags); + return 1; + } + } + } + p = (isdn_net_dev *) p->next; + } + /* If none of configured EAZ/MSN matched and not verbose, be silent */ + if (!ematch || dev->net_verbose) + printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz); + return (wret == 2)?5:0; } +/* + * Search list of net-interfaces for an interface with given name. + */ +isdn_net_dev * +isdn_net_findif(char *name) +{ + isdn_net_dev *p = dev->netdev; + + while (p) { + if (!strcmp(p->local->name, name)) + return p; + p = (isdn_net_dev *) p->next; + } + return (isdn_net_dev *) NULL; +} + +/* + * Force a net-interface to dial out. + * This is called from the userlevel-routine below or + * from isdn_net_start_xmit(). + */ +int +isdn_net_force_dial_lp(isdn_net_local * lp) +{ + if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) { + int chi; + if (lp->phone[1]) { + ulong flags; + + /* Grab a free ISDN-Channel */ + spin_lock_irqsave(&dev->lock, flags); + if ((chi = isdn_get_free_channel( + ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel, + lp->msn)) < 0) { + printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); + spin_unlock_irqrestore(&dev->lock, flags); + return -EAGAIN; + } + lp->dialstate = 1; + /* Connect interface with channel */ + isdn_net_bind_channel(lp, chi); +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (isdn_ppp_bind(lp) < 0) { + isdn_net_unbind_channel(lp); + spin_unlock_irqrestore(&dev->lock, flags); + return -EAGAIN; + } +#endif + /* Initiate dialing */ + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_dial(); + return 0; + } else + return -EINVAL; + } else + return -EBUSY; +} + +/* + * This is called from certain upper protocol layers (multilink ppp + * and x25iface encapsulation module) that want to initiate dialing + * themselves. + */ +int +isdn_net_dial_req(isdn_net_local * lp) +{ + /* is there a better error code? */ + if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY; + + return isdn_net_force_dial_lp(lp); +} + +/* + * Force a net-interface to dial out. + * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). + */ +int +isdn_net_force_dial(char *name) +{ + isdn_net_dev *p = isdn_net_findif(name); + + if (!p) + return -ENODEV; + return (isdn_net_force_dial_lp(p->local)); +} + +/* + * Allocate a new network-interface and initialize its data structures. + */ +char * +isdn_net_new(char *name, struct net_device *master) +{ + isdn_net_dev *netdev; + + /* Avoid creating an existing interface */ + if (isdn_net_findif(name)) { + printk(KERN_WARNING "isdn_net: interface %s already exists\n", name); + return NULL; + } + if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { + printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); + return NULL; + } + memset(netdev, 0, sizeof(isdn_net_dev)); + if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) { + printk(KERN_WARNING "isdn_net: Could not allocate device locals\n"); + kfree(netdev); + return NULL; + } + memset(netdev->local, 0, sizeof(isdn_net_local)); + if (name == NULL) + strcpy(netdev->local->name, " "); + else + strcpy(netdev->local->name, name); + strcpy(netdev->dev.name, netdev->local->name); + netdev->dev.priv = netdev->local; + netdev->dev.init = isdn_net_init; + netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP; + if (master) { + /* Device shall be a slave */ + struct net_device *p = (((isdn_net_local *) master->priv)->slave); + struct net_device *q = master; + + netdev->local->master = master; + /* Put device at end of slave-chain */ + while (p) { + q = p; + p = (((isdn_net_local *) p->priv)->slave); + } + ((isdn_net_local *) q->priv)->slave = &(netdev->dev); + } else { + /* Device shall be a master */ + /* + * Watchdog timer (currently) for master only. + */ + netdev->dev.tx_timeout = isdn_net_tx_timeout; + netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT; + if (register_netdev(&netdev->dev) != 0) { + printk(KERN_WARNING "isdn_net: Could not register net-device\n"); + kfree(netdev->local); + kfree(netdev); + return NULL; + } + } + netdev->local->magic = ISDN_NET_MAGIC; + + netdev->queue = netdev->local; + spin_lock_init(&netdev->queue_lock); + + netdev->local->last = netdev->local; + netdev->local->netdev = netdev; + netdev->local->next = netdev->local; + + INIT_WORK(&netdev->local->tqueue, (void *)(void *) isdn_net_softint, netdev->local); + spin_lock_init(&netdev->local->xmit_lock); + + netdev->local->isdn_device = -1; + netdev->local->isdn_channel = -1; + netdev->local->pre_device = -1; + netdev->local->pre_channel = -1; + netdev->local->exclusive = -1; + netdev->local->ppp_slot = -1; + netdev->local->pppbind = -1; + skb_queue_head_init(&netdev->local->super_tx_queue); + netdev->local->l2_proto = ISDN_PROTO_L2_X75I; + netdev->local->l3_proto = ISDN_PROTO_L3_TRANS; + netdev->local->triggercps = 6000; + netdev->local->slavedelay = 10 * HZ; + netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ + netdev->local->onhtime = 10; /* Default hangup-time for saving costs + of those who forget configuring this */ + netdev->local->dialmax = 1; + netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */ + netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */ + netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */ + netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ + netdev->local->dialstarted = 0; /* Jiffies of last dial-start */ + netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ + + /* Put into to netdev-chain */ + netdev->next = (void *) dev->netdev; + dev->netdev = netdev; + return netdev->dev.name; +} + +char * +isdn_net_newslave(char *parm) +{ + char *p = strchr(parm, ','); + isdn_net_dev *n; + char newname[10]; + + if (p) { + /* Slave-Name MUST not be empty */ + if (!strlen(p + 1)) + return NULL; + strcpy(newname, p + 1); + *p = 0; + /* Master must already exist */ + if (!(n = isdn_net_findif(parm))) + return NULL; + /* Master must be a real interface, not a slave */ + if (n->local->master) + return NULL; + /* Master must not be started yet */ + if (isdn_net_device_started(n)) + return NULL; + return (isdn_net_new(newname, &(n->dev))); + } + return NULL; +} + +/* + * Set interface-parameters. + * Always set all parameters, so the user-level application is responsible + * for not overwriting existing setups. It has to get the current + * setup first, if only selected parameters are to be changed. + */ +int +isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) +{ + isdn_net_dev *p = isdn_net_findif(cfg->name); + ulong features; + int i; + int drvidx; + int chidx; + char drvid[25]; + + if (p) { + isdn_net_local *lp = p->local; + + /* See if any registered driver supports the features we want */ + features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) | + ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT); + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (dev->drv[i]) + if ((dev->drv[i]->interface->features & features) == features) + break; + if (i == ISDN_MAX_DRIVERS) { + printk(KERN_WARNING "isdn_net: No driver with selected features\n"); + return -ENODEV; + } + if (lp->p_encap != cfg->p_encap){ +#ifdef CONFIG_ISDN_X25 + struct concap_proto * cprot = p -> cprot; +#endif + if (isdn_net_device_started(p)) { + printk(KERN_WARNING "%s: cannot change encap when if is up\n", + lp->name); + return -EBUSY; + } +#ifdef CONFIG_ISDN_X25 + if( cprot && cprot -> pops ) + cprot -> pops -> proto_del ( cprot ); + p -> cprot = NULL; + lp -> dops = NULL; + /* ... , prepare for configuration of new one ... */ + switch ( cfg -> p_encap ){ + case ISDN_NET_ENCAP_X25IFACE: + lp -> dops = &isdn_concap_reliable_dl_dops; + } + /* ... and allocate new one ... */ + p -> cprot = isdn_concap_new( cfg -> p_encap ); + /* p -> cprot == NULL now if p_encap is not supported + by means of the concap_proto mechanism */ + /* the protocol is not configured yet; this will + happen later when isdn_net_reset() is called */ +#endif + } + switch ( cfg->p_encap ) { + case ISDN_NET_ENCAP_SYNCPPP: +#ifndef CONFIG_ISDN_PPP + printk(KERN_WARNING "%s: SyncPPP support not configured\n", + lp->name); + return -EINVAL; +#else + p->dev.type = ARPHRD_PPP; /* change ARP type */ + p->dev.addr_len = 0; + p->dev.do_ioctl = isdn_ppp_dev_ioctl; +#endif + break; + case ISDN_NET_ENCAP_X25IFACE: +#ifndef CONFIG_ISDN_X25 + printk(KERN_WARNING "%s: isdn-x25 support not configured\n", + p->local->name); + return -EINVAL; +#else + p->dev.type = ARPHRD_X25; /* change ARP type */ + p->dev.addr_len = 0; +#endif + break; + case ISDN_NET_ENCAP_CISCOHDLCK: + p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl; + break; + default: + if( cfg->p_encap >= 0 && + cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP ) + break; + printk(KERN_WARNING + "%s: encapsulation protocol %d not supported\n", + p->local->name, cfg->p_encap); + return -EINVAL; + } + if (strlen(cfg->drvid)) { + /* A bind has been requested ... */ + char *c, + *e; + + drvidx = -1; + chidx = -1; + strcpy(drvid, cfg->drvid); + if ((c = strchr(drvid, ','))) { + /* The channel-number is appended to the driver-Id with a comma */ + chidx = (int) simple_strtoul(c + 1, &e, 10); + if (e == c) + chidx = -1; + *c = '\0'; + } + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + /* Lookup driver-Id in array */ + if (!(strcmp(dev->drvid[i], drvid))) { + drvidx = i; + break; + } + if ((drvidx == -1) || (chidx == -1)) + /* Either driver-Id or channel-number invalid */ + return -ENODEV; + } else { + /* Parameters are valid, so get them */ + drvidx = lp->pre_device; + chidx = lp->pre_channel; + } + if (cfg->exclusive > 0) { + unsigned long flags; + + /* If binding is exclusive, try to grab the channel */ + spin_lock_irqsave(&dev->lock, flags); + if ((i = isdn_get_free_channel(ISDN_USAGE_NET, + lp->l2_proto, lp->l3_proto, drvidx, + chidx, lp->msn)) < 0) { + /* Grab failed, because desired channel is in use */ + lp->exclusive = -1; + spin_unlock_irqrestore(&dev->lock, flags); + return -EBUSY; + } + /* All went ok, so update isdninfo */ + dev->usage[i] = ISDN_USAGE_EXCLUSIVE; + isdn_info_update(); + spin_unlock_irqrestore(&dev->lock, flags); + lp->exclusive = i; + } else { + /* Non-exclusive binding or unbind. */ + lp->exclusive = -1; + if ((lp->pre_device != -1) && (cfg->exclusive == -1)) { + isdn_unexclusive_channel(lp->pre_device, lp->pre_channel); + isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET); + drvidx = -1; + chidx = -1; + } + } + strcpy(lp->msn, cfg->eaz); + lp->pre_device = drvidx; + lp->pre_channel = chidx; + lp->onhtime = cfg->onhtime; + lp->charge = cfg->charge; + lp->l2_proto = cfg->l2_proto; + lp->l3_proto = cfg->l3_proto; + lp->cbdelay = cfg->cbdelay; + lp->dialmax = cfg->dialmax; + lp->triggercps = cfg->triggercps; + lp->slavedelay = cfg->slavedelay * HZ; + lp->pppbind = cfg->pppbind; + lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; + lp->dialwait = cfg->dialwait * HZ; + if (cfg->secure) + lp->flags |= ISDN_NET_SECURE; + else + lp->flags &= ~ISDN_NET_SECURE; + if (cfg->cbhup) + lp->flags |= ISDN_NET_CBHUP; + else + lp->flags &= ~ISDN_NET_CBHUP; + switch (cfg->callback) { + case 0: + lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT); + break; + case 1: + lp->flags |= ISDN_NET_CALLBACK; + lp->flags &= ~ISDN_NET_CBOUT; + break; + case 2: + lp->flags |= ISDN_NET_CBOUT; + lp->flags &= ~ISDN_NET_CALLBACK; + break; + } + lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */ + if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) { + /* old isdnctrl version, where only 0 or 1 is given */ + printk(KERN_WARNING + "Old isdnctrl version detected! Please update.\n"); + lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */ + } + else { + lp->flags |= cfg->dialmode; /* turn on selected bits */ + } + if (cfg->chargehup) + lp->hupflags |= ISDN_CHARGEHUP; + else + lp->hupflags &= ~ISDN_CHARGEHUP; + if (cfg->ihup) + lp->hupflags |= ISDN_INHUP; + else + lp->hupflags &= ~ISDN_INHUP; + if (cfg->chargeint > 10) { + lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE; + lp->chargeint = cfg->chargeint * HZ; + } + if (cfg->p_encap != lp->p_encap) { + if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { + p->dev.hard_header = NULL; + p->dev.hard_header_cache = NULL; + p->dev.header_cache_update = NULL; + p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; + } else { + p->dev.hard_header = isdn_net_header; + if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { + p->dev.hard_header_cache = lp->org_hhc; + p->dev.header_cache_update = lp->org_hcu; + p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; + } else { + p->dev.hard_header_cache = NULL; + p->dev.header_cache_update = NULL; + p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; + } + } + } + lp->p_encap = cfg->p_encap; + return 0; + } + return -ENODEV; +} + +/* + * Perform get-interface-parameters.ioctl + */ +int +isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) +{ + isdn_net_dev *p = isdn_net_findif(cfg->name); + + if (p) { + isdn_net_local *lp = p->local; + + strcpy(cfg->eaz, lp->msn); + cfg->exclusive = lp->exclusive; + if (lp->pre_device >= 0) { + sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device], + lp->pre_channel); + } else + cfg->drvid[0] = '\0'; + cfg->onhtime = lp->onhtime; + cfg->charge = lp->charge; + cfg->l2_proto = lp->l2_proto; + cfg->l3_proto = lp->l3_proto; + cfg->p_encap = lp->p_encap; + cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0; + cfg->callback = 0; + if (lp->flags & ISDN_NET_CALLBACK) + cfg->callback = 1; + if (lp->flags & ISDN_NET_CBOUT) + cfg->callback = 2; + cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0; + cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK; + cfg->chargehup = (lp->hupflags & 4) ? 1 : 0; + cfg->ihup = (lp->hupflags & 8) ? 1 : 0; + cfg->cbdelay = lp->cbdelay; + cfg->dialmax = lp->dialmax; + cfg->triggercps = lp->triggercps; + cfg->slavedelay = lp->slavedelay / HZ; + cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ? + (lp->chargeint / HZ) : 0; + cfg->pppbind = lp->pppbind; + cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1; + cfg->dialwait = lp->dialwait / HZ; + if (lp->slave) + strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name); + else + cfg->slave[0] = '\0'; + if (lp->master) + strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name); + else + cfg->master[0] = '\0'; + return 0; + } + return -ENODEV; +} + +/* + * Add a phone-number to an interface. + */ +int +isdn_net_addphone(isdn_net_ioctl_phone * phone) +{ + isdn_net_dev *p = isdn_net_findif(phone->name); + isdn_net_phone *n; + + if (p) { + if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL))) + return -ENOMEM; + strcpy(n->num, phone->phone); + n->next = p->local->phone[phone->outgoing & 1]; + p->local->phone[phone->outgoing & 1] = n; + return 0; + } + return -ENODEV; +} + +/* + * Copy a string of all phone-numbers of an interface to user space. + * This might sleep and must be called with the isdn semaphore down. + */ +int +isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) +{ + isdn_net_dev *p = isdn_net_findif(phone->name); + int inout = phone->outgoing & 1; + int more = 0; + int count = 0; + isdn_net_phone *n; + + if (!p) + return -ENODEV; + inout &= 1; + for (n = p->local->phone[inout]; n; n = n->next) { + if (more) { + put_user(' ', phones++); + count++; + } + if (copy_to_user(phones, n->num, strlen(n->num) + 1)) { + return -EFAULT; + } + phones += strlen(n->num); + count += strlen(n->num); + more = 1; + } + put_user(0, phones); + count++; + return count; +} + +/* + * Copy a string containing the peer's phone number of a connected interface + * to user space. + */ +int +isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer) +{ + isdn_net_dev *p = isdn_net_findif(phone->name); + int ch, dv, idx; + + if (!p) return -ENODEV; + /* + * Theoretical race: while this executes, the remote number might + * become invalid (hang up) or change (new connection), resulting + * in (partially) wrong number copied to user. This race + * currently ignored. + */ + ch = p->local->isdn_channel; + dv = p->local->isdn_device; + if(ch<0 && dv<0) return -ENOTCONN; + idx = isdn_dc2minor(dv, ch); + if (idx<0) return -ENODEV; + /* for pre-bound channels, we need this extra check */ + if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN; + strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN); + phone->outgoing=USG_OUTGOING(dev->usage[idx]); + if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT; + return 0; +} +/* + * Delete a phone-number from an interface. + */ +int +isdn_net_delphone(isdn_net_ioctl_phone * phone) +{ + isdn_net_dev *p = isdn_net_findif(phone->name); + int inout = phone->outgoing & 1; + isdn_net_phone *n; + isdn_net_phone *m; + + if (p) { + n = p->local->phone[inout]; + m = NULL; + while (n) { + if (!strcmp(n->num, phone->phone)) { + if (p->local->dial == n) + p->local->dial = n->next; + if (m) + m->next = n->next; + else + p->local->phone[inout] = n->next; + kfree(n); + return 0; + } + m = n; + n = (isdn_net_phone *) n->next; + } + return -EINVAL; + } + return -ENODEV; +} + +/* + * Delete all phone-numbers of an interface. + */ static int -isdn_ether_open(isdn_net_local *lp) +isdn_net_rmallphone(isdn_net_dev * p) { - struct net_device *dev = &lp->dev; - struct in_device *in_dev; + isdn_net_phone *n; + isdn_net_phone *m; int i; - /* Fill in the MAC-level header ... */ - for (i = 0; i < ETH_ALEN; i++) - dev->dev_addr[i] = 0xfc; - in_dev = dev->ip_ptr; - if (in_dev) { - /* any address will do - we take the first */ - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa) - memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); + for (i = 0; i < 2; i++) { + n = p->local->phone[i]; + while (n) { + m = n->next; + kfree(n); + n = m; + } + p->local->phone[i] = NULL; } + p->local->dial = NULL; return 0; } +/* + * Force a hangup of a network-interface. + */ +int +isdn_net_force_hangup(char *name) +{ + isdn_net_dev *p = isdn_net_findif(name); + struct net_device *q; + + if (p) { + if (p->local->isdn_device < 0) + return 1; + q = p->local->slave; + /* If this interface has slaves, do a hangup for them also. */ + while (q) { + isdn_net_hangup(q); + q = (((isdn_net_local *) q->priv)->slave); + } + isdn_net_hangup(&p->dev); + return 0; + } + return -ENODEV; +} + +/* + * Helper-function for isdn_net_rm: Do the real work. + */ static int -isdn_ether_init(isdn_net_local *lp) +isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) { - struct net_device *dev = &lp->dev; + u_long flags; - ether_setup(dev); - dev->tx_queue_len = 10; - dev->hard_header_len += isdn_hard_header_len(); + if (isdn_net_device_started(p)) { + return -EBUSY; + } +#ifdef CONFIG_ISDN_X25 + if( p -> cprot && p -> cprot -> pops ) + p -> cprot -> pops -> proto_del ( p -> cprot ); +#endif + /* Free all phone-entries */ + isdn_net_rmallphone(p); + /* If interface is bound exclusive, free channel-usage */ + if (p->local->exclusive != -1) + isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); + if (p->local->master) { + /* It's a slave-device, so update master's slave-pointer if necessary */ + if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev) + ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; + } else { + /* Unregister only if it's a master-device */ + p->dev.hard_header_cache = p->local->org_hhc; + p->dev.header_cache_update = p->local->org_hcu; + unregister_netdev(&p->dev); + } + /* Unlink device from chain */ + spin_lock_irqsave(&dev->lock, flags); + if (q) + q->next = p->next; + else + dev->netdev = p->next; + if (p->local->slave) { + /* If this interface has a slave, remove it also */ + char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name; + isdn_net_dev *n = dev->netdev; + q = NULL; + while (n) { + if (!strcmp(n->local->name, slavename)) { + spin_unlock_irqrestore(&dev->lock, flags); + isdn_net_realrm(n, q); + spin_lock_irqsave(&dev->lock, flags); + break; + } + q = n; + n = (isdn_net_dev *) n->next; + } + } + spin_unlock_irqrestore(&dev->lock, flags); + /* If no more net-devices remain, disable auto-hangup timer */ + if (dev->netdev == NULL) + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); + kfree(p->local); + kfree(p); return 0; } -struct isdn_netif_ops isdn_ether_ops = { - .hard_start_xmit = isdn_net_start_xmit, - .receive = isdn_ether_receive, - .init = isdn_ether_init, - .open = isdn_ether_open, -}; +/* + * Remove a single network-interface. + */ +int +isdn_net_rm(char *name) +{ + u_long flags; + isdn_net_dev *p; + isdn_net_dev *q; + + /* Search name in netdev-chain */ + spin_lock_irqsave(&dev->lock, flags); + p = dev->netdev; + q = NULL; + while (p) { + if (!strcmp(p->local->name, name)) { + spin_unlock_irqrestore(&dev->lock, flags); + return (isdn_net_realrm(p, q)); + } + q = p; + p = (isdn_net_dev *) p->next; + } + spin_unlock_irqrestore(&dev->lock, flags); + /* If no more net-devices remain, disable auto-hangup timer */ + if (dev->netdev == NULL) + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); + return -ENODEV; +} + +/* + * Remove all network-interfaces + */ +int +isdn_net_rmall(void) +{ + u_long flags; + int ret; + + /* Walk through netdev-chain */ + spin_lock_irqsave(&dev->lock, flags); + while (dev->netdev) { + if (!dev->netdev->local->master) { + /* Remove master-devices only, slaves get removed with their master */ + spin_unlock_irqrestore(&dev->lock, flags); + if ((ret = isdn_net_realrm(dev->netdev, NULL))) { + return ret; + } + spin_lock_irqsave(&dev->lock, flags); + } + } + dev->netdev = NULL; + spin_unlock_irqrestore(&dev->lock, flags); + return 0; +} diff -puN drivers/isdn/i4l/isdn_net.h~i4l drivers/isdn/i4l/isdn_net.h --- 25/drivers/isdn/i4l/isdn_net.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_net.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,15 +1,189 @@ -/* Linux ISDN subsystem, network related functions +/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * header for Linux ISDN subsystem, network related functions (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski + * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg + * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * + */ + + /* Definitions for hupflags: */ +#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */ +#define ISDN_HAVECHARGE 2 /* We know a charge info */ +#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ +#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ +#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ + +/* + * Definitions for Cisco-HDLC header. + */ + +#define CISCO_ADDR_UNICAST 0x0f +#define CISCO_ADDR_BROADCAST 0x8f +#define CISCO_CTRL 0x00 +#define CISCO_TYPE_CDP 0x2000 +#define CISCO_TYPE_SLARP 0x8035 +#define CISCO_SLARP_REQUEST 0 +#define CISCO_SLARP_REPLY 1 +#define CISCO_SLARP_KEEPALIVE 2 + +extern char *isdn_net_new(char *, struct net_device *); +extern char *isdn_net_newslave(char *); +extern int isdn_net_rm(char *); +extern int isdn_net_rmall(void); +extern int isdn_net_stat_callback(int, isdn_ctrl *); +extern int isdn_net_setcfg(isdn_net_ioctl_cfg *); +extern int isdn_net_getcfg(isdn_net_ioctl_cfg *); +extern int isdn_net_addphone(isdn_net_ioctl_phone *); +extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *); +extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *); +extern int isdn_net_delphone(isdn_net_ioctl_phone *); +extern int isdn_net_find_icall(int, int, int, setup_parm *); +extern void isdn_net_hangup(struct net_device *); +extern void isdn_net_dial(void); +extern void isdn_net_autohup(void); +extern int isdn_net_force_hangup(char *); +extern int isdn_net_force_dial(char *); +extern isdn_net_dev *isdn_net_findif(char *); +extern int isdn_net_rcv_skb(int, struct sk_buff *); +extern int isdn_net_dial_req(isdn_net_local *); +extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); +extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); + +#define ISDN_NET_MAX_QUEUE_LENGTH 2 + +/* + * is this particular channel busy? + */ +static __inline__ int isdn_net_lp_busy(isdn_net_local *lp) +{ + if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH) + return 0; + else + return 1; +} + +/* + * For the given net device, this will get a non-busy channel out of the + * corresponding bundle. The returned channel is locked. + */ +static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd) +{ + unsigned long flags; + isdn_net_local *lp; + + spin_lock_irqsave(&nd->queue_lock, flags); + lp = nd->queue; /* get lp on top of queue */ + spin_lock_bh(&nd->queue->xmit_lock); + while (isdn_net_lp_busy(nd->queue)) { + spin_unlock_bh(&nd->queue->xmit_lock); + nd->queue = nd->queue->next; + if (nd->queue == lp) { /* not found -- should never happen */ + lp = NULL; + goto errout; + } + spin_lock_bh(&nd->queue->xmit_lock); + } + lp = nd->queue; + nd->queue = nd->queue->next; +errout: + spin_unlock_irqrestore(&nd->queue_lock, flags); + return lp; +} + +/* + * add a channel to a bundle */ +static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp) +{ + isdn_net_local *lp; + unsigned long flags; + + spin_lock_irqsave(&nd->queue_lock, flags); + + lp = nd->queue; +// printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) nlp:%s(%p) last(%p)\n", +// lp->name, lp, nlp->name, nlp, lp->last); + nlp->last = lp->last; + lp->last->next = nlp; + lp->last = nlp; + nlp->next = lp; + nd->queue = nlp; + + spin_unlock_irqrestore(&nd->queue_lock, flags); +} +/* + * remove a channel from the bundle it belongs to + */ +static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) +{ + isdn_net_local *master_lp = lp; + unsigned long flags; + + if (lp->master) + master_lp = (isdn_net_local *) lp->master->priv; + +// printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", +// lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); + spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); + lp->last->next = lp->next; + lp->next->last = lp->last; + if (master_lp->netdev->queue == lp) { + master_lp->netdev->queue = lp->next; + if (lp->next == lp) { /* last in queue */ + master_lp->netdev->queue = master_lp->netdev->local; + } + } + lp->next = lp->last = lp; /* (re)set own pointers */ +// printk(KERN_DEBUG __FUNCTION__": mndq(%p)\n", +// master_lp->netdev->queue); + spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); +} + +static inline int +put_u8(unsigned char *p, u8 x) +{ + *p = x; + return 1; +} + +static inline int +put_u16(unsigned char *p, u16 x) +{ + *((u16 *)p) = htons(x); + return 2; +} + +static inline int +put_u32(unsigned char *p, u32 x) +{ + *((u32 *)p) = htonl(x); + return 4; +} + +static inline int +get_u8(unsigned char *p, u8 *x) +{ + *x = *p; + return 1; +} + +static inline int +get_u16(unsigned char *p, u16 *x) +{ + *x = ntohs(*((u16 *)p)); + return 2; +} + +static inline int +get_u32(unsigned char *p, u32 *x) +{ + *x = ntohl(*((u32 *)p)); + return 4; +} + -extern struct isdn_netif_ops isdn_iptyp_ops; -extern struct isdn_netif_ops isdn_uihdlc_ops; -extern struct isdn_netif_ops isdn_rawip_ops; -extern struct isdn_netif_ops isdn_ether_ops; diff -puN -L drivers/isdn/i4l/isdn_net_lib.c drivers/isdn/i4l/isdn_net_lib.c~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_net_lib.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,2342 +0,0 @@ -/* Linux ISDN subsystem, network interface support code - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -/* - * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 - * guy@traverse.com.au - * Outgoing calls - looks for a 'V' in first char of dialed number - * Incoming calls - checks first character of eaz as follows: - * Numeric - accept DATA only - original functionality - * 'V' - accept VOICE (DOV) only - * 'B' - accept BOTH DATA and DOV types - * - */ - -/* Locking works as follows: - * - * The configuration of isdn_net_devs works via ioctl on - * /dev/isdnctrl (for legacy reasons). - * All configuration accesses are globally serialized by means of - * the global semaphore &sem. - * - * All other uses of isdn_net_dev will only happen when the corresponding - * struct net_device has been opened. So in the non-config code we can - * rely on the config data not changing under us. - * - * To achieve this, in the "writing" ioctls, that is those which may change - * data, additionally grep the rtnl semaphore and check to make sure - * that the net_device has not been openend ("netif_running()") - * - * isdn_net_dev's are added to the global list "isdn_net_devs" in the - * configuration ioctls, so accesses to that list are protected by - * &sem as well. - * - * Incoming calls are signalled in IRQ context, so we cannot take &sem - * while walking the list of devices. To handle this, we put devices - * onto a "running" list, which is protected by a spin lock and can thus - * be traversed in IRQ context. If a matching isdn_net_dev is found, - * it's ref count shall be incremented, to make sure no racing - * net_device::close() can take it away under us. - */ - -#include -#include -#include -#include -#include -#include -#include "isdn_common.h" -#include "isdn_net_lib.h" -#include "isdn_net.h" -#include "isdn_ppp.h" -#include "isdn_ciscohdlck.h" -#include "isdn_concap.h" - -#define ISDN_NET_TX_TIMEOUT (20*HZ) - -/* All of this configuration code is globally serialized */ - -static DECLARE_MUTEX(sem); -LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */ // FIXME static - -/* Reference counting for net devices (they work on isdn_net_local *, - * but count references to the related isdn_net_dev's as well. - * Basic rule: When state of isdn_net_dev changes from ST_NULL -> sth, - * get a reference, when it changes back to ST_NULL, put it - */ - -static inline void -lp_get(isdn_net_local *lp) -{ - if (atomic_read(&lp->refcnt) < 1) - isdn_BUG(); - - atomic_inc(&lp->refcnt); -} - -static inline void -lp_put(isdn_net_local *lp) -{ - atomic_dec(&lp->refcnt); - - /* the last reference, the list should always remain */ - if (atomic_read(&lp->refcnt) < 1) - isdn_BUG(); -} - -static int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg); -static void isdn_net_tasklet(unsigned long data); -static void isdn_net_dial_timer(unsigned long data); -static int isdn_init_netif(struct net_device *ndev); -static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...); -static int isdn_net_dial(isdn_net_dev *idev); -static int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c); - -static struct fsm isdn_net_fsm; - -enum { - ST_NULL, - ST_OUT_BOUND, - ST_OUT_WAIT_DCONN, - ST_OUT_WAIT_BCONN, - ST_IN_WAIT_DCONN, - ST_IN_WAIT_BCONN, - ST_ACTIVE, - ST_WAIT_DHUP, - ST_WAIT_BEFORE_CB, - ST_OUT_DIAL_WAIT, -}; - -static char *isdn_net_st_str[] = { - "ST_NULL", - "ST_OUT_BOUND", - "ST_OUT_WAIT_DCONN", - "ST_OUT_WAIT_BCONN", - "ST_IN_WAIT_DCONN", - "ST_IN_WAIT_BCONN", - "ST_ACTIVE", - "ST_WAIT_DHUP", - "ST_WAIT_BEFORE_CB", - "ST_OUT_DIAL_WAIT", -}; - -enum { - EV_NET_TIMER_INCOMING, - EV_NET_TIMER_DIAL, - EV_NET_TIMER_DIAL_WAIT, - EV_NET_TIMER_CB_OUT, - EV_NET_TIMER_CB_IN, - EV_NET_TIMER_HUP, - EV_NET_STAT_DCONN, - EV_NET_STAT_BCONN, - EV_NET_STAT_DHUP, - EV_NET_STAT_BHUP, - EV_NET_STAT_CINF, - EV_NET_STAT_BSENT, - EV_NET_DO_DIAL, - EV_NET_DO_CALLBACK, - EV_NET_DO_ACCEPT, -}; - -static char *isdn_net_ev_str[] = { - "EV_NET_TIMER_INCOMING", - "EV_NET_TIMER_DIAL", - "EV_NET_TIMER_DIAL_WAIT", - "EV_NET_TIMER_CB_OUT", - "EV_NET_TIMER_CB_IN", - "EV_NET_TIMER_HUP", - "EV_NET_STAT_DCONN", - "EV_NET_STAT_BCONN", - "EV_NET_STAT_DHUP", - "EV_NET_STAT_BHUP", - "EV_NET_STAT_CINF", - "EV_NET_STAT_BSENT", - "EV_NET_DO_DIAL", - "EV_NET_DO_CALLBACK", - "EV_NET_DO_ACCEPT", -}; - -/* Definitions for hupflags: */ - -#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ -#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ -#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ - -enum { - ST_CHARGE_NULL, - ST_CHARGE_GOT_CINF, /* got a first charge info */ - ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */ -}; - -/* ====================================================================== */ -/* Registration of ISDN network interface types */ -/* ====================================================================== */ - -static struct isdn_netif_ops *isdn_netif_ops[ISDN_NET_ENCAP_NR]; - -int -register_isdn_netif(int encap, struct isdn_netif_ops *ops) -{ - if (encap < 0 || encap >= ISDN_NET_ENCAP_NR) - return -EINVAL; - - if (isdn_netif_ops[encap]) - return -EBUSY; - - isdn_netif_ops[encap] = ops; - - return 0; -} - -/* ====================================================================== */ -/* Helpers */ -/* ====================================================================== */ - -/* Search list of net-interfaces for an interface with given name. */ - -static isdn_net_dev * -isdn_net_findif(char *name) -{ - isdn_net_dev *idev; - - list_for_each_entry(idev, &isdn_net_devs, global_list) { - if (!strcmp(idev->name, name)) - return idev; - } - return NULL; -} - -/* Set up a certain encapsulation */ - -static int -isdn_net_set_encap(isdn_net_local *lp, int encap) -{ - int retval = 0; - - if (lp->p_encap == encap){ - /* nothing to do */ - retval = 0; - goto out; - } - if (netif_running(&lp->dev)) { - retval = -EBUSY; - goto out; - } - if (lp->ops && lp->ops->cleanup) - lp->ops->cleanup(lp); - - if (encap < 0 || encap >= ISDN_NET_ENCAP_NR || - !isdn_netif_ops[encap]) { - lp->p_encap = -1; - lp->ops = NULL; - retval = -EINVAL; - goto out; - } - - lp->p_encap = encap; - lp->ops = isdn_netif_ops[encap]; - - lp->dev.hard_start_xmit = lp->ops->hard_start_xmit; - lp->dev.hard_header = lp->ops->hard_header; - lp->dev.do_ioctl = lp->ops->do_ioctl; - lp->dev.flags = lp->ops->flags; - lp->dev.type = lp->ops->type; - lp->dev.addr_len = lp->ops->addr_len; - if (lp->ops->init) - retval = lp->ops->init(lp); - - if (retval != 0) { - lp->p_encap = -1; - lp->ops = NULL; - } - out: - return retval; -} - -static int -isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg) -{ - isdn_net_local *mlp = idev->mlp; - int retval; - int drvidx = -1; - int chidx = -1; - char drvid[25]; - - strlcpy(drvid, cfg->drvid, sizeof(drvid)); - - if (cfg->exclusive && !strlen(drvid)) { - /* If we want to bind exclusively, need to specify drv/chan */ - retval = -ENODEV; - goto out; - } - if (strlen(drvid)) { - /* A bind has been requested ... */ - char *c = strchr(drvid, ','); - if (!c) { - retval = -ENODEV; - goto out; - } - /* The channel-number is appended to the driver-Id with a comma */ - *c = 0; - chidx = simple_strtol(c + 1, NULL, 10); - drvidx = isdn_drv_lookup(drvid); - if (drvidx == -1 || chidx == -1) { - /* Either driver-Id or channel-number invalid */ - retval = -ENODEV; - goto out; - } - } - if (cfg->exclusive == !!idev->exclusive && - drvidx == idev->pre_device && chidx == idev->pre_channel) { - /* no change */ - retval = 0; - goto out; - } - if (idev->exclusive) { - isdn_slot_free(idev->exclusive); - idev->exclusive = NULL; - } - if (cfg->exclusive) { - /* If binding is exclusive, try to grab the channel */ - idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET | ISDN_USAGE_EXCLUSIVE, - mlp->l2_proto, mlp->l3_proto, drvidx, chidx, cfg->eaz); - if (!idev->exclusive) { - /* Grab failed, because desired channel is in use */ - retval = -EBUSY; - goto out; - } - } - idev->pre_device = drvidx; - idev->pre_channel = chidx; - retval = 0; - out: - return retval; -} - -/* - * Delete all phone-numbers of an interface. - */ -static void -isdn_net_rmallphone(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - struct isdn_net_phone *n; - int i; - - for (i = 0; i < 2; i++) { - while (!list_empty(&mlp->phone[i])) { - n = list_entry(mlp->phone[i].next, struct isdn_net_phone, list); - list_del(&n->list); - kfree(n); - } - } -} - -/* ====================================================================== */ -/* /dev/isdnctrl net ioctl interface */ -/* ====================================================================== */ - -/* - * Allocate a new network-interface and initialize its data structures - */ -static int -isdn_net_addif(char *name, isdn_net_local *mlp) -{ - int retval; - struct net_device *dev = NULL; - isdn_net_dev *idev; - - /* Avoid creating an existing interface */ - if (isdn_net_findif(name)) - return -EEXIST; - - idev = kmalloc(sizeof(*idev), GFP_KERNEL); - if (!idev) - return -ENOMEM; - - memset(idev, 0, sizeof(*idev)); - strcpy(idev->name, name); - - tasklet_init(&idev->tlet, isdn_net_tasklet, (unsigned long) idev); - skb_queue_head_init(&idev->super_tx_queue); - - idev->isdn_slot = NULL; - idev->pre_device = -1; - idev->pre_channel = -1; - idev->exclusive = NULL; - - idev->pppbind = -1; - - init_timer(&idev->dial_timer); - idev->dial_timer.data = (unsigned long) idev; - idev->dial_timer.function = isdn_net_dial_timer; - - idev->fi.fsm = &isdn_net_fsm; - idev->fi.state = ST_NULL; - idev->fi.debug = 1; - idev->fi.userdata = idev; - idev->fi.printdebug = isdn_net_dev_debug; - - if (!mlp) { - /* Device shall be a master */ - mlp = kmalloc(sizeof(*mlp), GFP_KERNEL); - if (!mlp) - return -ENOMEM; - - memset(mlp, 0, sizeof(*mlp)); - - mlp->magic = ISDN_NET_MAGIC; - INIT_LIST_HEAD(&mlp->slaves); - INIT_LIST_HEAD(&mlp->online); - spin_lock_init(&mlp->xmit_lock); - - mlp->p_encap = -1; - isdn_net_set_encap(mlp, ISDN_NET_ENCAP_RAWIP); - - mlp->l2_proto = ISDN_PROTO_L2_X75I; - mlp->l3_proto = ISDN_PROTO_L3_TRANS; - mlp->triggercps = 6000; - mlp->slavedelay = 10 * HZ; - mlp->hupflags = ISDN_INHUP; - mlp->onhtime = 10; - mlp->dialmax = 1; - mlp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL | ISDN_NET_SECURE; - mlp->cbdelay = 5 * HZ; /* Wait 5 secs before call-back */ - mlp->dialtimeout = 60 * HZ;/* Wait 1 min for connection */ - mlp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ - INIT_LIST_HEAD(&mlp->phone[0]); - INIT_LIST_HEAD(&mlp->phone[1]); - dev = &mlp->dev; - } - idev->mlp = mlp; - list_add_tail(&idev->slaves, &mlp->slaves); - - if (dev) { - strcpy(dev->name, name); - dev->priv = mlp; - dev->init = isdn_init_netif; - SET_MODULE_OWNER(dev); - retval = register_netdev(dev); - if (retval) { - kfree(mlp); - kfree(idev); - return retval; - } - } - list_add(&idev->global_list, &isdn_net_devs); - - return 0; -} - -/* - * Add a new slave interface to an existing one - */ -static int -isdn_net_addslave(char *parm) -{ - char *p = strchr(parm, ','); - isdn_net_dev *idev; - isdn_net_local *mlp; - int retval; - - /* get slave name */ - if (!p || !p[1]) - return -EINVAL; - - *p++ = 0; - - /* find master */ - idev = isdn_net_findif(parm); - if (!idev) - return -ESRCH; - - mlp = idev->mlp; - - rtnl_lock(); - - if (netif_running(&mlp->dev)) { - retval = -EBUSY; - goto out; - } - retval = isdn_net_addif(p, mlp); - out: - rtnl_unlock(); - return retval; -} - -/* - * Delete a single network-interface - */ -static int -isdn_net_dev_delete(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - int retval; - - rtnl_lock(); - - if (netif_running(&mlp->dev)) { - retval = -EBUSY; - goto unlock; - } - isdn_net_set_encap(mlp, -1); - isdn_net_rmallphone(idev); - - if (idev->exclusive) - isdn_slot_free(idev->exclusive); - - list_del(&idev->slaves); - - rtnl_unlock(); - - if (list_empty(&mlp->slaves)) { - unregister_netdev(&mlp->dev); - kfree(mlp); - } - - list_del(&idev->global_list); - kfree(idev); - return 0; - - unlock: - rtnl_unlock(); - return retval; -} - -/* - * Delete a single network-interface - */ -static int -isdn_net_delif(char *name) -{ - /* FIXME: For compatibility, if a master isdn_net_dev is rm'ed, - * kill all slaves, too */ - - isdn_net_dev *idev = isdn_net_findif(name); - - if (!idev) - return -ENODEV; - - return isdn_net_dev_delete(idev); -} - -/* - * Set interface-parameters. - * Always set all parameters, so the user-level application is responsible - * for not overwriting existing setups. It has to get the current - * setup first, if only selected parameters are to be changed. - */ -static int -isdn_net_setcfg(isdn_net_ioctl_cfg *cfg) -{ - isdn_net_dev *idev = isdn_net_findif(cfg->name); - isdn_net_local *mlp; - int retval; - - if (!idev) - return -ENODEV; - - mlp = idev->mlp; - - rtnl_lock(); - - if (netif_running(&mlp->dev)) { - retval = -EBUSY; - goto out; - } - - retval = isdn_net_set_encap(mlp, cfg->p_encap); - if (retval) - goto out; - - retval = isdn_net_bind(idev, cfg); - if (retval) - goto out; - - strlcpy(mlp->msn, cfg->eaz, sizeof(mlp->msn)); - mlp->onhtime = cfg->onhtime; - idev->charge = cfg->charge; - mlp->l2_proto = cfg->l2_proto; - mlp->l3_proto = cfg->l3_proto; - mlp->cbdelay = cfg->cbdelay * HZ / 5; - mlp->dialmax = cfg->dialmax; - mlp->triggercps = cfg->triggercps; - mlp->slavedelay = cfg->slavedelay * HZ; - idev->pppbind = cfg->pppbind; - mlp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; - mlp->dialwait = cfg->dialwait * HZ; - if (cfg->secure) - mlp->flags |= ISDN_NET_SECURE; - else - mlp->flags &= ~ISDN_NET_SECURE; - if (cfg->cbhup) - mlp->flags |= ISDN_NET_CBHUP; - else - mlp->flags &= ~ISDN_NET_CBHUP; - switch (cfg->callback) { - case 0: - mlp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT); - break; - case 1: - mlp->flags |= ISDN_NET_CALLBACK; - mlp->flags &= ~ISDN_NET_CBOUT; - break; - case 2: - mlp->flags |= ISDN_NET_CBOUT; - mlp->flags &= ~ISDN_NET_CALLBACK; - break; - } - mlp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */ - if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) { - retval = -EINVAL; - goto out; - } - - mlp->flags |= cfg->dialmode; /* turn on selected bits */ - if (mlp->flags & ISDN_NET_DM_OFF) - isdn_net_hangup(idev); - - if (cfg->chargehup) - mlp->hupflags |= ISDN_CHARGEHUP; - else - mlp->hupflags &= ~ISDN_CHARGEHUP; - - if (cfg->ihup) - mlp->hupflags |= ISDN_INHUP; - else - mlp->hupflags &= ~ISDN_INHUP; - - if (cfg->chargeint > 10) { - idev->chargeint = cfg->chargeint * HZ; - idev->charge_state = ST_CHARGE_HAVE_CINT; - mlp->hupflags |= ISDN_MANCHARGE; - } - retval = 0; - - out: - rtnl_unlock(); - - return retval; -} - -/* - * Perform get-interface-parameters.ioctl - */ -static int -isdn_net_getcfg(isdn_net_ioctl_cfg *cfg) -{ - isdn_net_dev *idev = isdn_net_findif(cfg->name); - isdn_net_local *mlp; - - if (!idev) - return -ENODEV; - - mlp = idev->mlp; - - strcpy(cfg->eaz, mlp->msn); - cfg->exclusive = !!idev->exclusive; - if (idev->pre_device >= 0) { - sprintf(cfg->drvid, "%s,%d", isdn_drv_drvid(idev->pre_device), - idev->pre_channel); - } else { - cfg->drvid[0] = '\0'; - } - cfg->onhtime = mlp->onhtime; - cfg->charge = idev->charge; - cfg->l2_proto = mlp->l2_proto; - cfg->l3_proto = mlp->l3_proto; - cfg->p_encap = mlp->p_encap; - cfg->secure = (mlp->flags & ISDN_NET_SECURE) ? 1 : 0; - cfg->callback = 0; - if (mlp->flags & ISDN_NET_CALLBACK) - cfg->callback = 1; - if (mlp->flags & ISDN_NET_CBOUT) - cfg->callback = 2; - cfg->cbhup = (mlp->flags & ISDN_NET_CBHUP) ? 1 : 0; - cfg->dialmode = mlp->flags & ISDN_NET_DIALMODE_MASK; - cfg->chargehup = (mlp->hupflags & ISDN_CHARGEHUP) ? 1 : 0; - cfg->ihup = (mlp->hupflags & ISDN_INHUP) ? 1 : 0; - cfg->cbdelay = mlp->cbdelay * 5 / HZ; - cfg->dialmax = mlp->dialmax; - cfg->triggercps = mlp->triggercps; - cfg->slavedelay = mlp->slavedelay / HZ; - cfg->chargeint = (mlp->hupflags & ISDN_CHARGEHUP) ? - (idev->chargeint / HZ) : 0; - cfg->pppbind = idev->pppbind; - cfg->dialtimeout = mlp->dialtimeout >= 0 ? mlp->dialtimeout / HZ : -1; - cfg->dialwait = mlp->dialwait / HZ; - - if (idev->slaves.next != &mlp->slaves) - strcpy(cfg->slave, list_entry(idev->slaves.next, isdn_net_dev, slaves)->name); - else - cfg->slave[0] = '\0'; - if (strcmp(mlp->dev.name, idev->name)) - strcpy(cfg->master, mlp->dev.name); - else - cfg->master[0] = '\0'; - - return 0; -} - -/* - * Add a phone-number to an interface. - */ -static int -isdn_net_addphone(isdn_net_ioctl_phone *phone) -{ - isdn_net_dev *idev = isdn_net_findif(phone->name); - struct isdn_net_phone *n; - int retval = 0; - - if (!idev) - return -ENODEV; - - rtnl_lock(); - - if (netif_running(&idev->mlp->dev)) { - retval = -EBUSY; - goto out; - } - n = kmalloc(sizeof(*n), GFP_KERNEL); - if (!n) { - retval = -ENOMEM; - goto out; - } - strcpy(n->num, phone->phone); - list_add_tail(&n->list, &idev->mlp->phone[phone->outgoing & 1]); - - out: - rtnl_unlock(); - return retval; -} - -/* - * Delete a phone-number from an interface. - */ -static int -isdn_net_delphone(isdn_net_ioctl_phone *phone) -{ - isdn_net_dev *idev = isdn_net_findif(phone->name); - struct isdn_net_phone *n; - int retval; - - if (!idev) - return -ENODEV; - - rtnl_lock(); - - if (netif_running(&idev->mlp->dev)) { - retval = -EBUSY; - goto out; - } - retval = -EINVAL; - list_for_each_entry(n, &idev->mlp->phone[phone->outgoing & 1], list) { - if (!strcmp(n->num, phone->phone)) { - list_del(&n->list); - kfree(n); - retval = 0; - break; - } - } - out: - rtnl_unlock(); - return retval; -} - -/* - * Copy a string of all phone-numbers of an interface to user space. - */ -static int -isdn_net_getphone(isdn_net_ioctl_phone * phone, char *phones) -{ - isdn_net_dev *idev = isdn_net_findif(phone->name); - u_int count = 0; - char *buf = (char *)__get_free_page(GFP_KERNEL); - struct isdn_net_phone *n; - - if (!buf) - return -ENOMEM; - - if (!idev) { - count = -ENODEV; - goto free; - } - list_for_each_entry(n, &idev->mlp->phone[phone->outgoing & 1], list) { - strcpy(&buf[count], n->num); - count += strlen(n->num); - buf[count++] = ' '; - if (count > PAGE_SIZE - ISDN_MSNLEN - 1) - break; - } - if (!count) /* list was empty? */ - count++; - - buf[count-1] = 0; - - if (copy_to_user(phones, buf, count)) - count = -EFAULT; - - free: - free_page((unsigned long)buf); - return count; -} - -/* - * Force a net-interface to dial out. - */ -static int -isdn_net_dial_out(char *name) -{ - isdn_net_dev *idev = isdn_net_findif(name); - - if (!idev) - return -ENODEV; - - return isdn_net_dial(idev); -} - -static int -__isdn_net_dial_slave(isdn_net_local *mlp) -{ - isdn_net_dev *idev; - - list_for_each_entry(idev, &mlp->slaves, slaves) { - if (isdn_net_dial(idev) == 0) - return 0; - } - return -EBUSY; -} - -static int -isdn_net_dial_slave(char *name) -{ - isdn_net_dev *idev = isdn_net_findif(name); - - if (!idev) - return -ENODEV; - - return __isdn_net_dial_slave(idev->mlp); -} - -/* - * Force a hangup of a network-interface. - */ -static int -isdn_net_force_hangup(char *name) // FIXME rename? -{ - isdn_net_dev *idev = isdn_net_findif(name); - - if (!idev) - return -ENODEV; - - if (idev->isdn_slot == NULL) - return -ENOTCONN; - - isdn_net_hangup(idev); - return 0; -} - -/* - * Copy a string containing the peer's phone number of a connected interface - * to user space. - */ -static int -isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer) -{ - isdn_net_dev *idev = isdn_net_findif(phone->name); - struct isdn_slot *slot; - - if (!idev) - return -ENODEV; - - if (idev->fi.state != ST_ACTIVE) - return -ENOTCONN; - - slot = idev->isdn_slot; - - strlcpy(phone->phone, slot->num, sizeof(phone->phone)); - phone->outgoing = USG_OUTGOING(slot->usage); - - if (copy_to_user(peer, phone, sizeof(*peer))) - return -EFAULT; - - return 0; -} - -/* - * ioctl on /dev/isdnctrl, used to configure ISDN net interfaces - */ -int -isdn_net_ioctl(struct inode *ino, struct file *file, uint cmd, ulong arg) -{ - /* Save stack space */ - union { - char name[10]; - char bname[20]; - isdn_net_ioctl_phone phone; - isdn_net_ioctl_cfg cfg; - } iocpar; - int retval; - -#define name iocpar.name -#define bname iocpar.bname -#define phone iocpar.phone -#define cfg iocpar.cfg - - name[sizeof(name)-1] = 0; - bname[sizeof(bname)-1] = 0; - - down(&sem); - - switch (cmd) { - case IIOCNETAIF: /* add an interface */ - if (copy_from_user(name, (char *) arg, sizeof(name) - 1)) { - retval = -EFAULT; - break; - } - retval = isdn_net_addif(name, NULL); - break; - case IIOCNETASL: /* add slave to an interface */ - if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) { - retval = -EFAULT; - break; - } - retval = isdn_net_addslave(bname); - break; - case IIOCNETDIF: /* delete an interface */ - if (copy_from_user(name, (char *) arg, sizeof(name) - 1)) { - retval = -EFAULT; - break; - } - retval = isdn_net_delif(name); - break; - case IIOCNETSCF: /* set config */ - if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) { - retval = -EFAULT; - break; - } - retval = isdn_net_setcfg(&cfg); - break; - case IIOCNETGCF: /* get config */ - if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) { - retval = -EFAULT; - break; - } - retval = isdn_net_getcfg(&cfg); - if (retval) - break; - if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) - retval = -EFAULT; - break; - case IIOCNETANM: /* add a phone number */ - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) { - retval = -EFAULT; - break; - } - retval = isdn_net_addphone(&phone); - break; - case IIOCNETGNM: /* get list of phone numbers */ - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) { - retval = -EFAULT; - break; - } - retval = isdn_net_getphone(&phone, (char *) arg); - break; - case IIOCNETDNM: /* delete a phone number */ - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) { - retval = -EFAULT; - break; - } - retval = isdn_net_delphone(&phone); - break; - case IIOCNETDIL: /* trigger dial-out */ - if (copy_from_user(name, (char *) arg, sizeof(name))) { - retval = -EFAULT; - break; - } - retval = isdn_net_dial_out(name); - break; - case IIOCNETHUP: /* hangup */ - if (copy_from_user(name, (char *) arg, sizeof(name))) { - retval = -EFAULT; - break; - } - retval = isdn_net_force_hangup(name); - break; - case IIOCNETGPN: /* Get peer phone number of a connected interface */ - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) { - retval = -EFAULT; - } - retval = isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); - break; - case IIOCNETALN: /* Add link */ - if (copy_from_user(name, (char *) arg, sizeof(name))) { - retval = -EFAULT; - break; - } - retval = isdn_net_dial_slave(name); - break; - case IIOCNETDLN: /* Delete link */ - if (copy_from_user(name, (char *) arg, sizeof(name))) { - retval = -EFAULT; - break; - } - retval = isdn_net_force_hangup(name); - break; - default: - retval = -ENOTTY; - } - up(&sem); - return retval; - -#undef name -#undef bname -#undef iocts -#undef phone -#undef cfg -} - -/* - * Hang up all network-interfaces - */ -void -isdn_net_hangup_all(void) -{ - isdn_net_dev *idev; - - down(&sem); - - list_for_each_entry(idev, &isdn_net_devs, global_list) - isdn_net_hangup(idev); - - up(&sem); -} - -/* - * Remove all network-interfaces - */ -void -isdn_net_cleanup(void) -{ - isdn_net_dev *idev; - int retval; - - down(&sem); - - while (!list_empty(&isdn_net_devs)) { - idev = list_entry(isdn_net_devs.next, isdn_net_dev, global_list); - retval = isdn_net_dev_delete(idev); - /* can only fail if an interface is still running. - * In this case, an elevated module use count should - * have prevented this function from being called in - * the first place */ - if (retval) - isdn_BUG(); - } - up(&sem); -} - -/* ====================================================================== */ -/* interface to network layer */ -/* ====================================================================== */ - -static spinlock_t running_devs_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(running_devs); - -/* - * Open/initialize the board. - */ -static int -isdn_net_open(struct net_device *dev) -{ - isdn_net_local *lp = dev->priv; - unsigned long flags; - int retval = 0; - - if (!lp->ops) - return -ENODEV; - - if (lp->ops->open) - retval = lp->ops->open(lp); - - if (retval) - return retval; - - netif_start_queue(dev); - - atomic_set(&lp->refcnt, 1); - spin_lock_irqsave(&running_devs_lock, flags); - list_add(&lp->running_devs, &running_devs); - spin_unlock_irqrestore(&running_devs_lock, flags); - - return 0; -} - -/* - * Shutdown a net-interface. - */ -static int -isdn_net_close(struct net_device *dev) -{ - isdn_net_local *lp = dev->priv; - isdn_net_dev *sdev; - struct list_head *l, *n; - unsigned long flags; - - if (lp->ops->close) - lp->ops->close(lp); - - netif_stop_queue(dev); - - list_for_each_safe(l, n, &lp->slaves) { - sdev = list_entry(l, isdn_net_dev, slaves); - isdn_net_hangup(sdev); - } - /* The hangup will make the refcnt drop back to - * 1 (referenced by list only) soon. */ - spin_lock_irqsave(&running_devs_lock, flags); - while (atomic_read(&lp->refcnt) != 1) { - spin_unlock_irqrestore(&running_devs_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); - spin_lock_irqsave(&running_devs_lock, flags); - } - /* We have the only reference and list lock, so - * nobody can get another reference. */ - list_del(&lp->running_devs); - spin_unlock_irqrestore(&running_devs_lock, flags); - - return 0; -} - -/* - * Get statistics - */ -static struct net_device_stats * -isdn_net_get_stats(struct net_device *dev) -{ - isdn_net_local *lp = dev->priv; - - return &lp->stats; -} - -/* - * Transmit timeout - */ -static void -isdn_net_tx_timeout(struct net_device *dev) -{ - printk(KERN_WARNING "isdn_tx_timeout dev %s\n", dev->name); - - netif_wake_queue(dev); -} - -/* - * Interface-setup. (just after registering a new interface) - */ -static int -isdn_init_netif(struct net_device *ndev) -{ - /* Setup the generic properties */ - - ndev->mtu = 1500; - ndev->tx_queue_len = 10; - ndev->open = &isdn_net_open; - ndev->hard_header_len = ETH_HLEN + isdn_hard_header_len(); - ndev->stop = &isdn_net_close; - ndev->get_stats = &isdn_net_get_stats; - ndev->tx_timeout = isdn_net_tx_timeout; - ndev->watchdog_timeo = ISDN_NET_TX_TIMEOUT; - - return 0; -} - -/* ====================================================================== */ -/* call control state machine */ -/* ====================================================================== */ - -// FIXME -static int -isdn_net_is_connected(isdn_net_dev *idev) -{ - return idev->fi.state == ST_ACTIVE; -} - -static void -isdn_net_dial_timer(unsigned long data) -{ - isdn_net_dev *idev = (isdn_net_dev *) data; - - isdn_net_handle_event(idev, idev->dial_event, NULL); -} - -/* - * Unbind a net-interface - */ -static void -isdn_net_unbind_channel(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - - if (idev->isdn_slot == NULL) { - isdn_BUG(); - return; - } - - if (mlp->ops->unbind) - mlp->ops->unbind(idev); - - idev->isdn_slot->priv = NULL; - idev->isdn_slot->event_cb = NULL; - - skb_queue_purge(&idev->super_tx_queue); - - if (idev->isdn_slot != idev->exclusive) - isdn_slot_free(idev->isdn_slot); - - idev->isdn_slot = NULL; - - if (idev->fi.state != ST_NULL) { - lp_put(mlp); - fsm_change_state(&idev->fi, ST_NULL); - } -} - -static int isdn_net_event_callback(struct isdn_slot *slot, int pr, void *arg); - -/* - * Assign an ISDN-channel to a net-interface - */ -static int -isdn_net_bind_channel(isdn_net_dev *idev, struct isdn_slot *slot) -{ - isdn_net_local *mlp = idev->mlp; - int retval = 0; - - if (mlp->ops->bind) - retval = mlp->ops->bind(idev); - - if (retval < 0) - goto out; - - idev->isdn_slot = slot; - slot->priv = idev; - slot->event_cb = isdn_net_event_callback; - slot->usage |= ISDN_USAGE_NET; - - out: - return retval; -} - -static int -isdn_net_dial(isdn_net_dev *idev) -{ - int retval; - - lp_get(idev->mlp); - retval = fsm_event(&idev->fi, EV_NET_DO_DIAL, NULL); - if (retval == -ESRCH) /* event not handled in this state */ - retval = -EBUSY; - - if (retval) - lp_put(idev->mlp); - - return retval; -} - -static void -isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) -{ - u_short proto = ntohs(skb->protocol); - - printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", - dev->name, - (reason != NULL) ? reason : "unknown", - (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); - - dst_link_failure(skb); -} - -/* - * This is called from certain upper protocol layers (multilink ppp - * and x25iface encapsulation module) that want to initiate dialing - * themselves. - */ -int -isdn_net_dial_req(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - /* is there a better error code? */ - if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) - return -EBUSY; - - return isdn_net_dial(idev); -} - -static void -isdn_net_log_skb(struct sk_buff *skb, isdn_net_dev *idev) -{ - unsigned char *p = skb->nh.raw; /* hopefully, this was set correctly */ - unsigned short proto = ntohs(skb->protocol); - int data_ofs; - struct ip_ports { - unsigned short source; - unsigned short dest; - } *ipp; - char addinfo[100]; - - data_ofs = ((p[0] & 15) * 4); - switch (proto) { - case ETH_P_IP: - switch (p[9]) { - case IPPROTO_ICMP: - strcpy(addinfo, "ICMP"); - break; - case IPPROTO_TCP: - case IPPROTO_UDP: - ipp = (struct ip_ports *) (&p[data_ofs]); - sprintf(addinfo, "%s, port: %d -> %d", - p[9] == IPPROTO_TCP ? "TCP" : "UDP", - ntohs(ipp->source), ntohs(ipp->dest)); - break; - default: - sprintf(addinfo, "type %d", p[9]); - } - printk(KERN_INFO - "OPEN: %u.%u.%u.%u -> %u.%u.%u.%u %s\n", - - NIPQUAD(*(u32 *)(p + 12)), NIPQUAD(*(u32 *)(p + 16)), - addinfo); - break; - case ETH_P_ARP: - printk(KERN_INFO - "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", - NIPQUAD(*(u32 *)(p + 14)), NIPQUAD(*(u32 *)(p + 24))); - break; - default: - printk(KERN_INFO "OPEN: unknown proto %#x\n", proto); - } -} - -int -isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev) -{ - isdn_net_local *mlp = ndev->priv; - isdn_net_dev *idev = list_entry(mlp->slaves.next, isdn_net_dev, slaves); - int retval; - - if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO) - goto discard; - - retval = isdn_net_dial(idev); - if (retval == -ESRCH) - goto stop_queue; - - if (retval < 0) - goto discard; - - /* Log packet, which triggered dialing */ - if ((get_isdn_dev())->net_verbose) - isdn_net_log_skb(skb, idev); - - stop_queue: - netif_stop_queue(ndev); - return 1; - - discard: - isdn_net_unreachable(ndev, skb, "dial rejected"); - dev_kfree_skb(skb); - return 0; -} - -static int -accept_icall(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - isdn_ctrl cmd; - struct isdn_slot *slot = arg; - - isdn_net_bind_channel(idev, slot); - - idev->outgoing = 0; - idev->charge_state = ST_CHARGE_NULL; - /* Got incoming call, setup L2 and L3 protocols, - * then wait for D-Channel-connect - */ - cmd.arg = mlp->l2_proto << 8; - isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd); - cmd.arg = mlp->l3_proto << 8; - isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd); - isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTD, &cmd); - - idev->dial_timer.expires = jiffies + mlp->dialtimeout; - idev->dial_event = EV_NET_TIMER_INCOMING; - add_timer(&idev->dial_timer); - fsm_change_state(&idev->fi, ST_IN_WAIT_DCONN); - return 0; -} - -static int -do_callback(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - - printk(KERN_DEBUG "%s: start callback\n", idev->name); - - idev->dial_timer.expires = jiffies + mlp->cbdelay; - idev->dial_event = EV_NET_TIMER_CB_IN; - add_timer(&idev->dial_timer); - fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB); - - return 0; -} - -static int -isdn_net_dev_icall(isdn_net_dev *idev, struct isdn_slot *slot, - int si1, char *eaz, char *nr) -{ - isdn_net_local *mlp = idev->mlp; - struct isdn_net_phone *ph; - char *my_eaz; - - /* check acceptable call types for DOV */ - dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d\n", - idev->name, mlp->msn, mlp->flags, idev->fi.state); - - my_eaz = isdn_slot_map_eaz2msn(slot, mlp->msn); - if (si1 == 1) { /* it's a DOV call, check if we allow it */ - if (*my_eaz == 'v' || *my_eaz == 'V' || - *my_eaz == 'b' || *my_eaz == 'B') - my_eaz++; /* skip to allow a match */ - else - return 0; /* no match */ - } else { /* it's a DATA call, check if we allow it */ - if (*my_eaz == 'b' || *my_eaz == 'B') - my_eaz++; /* skip to allow a match */ - } - /* check called number */ - switch (isdn_msncmp(eaz, my_eaz)) { - case 1: /* no match */ - return 0; - case 2: /* matches so far */ - return 5; - } - - dbg_net_icall("%s: pdev=%d di=%d pch=%d ch = %d\n", idev->name, - idev->pre_device, slot->di, idev->pre_channel, slot->ch); - - /* check if exclusive */ - if ((slot->usage & ISDN_USAGE_EXCLUSIVE) && - (idev->pre_channel != slot->ch || idev->pre_device != slot->di)) { - dbg_net_icall("%s: excl check failed\n", idev->name); - return 0; - } - - /* check calling number */ - dbg_net_icall("%s: secure\n", idev->name); - if (mlp->flags & ISDN_NET_SECURE) { - list_for_each_entry(ph, &mlp->phone[0], list) { - if (isdn_msncmp(nr, ph->num) == 0) - goto found; - } - return 0; - } - found: - /* check dial mode */ - if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) { - printk(KERN_INFO "%s: incoming call, stopped -> rejected\n", - idev->name); - return 3; - } - lp_get(mlp); - /* check callback */ - if (mlp->flags & ISDN_NET_CALLBACK) { - if (fsm_event(&idev->fi, EV_NET_DO_CALLBACK, NULL)) { - lp_put(mlp); - return 0; - } - /* Initiate dialing by returning 2 or 4 */ - return (mlp->flags & ISDN_NET_CBHUP) ? 2 : 4; - } - printk(KERN_INFO "%s: call from %s -> %s accepted\n", - idev->name, nr, eaz); - - if (fsm_event(&idev->fi, EV_NET_DO_ACCEPT, slot)) { - lp_put(mlp); - return 0; - } - return 1; // accepted -} - -/* - * An incoming call-request has arrived. - * Search the interface-chain for an appropriate interface. - * If found, connect the interface to the ISDN-channel and initiate - * D- and B-Channel-setup. If secure-flag is set, accept only - * configured phone-numbers. If callback-flag is set, initiate - * callback-dialing. - * - * Return-Value: 0 = No appropriate interface for this call. - * 1 = Call accepted - * 2 = Reject call, wait cbdelay, then call back - * 3 = Reject call - * 4 = Wait cbdelay, then call back - * 5 = No appropriate interface for this call, - * would eventually match if CID was longer. - */ -int -isdn_net_find_icall(struct isdn_slot *slot, setup_parm *setup) -{ - isdn_net_local *lp; - isdn_net_dev *idev; - char *nr, *eaz; - unsigned char si1, si2; - int retval; - int verbose = (get_isdn_dev())->net_verbose; - unsigned long flags; - - /* fix up calling number */ - if (!setup->phone[0]) { - printk(KERN_INFO - "isdn_net: Incoming call without OAD, assuming '0'\n"); - nr = "0"; - } else { - nr = setup->phone; - } - /* fix up called number */ - if (!setup->eazmsn[0]) { - printk(KERN_INFO - "isdn_net: Incoming call without CPN, assuming '0'\n"); - eaz = "0"; - } else { - eaz = setup->eazmsn; - } - si1 = setup->si1; - si2 = setup->si2; - if (verbose > 1) - printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", - nr, si1, si2, eaz); - /* check service indicator */ - /* Accept DATA and VOICE calls at this stage - local eaz is checked later for allowed call types */ - if ((si1 != 7) && (si1 != 1)) { - if (verbose > 1) - printk(KERN_INFO "isdn_net: " - "Service-Indicator not 1 or 7, ignored\n"); - return 0; - } - - dbg_net_icall("n_fi: di=%d ch=%d usg=%#x\n", slot->di, slot->ch, - slot->usage); - - retval = 0; - spin_lock_irqsave(&running_devs_lock, flags); - list_for_each_entry(lp, &running_devs, running_devs) { - lp_get(lp); - spin_unlock_irqrestore(&running_devs_lock, flags); - - list_for_each_entry(idev, &lp->slaves, slaves) { - retval = isdn_net_dev_icall(idev, slot, si1, eaz, nr); - if (retval > 0) - break; - } - - spin_lock_irqsave(&running_devs_lock, flags); - lp_put(lp); - if (retval > 0) - break; - - } - spin_unlock_irqrestore(&running_devs_lock, flags); - if (!retval) { - if (verbose) - printk(KERN_INFO "isdn_net: call " - "from %s -> %s ignored\n", nr, eaz); - } - return retval; -} - -/* ---------------------------------------------------------------------- */ -/* callbacks in the state machine */ -/* ---------------------------------------------------------------------- */ - -/* Find the idev->dial'th outgoing number. */ - -static struct isdn_net_phone * -get_outgoing_phone(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - struct isdn_net_phone *phone; - int i = 0; - - list_for_each_entry(phone, &mlp->phone[1], list) { - if (i++ == idev->dial) - return phone; - } - return NULL; -} - -static int dialout_next(struct fsm_inst *fi, int pr, void *arg); - -/* Initiate dialout. */ - -static int -do_dial(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - struct isdn_slot *slot; - - if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) - return -EPERM; - - if (list_empty(&mlp->phone[1])) /* no number to dial ? */ - return -EINVAL; - - if (idev->exclusive) - slot = idev->exclusive; - else - slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto, - mlp->l3_proto, idev->pre_device, - idev->pre_channel, mlp->msn); - if (!slot) - return -EAGAIN; - - if (isdn_net_bind_channel(idev, slot) < 0) { - /* has freed the slot as well */ - return -EAGAIN; - } - - fsm_change_state(fi, ST_OUT_BOUND); - - idev->dial = 0; - idev->dialretry = 0; - - dialout_next(fi, pr, arg); - return 0; -} - -/* Try dialing the next number. */ - -static int -dialout_next(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - struct dial_info dial = { - .l2_proto = mlp->l2_proto, - .l3_proto = mlp->l3_proto, - .si1 = 7, - .si2 = 0, - .msn = mlp->msn, - .phone = get_outgoing_phone(idev)->num, - }; - - /* next time, try next number */ - idev->dial++; - - idev->outgoing = 1; - if (idev->chargeint) - idev->charge_state = ST_CHARGE_HAVE_CINT; - else - idev->charge_state = ST_CHARGE_NULL; - - /* For outgoing callback, use cbdelay instead of dialtimeout */ - if (mlp->cbdelay && (mlp->flags & ISDN_NET_CBOUT)) { - idev->dial_timer.expires = jiffies + mlp->cbdelay; - idev->dial_event = EV_NET_TIMER_CB_OUT; - } else { - idev->dial_timer.expires = jiffies + mlp->dialtimeout; - idev->dial_event = EV_NET_TIMER_DIAL; - } - fsm_change_state(&idev->fi, ST_OUT_WAIT_DCONN); - add_timer(&idev->dial_timer); - - /* Dial */ - isdn_slot_dial(idev->isdn_slot, &dial); - return 0; -} - -/* If we didn't connect within dialtimeout, we give up for now - * and wait for dialwait jiffies before trying again. - */ -static int -dial_timeout(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - isdn_ctrl cmd; - - fsm_change_state(&idev->fi, ST_OUT_DIAL_WAIT); - isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd); - - /* get next phone number */ - if (!get_outgoing_phone(idev)) { - /* otherwise start over at first entry */ - idev->dial = 0; - idev->dialretry++; - } - if (idev->dialretry >= mlp->dialmax) { - isdn_net_hangup(idev); - return 0; - } - idev->dial_event = EV_NET_TIMER_DIAL_WAIT; - mod_timer(&idev->dial_timer, jiffies + mlp->dialwait); - return 0; -} - -static int -connect_fail(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - - del_timer(&idev->dial_timer); - printk(KERN_INFO "%s: connection failed\n", idev->name); - isdn_net_unbind_channel(idev); - return 0; -} - -static int -out_dconn(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_ctrl cmd; - - fsm_change_state(&idev->fi, ST_OUT_WAIT_BCONN); - isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd); - return 0; -} - -static int -in_dconn(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_ctrl cmd; - - fsm_change_state(&idev->fi, ST_IN_WAIT_BCONN); - isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd); - return 0; -} - -static int -bconn(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - - fsm_change_state(&idev->fi, ST_ACTIVE); - - if (mlp->onhtime) { - idev->huptimer = 0; - idev->dial_event = EV_NET_TIMER_HUP; - mod_timer(&idev->dial_timer, jiffies + HZ); - } else { - del_timer(&idev->dial_timer); - } - - printk(KERN_INFO "%s connected\n", idev->name); - /* If first Chargeinfo comes before B-Channel connect, - * we correct the timestamp here. - */ - idev->chargetime = jiffies; - idev->frame_cnt = 0; - idev->transcount = 0; - idev->cps = 0; - idev->last_jiffies = jiffies; - - if (mlp->ops->connected) - mlp->ops->connected(idev); - else - isdn_net_online(idev); - - return 0; -} - -static int -bhup(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - - del_timer(&idev->dial_timer); - if (mlp->ops->disconnected) - mlp->ops->disconnected(idev); - else - isdn_net_offline(idev); - - printk(KERN_INFO "%s: disconnected\n", idev->name); - fsm_change_state(fi, ST_WAIT_DHUP); - return 0; -} - -static int -dhup(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - - printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge); - isdn_net_unbind_channel(idev); - return 0; -} - -/* Check if it's time for idle hang-up */ - -static int -check_hup(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_net_local *mlp = idev->mlp; - - dbg_net_dial("%s: huptimer %d onhtime %d chargetime %ld chargeint %d\n", - idev->name, idev->huptimer, mlp->onhtime, idev->chargetime, idev->chargeint); - - if (idev->huptimer++ <= mlp->onhtime) - goto mod_timer; - - if (mlp->hupflags & ISDN_CHARGEHUP && - idev->charge_state == ST_CHARGE_HAVE_CINT) { - if (!time_after(jiffies, idev->chargetime - + idev->chargeint - 2 * HZ)) - goto mod_timer; - } - if (idev->outgoing || mlp->hupflags & ISDN_INHUP) { - isdn_net_hangup(idev); - return 0; - } - mod_timer: - mod_timer(&idev->dial_timer, idev->dial_timer.expires + HZ); - return 0; -} - -/* Charge-info from TelCo. */ - -static int -got_cinf(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - - idev->charge++; - switch (idev->charge_state) { - case ST_CHARGE_NULL: - idev->charge_state = ST_CHARGE_GOT_CINF; - break; - case ST_CHARGE_GOT_CINF: - idev->charge_state = ST_CHARGE_HAVE_CINT; - /* fall through */ - case ST_CHARGE_HAVE_CINT: - idev->chargeint = jiffies - idev->chargetime; - break; - } - idev->chargetime = jiffies; - dbg_net_dial("%s: got CINF\n", idev->name); - return 0; -} - -/* Perform hangup for a net-interface. */ - -int -isdn_net_hangup(isdn_net_dev *idev) -{ - isdn_ctrl cmd; - - del_timer(&idev->dial_timer); - - printk(KERN_INFO "%s: local hangup\n", idev->name); - // FIXME via state machine - if (idev->isdn_slot) - isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd); - return 1; -} - -static int isdn_net_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb); - -/* - * Handle status-messages from ISDN-interfacecard. - * This function is called from within the main-status-dispatcher - * isdn_status_callback, which itself is called from the low-level driver. - */ -static int -isdn_net_event_callback(struct isdn_slot *slot, int pr, void *arg) -{ - isdn_net_dev *idev = slot->priv; - - if (!idev) { - isdn_BUG(); - return 0; - } - switch (pr) { - case EV_DATA_IND: - return isdn_net_rcv_skb(slot, arg); - case EV_STAT_DCONN: - return fsm_event(&idev->fi, EV_NET_STAT_DCONN, arg); - case EV_STAT_BCONN: - return fsm_event(&idev->fi, EV_NET_STAT_BCONN, arg); - case EV_STAT_BHUP: - return fsm_event(&idev->fi, EV_NET_STAT_BHUP, arg); - case EV_STAT_DHUP: - return fsm_event(&idev->fi, EV_NET_STAT_DHUP, arg); - case EV_STAT_CINF: - return fsm_event(&idev->fi, EV_NET_STAT_CINF, arg); - case EV_STAT_BSENT: - return fsm_event(&idev->fi, EV_NET_STAT_BSENT, arg); - default: - printk("unknown pr %d\n", pr); - return 0; - } -} - -static int -isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg) -{ - return fsm_event(&idev->fi, pr, arg); -} - -static int -hang_up(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - - isdn_net_hangup(idev); - return 0; -} - -static int -got_bsent(struct fsm_inst *fi, int pr, void *arg) -{ - isdn_net_dev *idev = fi->userdata; - isdn_ctrl *c = arg; - - isdn_net_bsent(idev, c); - return 0; -} - -static struct fsm_node isdn_net_fn_tbl[] = { - { ST_NULL, EV_NET_DO_DIAL, do_dial }, - { ST_NULL, EV_NET_DO_ACCEPT, accept_icall }, - { ST_NULL, EV_NET_DO_CALLBACK, do_callback }, - - { ST_OUT_WAIT_DCONN, EV_NET_TIMER_DIAL, dial_timeout }, - { ST_OUT_WAIT_DCONN, EV_NET_STAT_DCONN, out_dconn }, - { ST_OUT_WAIT_DCONN, EV_NET_STAT_DHUP, connect_fail }, - { ST_OUT_WAIT_DCONN, EV_NET_TIMER_CB_OUT, hang_up }, - - { ST_OUT_WAIT_BCONN, EV_NET_TIMER_DIAL, dial_timeout }, - { ST_OUT_WAIT_BCONN, EV_NET_STAT_BCONN, bconn }, - { ST_OUT_WAIT_BCONN, EV_NET_STAT_DHUP, connect_fail }, - - { ST_IN_WAIT_DCONN, EV_NET_TIMER_INCOMING, hang_up }, - { ST_IN_WAIT_DCONN, EV_NET_STAT_DCONN, in_dconn }, - { ST_IN_WAIT_DCONN, EV_NET_STAT_DHUP, connect_fail }, - - { ST_IN_WAIT_BCONN, EV_NET_TIMER_INCOMING, hang_up }, - { ST_IN_WAIT_BCONN, EV_NET_STAT_BCONN, bconn }, - { ST_IN_WAIT_BCONN, EV_NET_STAT_DHUP, connect_fail }, - - { ST_ACTIVE, EV_NET_TIMER_HUP, check_hup }, - { ST_ACTIVE, EV_NET_STAT_BHUP, bhup }, - { ST_ACTIVE, EV_NET_STAT_CINF, got_cinf }, - { ST_ACTIVE, EV_NET_STAT_BSENT, got_bsent }, - - { ST_WAIT_DHUP, EV_NET_STAT_DHUP, dhup }, - - { ST_WAIT_BEFORE_CB, EV_NET_TIMER_CB_IN, do_dial }, - - { ST_OUT_DIAL_WAIT, EV_NET_TIMER_DIAL_WAIT, dialout_next }, -}; - -static struct fsm isdn_net_fsm = { - .st_cnt = ARRAY_SIZE(isdn_net_st_str), - .st_str = isdn_net_st_str, - .ev_cnt = ARRAY_SIZE(isdn_net_ev_str), - .ev_str = isdn_net_ev_str, - .fn_cnt = ARRAY_SIZE(isdn_net_fn_tbl), - .fn_tbl = isdn_net_fn_tbl, -}; - -static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...) -{ - va_list args; - isdn_net_dev *idev = fi->userdata; - char buf[128]; - char *p = buf; - - va_start(args, fmt); - p += sprintf(p, "%s: ", idev->name); - p += vsprintf(p, fmt, args); - va_end(args); - printk(KERN_DEBUG "%s\n", buf); -} - -/* ====================================================================== */ -/* xmit path */ -/* ====================================================================== */ - -#define ISDN_NET_MAX_QUEUE_LENGTH 2 - -/* - * is this particular channel busy? - */ -static inline int -isdn_net_dev_busy(isdn_net_dev *idev) -{ - return idev->frame_cnt >= ISDN_NET_MAX_QUEUE_LENGTH; -} - -/* - * find out if the net_device which this mlp is belongs to is busy. - * It's busy iff all channels are busy. - * must hold mlp->xmit_lock - * FIXME: Use a mlp->frame_cnt instead of loop? - */ -static inline int -isdn_net_local_busy(isdn_net_local *mlp) -{ - isdn_net_dev *idev; - - list_for_each_entry(idev, &mlp->online, online) { - if (!isdn_net_dev_busy(idev)) - return 0; - } - return 1; -} - -/* - * For the given net device, this will get a non-busy channel out of the - * corresponding bundle. - * must hold mlp->xmit_lock - */ -isdn_net_dev * -isdn_net_get_xmit_dev(isdn_net_local *mlp) -{ - isdn_net_dev *idev; - - list_for_each_entry(idev, &mlp->online, online) { - if (!isdn_net_dev_busy(idev)) { - /* point the head to next online channel */ - list_del(&mlp->online); - list_add(&mlp->online, &idev->online); - return idev; - } - } - return NULL; -} - -/* mlp->xmit_lock must be held */ -static inline void -isdn_net_inc_frame_cnt(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - - if (isdn_net_dev_busy(idev)) - isdn_BUG(); - - idev->frame_cnt++; - if (isdn_net_local_busy(mlp)) - netif_stop_queue(&mlp->dev); -} - -/* mlp->xmit_lock must be held */ -static inline void -isdn_net_dec_frame_cnt(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - - idev->frame_cnt--; - - if (isdn_net_dev_busy(idev)) - isdn_BUG(); - - if (!skb_queue_empty(&idev->super_tx_queue)) - tasklet_schedule(&idev->tlet); - else - netif_wake_queue(&mlp->dev); -} - -static void -isdn_net_tasklet(unsigned long data) -{ - isdn_net_dev *idev = (isdn_net_dev *) data; - isdn_net_local *mlp = idev->mlp; - struct sk_buff *skb; - unsigned long flags; - - spin_lock_irqsave(&mlp->xmit_lock, flags); - while (!isdn_net_dev_busy(idev) && - (skb = skb_dequeue(&idev->super_tx_queue))) { - isdn_net_writebuf_skb(idev, skb); - } - spin_unlock_irqrestore(&mlp->xmit_lock, flags); -} - -/* We're good to accept (IP/whatever) traffic now */ - -void -isdn_net_online(isdn_net_dev *idev) -{ - // FIXME check we're connected - isdn_net_local *mlp = idev->mlp; - unsigned long flags; - - spin_lock_irqsave(&mlp->xmit_lock, flags); - list_add(&idev->online, &mlp->online); - spin_unlock_irqrestore(&mlp->xmit_lock, flags); - - netif_wake_queue(&mlp->dev); -} - -/* No more (IP/whatever) traffic over the net interface */ - -void -isdn_net_offline(isdn_net_dev *idev) -{ - isdn_net_local *mlp = idev->mlp; - unsigned long flags; - - spin_lock_irqsave(&mlp->xmit_lock, flags); - list_del(&idev->online); - spin_unlock_irqrestore(&mlp->xmit_lock, flags); - - skb_queue_purge(&idev->super_tx_queue); -} - -/* - * all frames sent from the (net) LL to a HL driver should go via this function - * must hold mlp->xmit_lock - */ -void -isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb) -{ - isdn_net_local *mlp = idev->mlp; - int ret; - int len = skb->len; /* save len */ - - /* before obtaining the lock the caller should have checked that - the lp isn't busy */ - if (isdn_net_dev_busy(idev)) { - isdn_BUG(); - goto error; - } - - if (!isdn_net_is_connected(idev)) { - isdn_BUG(); - goto error; - } - ret = isdn_slot_write(idev->isdn_slot, skb); - if (ret != len) { - /* we should never get here */ - printk(KERN_WARNING "%s: HL driver queue full\n", idev->name); - goto error; - } - - idev->transcount += len; - isdn_net_inc_frame_cnt(idev); - return; - - error: - dev_kfree_skb(skb); - mlp->stats.tx_errors++; -} - -/* A packet has successfully been sent out. */ - -static int -isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c) -{ - isdn_net_local *mlp = idev->mlp; - unsigned long flags; - - spin_lock_irqsave(&mlp->xmit_lock, flags); - isdn_net_dec_frame_cnt(idev); - spin_unlock_irqrestore(&mlp->xmit_lock, flags); - mlp->stats.tx_packets++; - mlp->stats.tx_bytes += c->parm.length; - return 1; -} - -/* - * Based on cps-calculation, check if device is overloaded. - * If so, and if a slave exists, trigger dialing for it. - * If any slave is online, deliver packets using a simple round robin - * scheme. - * - * Return: 0 on success, !0 on failure. - */ - -int -isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - isdn_net_dev *idev; - isdn_net_local *mlp = ndev->priv; - unsigned long flags; - int retval; - - ndev->trans_start = jiffies; - - spin_lock_irqsave(&mlp->xmit_lock, flags); - - if (list_empty(&mlp->online)) { - retval = isdn_net_autodial(skb, ndev); - goto out; - } - - idev = isdn_net_get_xmit_dev(mlp); - if (!idev) { - printk(KERN_INFO "%s: all channels busy - requeuing!\n", ndev->name); - netif_stop_queue(ndev); - retval = 1; - goto out; - } - - isdn_net_writebuf_skb(idev, skb); - - /* the following stuff is here for backwards compatibility. - * in future, start-up and hangup of slaves (based on current load) - * should move to userspace and get based on an overall cps - * calculation - */ - if (jiffies != idev->last_jiffies) { - idev->cps = idev->transcount * HZ / (jiffies - idev->last_jiffies); - idev->last_jiffies = jiffies; - idev->transcount = 0; - } - if ((get_isdn_dev())->net_verbose > 3) - printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps); - - if (idev->cps > mlp->triggercps) { - if (!idev->sqfull) { - /* First time overload: set timestamp only */ - idev->sqfull = 1; - idev->sqfull_stamp = jiffies; - } else { - /* subsequent overload: if slavedelay exceeded, start dialing */ - if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) { - if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_AUTO) - __isdn_net_dial_slave(mlp); - } - } - } else { - if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay + 10 * HZ)) { - idev->sqfull = 0; - } - /* this is a hack to allow auto-hangup for slaves on moderate loads */ - list_del(&mlp->online); - list_add_tail(&mlp->online, &idev->online); - } - - retval = 0; - out: - spin_unlock_irqrestore(&mlp->xmit_lock, flags); - return retval; -} - -/* - * this function is used to send supervisory data, i.e. data which was - * not received from the network layer, but e.g. frames from ipppd, CCP - * reset frames etc. - * must hold mlp->xmit_lock - */ -void -isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb) -{ - if (!isdn_net_dev_busy(idev)) { - isdn_net_writebuf_skb(idev, skb); - } else { - skb_queue_tail(&idev->super_tx_queue, skb); - } -} - -/* ====================================================================== */ -/* receive path */ -/* ====================================================================== */ - -/* - * A packet arrived via ISDN. Search interface-chain for a corresponding - * interface. If found, deliver packet to receiver-function and return 1, - * else return 0. - */ -static int -isdn_net_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb) -{ - isdn_net_dev *idev = slot->priv; - isdn_net_local *mlp; - - if (!idev) { - isdn_BUG(); - return 0; - } - if (!isdn_net_is_connected(idev)) { - isdn_BUG(); - return 0; - } - - mlp = idev->mlp; - - idev->transcount += skb->len; - - mlp->stats.rx_packets++; - mlp->stats.rx_bytes += skb->len; - skb->dev = &mlp->dev; - skb->pkt_type = PACKET_HOST; - isdn_dumppkt("R:", skb->data, skb->len, 40); - - mlp->ops->receive(mlp, idev, skb); - - return 1; -} - -/* - * After handling connection-type specific stuff, the receiver function - * can use this function to pass the skb on to the network layer. - */ -void -isdn_netif_rx(isdn_net_dev *idev, struct sk_buff *skb, u16 protocol) -{ - idev->huptimer = 0; - - skb->protocol = protocol; - skb->dev = &idev->mlp->dev; - netif_rx(skb); -} - -/* ====================================================================== */ -/* init / exit */ -/* ====================================================================== */ - -void -isdn_net_lib_init(void) -{ - fsm_new(&isdn_net_fsm); - -#ifdef CONFIG_ISDN_NET_SIMPLE - register_isdn_netif(ISDN_NET_ENCAP_ETHER, &isdn_ether_ops); - register_isdn_netif(ISDN_NET_ENCAP_RAWIP, &isdn_rawip_ops); - register_isdn_netif(ISDN_NET_ENCAP_IPTYP, &isdn_iptyp_ops); - register_isdn_netif(ISDN_NET_ENCAP_UIHDLC, &isdn_uihdlc_ops); -#endif -#ifdef CONFIG_ISDN_NET_CISCO - register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLC, &isdn_ciscohdlck_ops); - register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLCK, &isdn_ciscohdlck_ops); -#endif -#ifdef CONFIG_ISDN_X25 - register_isdn_netif(ISDN_NET_ENCAP_X25IFACE, &isdn_x25_ops); -#endif -#ifdef CONFIG_ISDN_PPP - register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP, &isdn_ppp_ops); -#endif -} - -void -isdn_net_lib_exit(void) -{ - fsm_free(&isdn_net_fsm); -} diff -puN -L drivers/isdn/i4l/isdn_net_lib.h drivers/isdn/i4l/isdn_net_lib.h~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_net_lib.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,224 +0,0 @@ -/* Linux ISDN subsystem, network interface support code - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef __ISDN_NET_LIB_H__ -#define __ISDN_NET_LIB_H__ - -#include - -typedef struct isdn_net_local_s isdn_net_local; -typedef struct isdn_net_dev_s isdn_net_dev; - -struct isdn_netif_ops { - int (*hard_start_xmit) (struct sk_buff *skb, - struct net_device *dev); - int (*hard_header) (struct sk_buff *skb, - struct net_device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len); - int (*do_ioctl)(struct net_device *dev, - struct ifreq *ifr, int cmd); - - unsigned short flags; /* interface flags (a la BSD) */ - unsigned short type; /* interface hardware type */ - unsigned char addr_len;/* hardware address length */ - void (*receive)(struct isdn_net_local_s *, - struct isdn_net_dev_s *, - struct sk_buff *); - void (*connected)(struct isdn_net_dev_s *); - void (*disconnected)(struct isdn_net_dev_s *); - int (*bind)(struct isdn_net_dev_s *); - void (*unbind)(struct isdn_net_dev_s *); - int (*init)(struct isdn_net_local_s *); - void (*cleanup)(struct isdn_net_local_s *); - int (*open)(struct isdn_net_local_s *); - void (*close)(struct isdn_net_local_s *); -}; - -/* our interface to isdn_common.c */ -void isdn_net_lib_init(void); -void isdn_net_lib_exit(void); -void isdn_net_hangup_all(void); -int isdn_net_ioctl(struct inode *, struct file *, uint, ulong); -int isdn_net_find_icall(struct isdn_slot *slot, setup_parm *setup); - -/* provided for interface types to use */ -void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb); -void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb); -void isdn_net_online(isdn_net_dev *idev); -void isdn_net_offline(isdn_net_dev *idev); -int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev); -void isdn_netif_rx(isdn_net_dev *idev, struct sk_buff *skb, u16 protocol); -isdn_net_dev *isdn_net_get_xmit_dev(isdn_net_local *mlp); -int isdn_net_hangup(isdn_net_dev *); -int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev); -int isdn_net_dial_req(isdn_net_dev *); -int register_isdn_netif(int encap, struct isdn_netif_ops *ops); - -/* ====================================================================== */ - -/* Feature- and status-flags for a net-interface */ -#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */ -#define ISDN_NET_CALLBACK 0x04 /* activate callback */ -#define ISDN_NET_CBHUP 0x08 /* hangup before callback */ -#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */ - -#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */ - -/* Phone-list-element */ -struct isdn_net_phone { - struct list_head list; - char num[ISDN_MSNLEN]; -}; - -/* per network interface data (dev->priv) */ - -struct isdn_net_local_s { - ulong magic; - struct net_device dev; /* interface to upper levels */ - struct net_device_stats stats; /* Ethernet Statistics */ - struct isdn_netif_ops *ops; - void *inl_priv; /* interface types can put their - private data here */ - int flags; /* Connection-flags */ - int dialmax; /* Max. Number of Dial-retries */ - int dialtimeout; /* How long shall we try on dialing */ - int dialwait; /* wait after failed attempt */ - - int cbdelay; /* Delay before Callback starts */ - char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */ - - u_char cbhup; /* Flag: Reject Call before Callback*/ - int hupflags; /* Flags for charge-unit-hangup: */ - int onhtime; /* Time to keep link up */ - - u_char p_encap; /* Packet encapsulation */ - u_char l2_proto; /* Layer-2-protocol */ - u_char l3_proto; /* Layer-3-protocol */ - - ulong slavedelay; /* Dynamic bundling delaytime */ - int triggercps; /* BogoCPS needed for trigger slave */ - struct list_head phone[2]; /* List of remote-phonenumbers */ - /* phone[0] = Incoming Numbers */ - /* phone[1] = Outgoing Numbers */ - - struct list_head slaves; /* list of all bundled channels - protected by serializing config - ioctls / no change allowed when - interface is running */ - struct list_head online; /* list of all bundled channels - which can be used for actual - data (IP) transfer - protected by xmit_lock */ - - spinlock_t xmit_lock; /* used to protect the xmit path of - a net_device, including all - associated channels's frame_cnt */ - struct list_head running_devs; /* member of global running_devs */ - atomic_t refcnt; /* references held by ISDN code */ - -}; - - -/* per ISDN channel (ISDN interface) data */ - -struct isdn_net_dev_s { - struct isdn_slot *isdn_slot; /* Index to isdn device/channel */ - struct isdn_slot *exclusive; /* NULL if non excl */ - int pre_device; /* Preselected isdn-device */ - int pre_channel; /* Preselected isdn-channel */ - - struct timer_list dial_timer; /* dial events timer */ - struct fsm_inst fi; /* call control state machine */ - int dial_event; /* event in case of timer expiry */ - int dial; /* # of phone number just dialed */ - int outgoing; /* Flag: outgoing call */ - int dialretry; /* Counter for Dialout-retries */ - - int cps; /* current speed of this interface */ - int transcount; /* byte-counter for cps-calculation */ - u_long last_jiffies; /* when transcount was reset */ - int sqfull; /* Flag: netdev-queue overloaded */ - u_long sqfull_stamp; /* Start-Time of overload */ - - int huptimer; /* Timeout-counter for auto-hangup */ - int charge; /* Counter for charging units */ - int charge_state; /* ChargeInfo state machine */ - u_long chargetime; /* Timer for Charging info */ - int chargeint; /* Interval between charge-infos */ - - int pppbind; /* ippp device for bindings */ - - struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ - /* be transmitted asap */ - int frame_cnt; /* number of frames currently */ - /* queued in HL driver */ - struct tasklet_struct tlet; - - isdn_net_local *mlp; /* Ptr to master device for all devs*/ - - struct list_head slaves; /* member of local->slaves */ - struct list_head online; /* member of local->online */ - - char name[10]; /* Name of device */ - struct list_head global_list; /* global list of all isdn_net_devs */ - void *ind_priv; /* interface types can put their - private data here */ -}; - -/* ====================================================================== */ - -static inline int -put_u8(unsigned char *p, u8 x) -{ - *p = x; - return 1; -} - -static inline int -put_u16(unsigned char *p, u16 x) -{ - *((u16 *)p) = htons(x); - return 2; -} - -static inline int -put_u32(unsigned char *p, u32 x) -{ - *((u32 *)p) = htonl(x); - return 4; -} - -static inline int -get_u8(unsigned char *p, u8 *x) -{ - *x = *p; - return 1; -} - -static inline int -get_u16(unsigned char *p, u16 *x) -{ - *x = ntohs(*((u16 *)p)); - return 2; -} - -static inline int -get_u32(unsigned char *p, u32 *x) -{ - *x = ntohl(*((u32 *)p)); - return 4; -} - - -#endif diff -puN drivers/isdn/i4l/isdn_ppp.c~i4l drivers/isdn/i4l/isdn_ppp.c --- 25/drivers/isdn/i4l/isdn_ppp.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_ppp.c 2004-02-10 01:59:59.000000000 -0800 @@ -1,803 +1,843 @@ -/* Linux ISDN subsystem, functions for synchronous PPP (linklevel). +/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski + * Linux ISDN subsystem, functions for synchronous PPP (linklevel). + * + * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ -#include +#include #include -#include #include #include -#include +#ifdef CONFIG_IPPP_FILTER +#include +#endif #include "isdn_common.h" -#include "isdn_net_lib.h" #include "isdn_ppp.h" -#include "isdn_ppp_ccp.h" -#include "isdn_ppp_vj.h" -#include "isdn_ppp_mp.h" +#include "isdn_net.h" -/* ====================================================================== */ +#ifndef PPP_IPX +#define PPP_IPX 0x002b +#endif -#define IPPP_MAX_RQ_LEN 8 /* max #frames queued for ipppd to read */ +/* Prototypes */ +static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); +static int isdn_ppp_closewait(int slot); +static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff *skb, int proto); +static int isdn_ppp_if_get_unit(char *namebuf); +static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *); +static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, + struct ippp_struct *,struct ippp_struct *,int *proto); +static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff *skb,int proto); +static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, + struct ippp_struct *is,struct ippp_struct *master,int type); +static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, + struct sk_buff *skb); -static int -isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *); +/* New CCP stuff */ +static void isdn_ppp_ccp_kickup(struct ippp_struct *is); +static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len); +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); +static void isdn_ppp_ccp_reset_free(struct ippp_struct *is); +static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, + unsigned char id); +static void isdn_ppp_ccp_timer_callback(unsigned long closure); +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, + unsigned char id); +static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, + struct isdn_ppp_resetparams *rp); +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, + unsigned char id); -/* ====================================================================== */ -/* IPPPD handling */ -/* ====================================================================== */ - -/* We use reference counting for struct ipppd. It is alloced on - * open() on /dev/ipppX and saved into file->private, making for one - * reference. release() will release this reference, after all other - * references are gone, the destructor frees it. - * - * Another reference is taken by isdn_ppp_bind() and freed by - * isdn_ppp_unbind(). The callbacks from isdn_net_lib.c happen only - * between isdn_ppp_bind() and isdn_ppp_unbind(), i.e. access to - * idev->ipppd is safe without further locking. - */ -#undef IPPPD_DEBUG - -#ifdef IPPPD_DEBUG -#define ipppd_debug(i, fmt, arg...) \ - printk(KERN_DEBUG "ipppd %p minor %d state %#x %s: " fmt "\n", (i), \ - (i)->minor, (i)->state, __FUNCTION__ , ## arg) -#else -#define ipppd_debug(...) do { } while (0) -#endif -/* ipppd::flags */ -enum { - IPPPD_FL_HUP = 0x01, - IPPPD_FL_WAKEUP = 0x02, -}; - -/* ipppd::state */ -enum { - IPPPD_ST_OPEN, - IPPPD_ST_ASSIGNED, - IPPPD_ST_CONNECTED, -}; - -struct ipppd { - struct list_head ipppds; - int state; - int flags; - struct sk_buff_head rq; - wait_queue_head_t wq; - struct isdn_net_dev_s *idev; - int unit; - int minor; - unsigned long debug; - atomic_t refcnt; -}; +#ifdef CONFIG_ISDN_MPP +static ippp_bundle * isdn_ppp_bundle_arr = NULL; + +static int isdn_ppp_mp_bundle_array_init(void); +static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ); +static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff *skb); +static void isdn_ppp_mp_cleanup( isdn_net_local * lp ); + +static int isdn_ppp_bundle(struct ippp_struct *, int unit); +#endif /* CONFIG_ISDN_MPP */ + +char *isdn_ppp_revision = "$Revision: 1.1.2.3 $"; -/* ====================================================================== */ +static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; -static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(ipppds); +static struct isdn_ppp_compressor *ipc_head = NULL; +/* + * frame log (debug) + */ static void -ipppd_destroy(struct ipppd *ipppd) +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) { - HERE; + int cnt, + j, + i; + char buf[80]; - skb_queue_purge(&ipppd->rq); - kfree(ipppd); -} + if (len < maxlen) + maxlen = len; -static inline struct ipppd * -ipppd_get(struct ipppd *ipppd) -{ - atomic_inc(&ipppd->refcnt); - printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt)); - return ipppd; + for (i = 0, cnt = 0; cnt < maxlen; i++) { + for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) + sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]); + printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf); + } } -static inline void -ipppd_put(struct ipppd *ipppd) +/* + * unbind isdn_net_local <=> ippp-device + * note: it can happen, that we hangup/free the master before the slaves + * in this case we bind another lp to the master device + */ +int +isdn_ppp_free(isdn_net_local * lp) { - printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt)); - - if (atomic_dec_and_test(&ipppd->refcnt)) - ipppd_destroy(ipppd); -} - -/* ====================================================================== */ -/* char dev ops */ - -/* --- open ------------------------------------------------------------- */ + struct ippp_struct *is; -static int -ipppd_open(struct inode *ino, struct file *file) -{ - unsigned long flags; - unsigned int minor = iminor(ino) - ISDN_MINOR_PPP; - struct ipppd *ipppd; + if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", + __FUNCTION__, lp->ppp_slot); + return 0; + } - ipppd = kmalloc(sizeof(*ipppd), GFP_KERNEL); - if (!ipppd) - return -ENOMEM; +#ifdef CONFIG_ISDN_MPP + spin_lock(&lp->netdev->pb->lock); +#endif + isdn_net_rm_from_bundle(lp); +#ifdef CONFIG_ISDN_MPP + if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ + isdn_ppp_mp_cleanup(lp); + + lp->netdev->pb->ref_ct--; + spin_unlock(&lp->netdev->pb->lock); +#endif /* CONFIG_ISDN_MPP */ + if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", + __FUNCTION__, lp->ppp_slot); + return 0; + } + is = ippp_table[lp->ppp_slot]; + if ((is->state & IPPP_CONNECT)) + isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ + else if (is->state & IPPP_ASSIGNED) + is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ - memset(ipppd, 0, sizeof(*ipppd)); - atomic_set(&ipppd->refcnt, 0); - - /* file->private_data holds a reference */ - file->private_data = ipppd_get(ipppd); + if (is->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp); - ipppd->unit = -1; /* set by isdn_ppp_bind */ - ipppd->minor = minor; - ipppd->state = IPPPD_ST_OPEN; - init_waitqueue_head(&ipppd->wq); - skb_queue_head_init(&ipppd->rq); - - spin_lock_irqsave(&ipppds_lock, flags); - list_add(&ipppd->ipppds, &ipppds); - spin_unlock_irqrestore(&ipppds_lock, flags); - - ipppd_debug(ipppd, "minor %d", minor); + is->lp = NULL; /* link is down .. set lp to NULL */ + lp->ppp_slot = -1; /* is this OK ?? */ return 0; } -/* --- release --------------------------------------------------------- */ - -static int -ipppd_release(struct inode *ino, struct file *file) +/* + * bind isdn_net_local <=> ippp-device + * + * This function is allways called with holding dev->lock so + * no additional lock is needed + */ +int +isdn_ppp_bind(isdn_net_local * lp) { - unsigned long flags; - struct ipppd *ipppd = file->private_data; - - ipppd_debug(ipppd, ""); + int i; + int unit = 0; + struct ippp_struct *is; + int retval; - if (ipppd->state == IPPPD_ST_CONNECTED) - isdn_net_hangup(ipppd->idev); + if (lp->pppbind < 0) { /* device bounded to ippp device ? */ + isdn_net_dev *net_dev = dev->netdev; + char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ + memset(exclusive, 0, ISDN_MAX_CHANNELS); + while (net_dev) { /* step through net devices to find exclusive minors */ + isdn_net_local *lp = net_dev->local; + if (lp->pppbind >= 0) + exclusive[lp->pppbind] = 1; + net_dev = net_dev->next; + } + /* + * search a free device / slot + */ + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ + break; + } + } + } else { + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (ippp_table[i]->minor == lp->pppbind && + (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) + break; + } + } - spin_lock_irqsave(&ipppds_lock, flags); - list_del(&ipppd->ipppds); - spin_unlock_irqrestore(&ipppds_lock, flags); + if (i >= ISDN_MAX_CHANNELS) { + printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); + retval = -1; + goto out; + } + unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ + if (unit < 0) { + printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name); + retval = -1; + goto out; + } + + lp->ppp_slot = i; + is = ippp_table[i]; + is->lp = lp; + is->unit = unit; + is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ +#ifdef CONFIG_ISDN_MPP + retval = isdn_ppp_mp_init(lp, NULL); + if (retval < 0) + goto out; +#endif /* CONFIG_ISDN_MPP */ - ipppd_put(ipppd); + retval = lp->ppp_slot; - return 0; + out: + return retval; } -/* --- read ------------------------------------------------------------- */ +/* + * kick the ipppd on the device + * (wakes up daemon after B-channel connect) + */ -/* read() is always non blocking */ -static ssize_t -ipppd_read(struct file *file, char *buf, size_t count, loff_t *off) +void +isdn_ppp_wakeup_daemon(isdn_net_local * lp) { - struct ipppd *is; - struct sk_buff *skb; - int retval; + if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", + __FUNCTION__, lp->ppp_slot); + return; + } + ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; + wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); +} - if (off != &file->f_pos) - return -ESPIPE; - - is = file->private_data; +/* + * there was a hangup on the netdevice + * force wakeup of the ippp device + * go into 'device waits for release' state + */ +static int +isdn_ppp_closewait(int slot) +{ + struct ippp_struct *is; - skb = skb_dequeue(&is->rq); - if (!skb) { - retval = -EAGAIN; - goto out; - } - if (skb->len > count) { - retval = -EMSGSIZE; - goto out_free; - } - if (copy_to_user(buf, skb->data, skb->len)) { - retval = -EFAULT; - goto out_free; + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: slot(%d) out of range\n", + __FUNCTION__, slot); + return 0; } - retval = skb->len; - - out_free: - dev_kfree_skb(skb); - out: - return retval; + is = ippp_table[slot]; + if (is->state) + wake_up_interruptible(&is->wq); + is->state = IPPP_CLOSEWAIT; + return 1; } -/* --- write ------------------------------------------------------------ */ +/* + * isdn_ppp_find_slot / isdn_ppp_free_slot + */ -/* write() is always non blocking */ -static ssize_t -ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off) -{ - isdn_net_dev *idev; - struct inl_ppp *inl_ppp; - struct ind_ppp *ind_ppp; - struct ipppd *ipppd; - struct sk_buff *skb; - char *p; - int retval; - u16 proto; +static int +isdn_ppp_get_slot(void) +{ + int i; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (!ippp_table[i]->state) + return i; + } + return -1; +} - if (off != &file->f_pos) - return -ESPIPE; +/* + * isdn_ppp_open + */ - ipppd = file->private_data; - ipppd_debug(ipppd, "count = %d", count); +int +isdn_ppp_open(int min, struct file *file) +{ + int slot; + struct ippp_struct *is; - if (ipppd->state != IPPPD_ST_CONNECTED) { - retval = -ENOTCONN; - goto out; - } + if (min < 0 || min > ISDN_MAX_CHANNELS) + return -ENODEV; - idev = ipppd->idev; - if (!idev) { - isdn_BUG(); - retval = -ENODEV; - goto out; - } - ind_ppp = idev->ind_priv; - inl_ppp = idev->mlp->inl_priv; - /* Daemon needs to send at least full header, AC + proto */ - if (count < 4) { - retval = -EMSGSIZE; - goto out; - } - skb = isdn_ppp_dev_alloc_skb(idev, count, GFP_KERNEL); - if (!skb) { - retval = -ENOMEM; - goto out; + slot = isdn_ppp_get_slot(); + if (slot < 0) { + return -EBUSY; } - p = skb_put(skb, count); - if (copy_from_user(p, buf, count)) { - kfree_skb(skb); - retval = -EFAULT; - goto out; - } - /* Don't reset huptimer for LCP packets. (Echo requests). */ - proto = PPP_PROTOCOL(p); - if (proto != PPP_LCP) - idev->huptimer = 0; + is = file->private_data = ippp_table[slot]; - /* Keeps CCP/compression states in sync */ - switch (proto) { - case PPP_CCP: - ippp_ccp_send_ccp(inl_ppp->ccp, skb); - break; - case PPP_CCPFRAG: - ippp_ccp_send_ccp(ind_ppp->ccp, skb); - break; - } - /* FIXME: Somewhere we need protection against the - * queue growing too large */ - isdn_net_write_super(idev, skb); + printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", + slot, min, is->state); - retval = count; - - out: - return retval; -} + /* compression stuff */ + is->link_compressor = is->compressor = NULL; + is->link_decompressor = is->decompressor = NULL; + is->link_comp_stat = is->comp_stat = NULL; + is->link_decomp_stat = is->decomp_stat = NULL; + is->compflags = 0; + + is->reset = isdn_ppp_ccp_reset_alloc(is); + + is->lp = NULL; + is->mp_seqno = 0; /* MP sequence number */ + is->pppcfg = 0; /* ppp configuration */ + is->mpppcfg = 0; /* mppp configuration */ + is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ + is->unit = -1; /* set, when we have our interface */ + is->mru = 1524; /* MRU, default 1524 */ + is->maxcid = 16; /* VJ: maxcid */ + is->tk = current; + init_waitqueue_head(&is->wq); + is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + is->last = is->rq; + is->minor = min; +#ifdef CONFIG_ISDN_PPP_VJ + /* + * VJ header compression init + */ + is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ +#endif +#ifdef CONFIG_IPPP_FILTER + is->pass_filter.filter = NULL; + is->active_filter.filter = NULL; +#endif + is->state = IPPP_OPEN; -/* --- poll ------------------------------------------------------------- */ + return 0; +} -static unsigned int -ipppd_poll(struct file *file, poll_table * wait) +/* + * release ippp device + */ +void +isdn_ppp_release(int min, struct file *file) { - unsigned int mask; - struct ipppd *is; + int i; + struct ippp_struct *is; + if (min < 0 || min >= ISDN_MAX_CHANNELS) + return; is = file->private_data; - ipppd_debug(is, ""); + if (!is) { + printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__); + return; + } + if (is->debug & 0x1) + printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp); - /* just registers wait_queue hook. This doesn't really wait. */ - poll_wait(file, &is->wq, wait); + if (is->lp) { /* a lp address says: this link is still up */ + isdn_net_dev *p = is->lp->netdev; - if (is->flags & IPPPD_FL_HUP) { - mask = POLLHUP; - goto out; + if (!p) { + printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__); + return; + } + is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */ + /* + * isdn_net_hangup() calls isdn_ppp_free() + * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 + * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() + */ + isdn_net_hangup(&p->dev); } - /* we're always ready to send .. */ - mask = POLLOUT | POLLWRNORM; + for (i = 0; i < NUM_RCV_BUFFS; i++) { + if (is->rq[i].buf) { + kfree(is->rq[i].buf); + is->rq[i].buf = NULL; + } + } + is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + is->last = is->rq; - /* - * if IPPP_FL_WAKEUP is set we return even if we have nothing to read - */ - if (!skb_queue_empty(&is->rq) || is->flags & IPPPD_FL_WAKEUP) { - is->flags &= ~IPPPD_FL_WAKEUP; - mask |= POLLIN | POLLRDNORM; +#ifdef CONFIG_ISDN_PPP_VJ +/* TODO: if this was the previous master: link the slcomp to the new master */ + slhc_free(is->slcomp); + is->slcomp = NULL; +#endif +#ifdef CONFIG_IPPP_FILTER + if (is->pass_filter.filter) { + kfree(is->pass_filter.filter); + is->pass_filter.filter = NULL; + } + if (is->active_filter.filter) { + kfree(is->active_filter.filter); + is->active_filter.filter = NULL; } +#endif - out: - return mask; -} +/* TODO: if this was the previous master: link the stuff to the new master */ + if(is->comp_stat) + is->compressor->free(is->comp_stat); + if(is->link_comp_stat) + is->link_compressor->free(is->link_comp_stat); + if(is->link_decomp_stat) + is->link_decompressor->free(is->link_decomp_stat); + if(is->decomp_stat) + is->decompressor->free(is->decomp_stat); + is->compressor = is->link_compressor = NULL; + is->decompressor = is->link_decompressor = NULL; + is->comp_stat = is->link_comp_stat = NULL; + is->decomp_stat = is->link_decomp_stat = NULL; + + /* Clean up if necessary */ + if(is->reset) + isdn_ppp_ccp_reset_free(is); -/* --- ioctl ------------------------------------------------------------ */ + /* this slot is ready for new connections */ + is->state = 0; +} -/* get_arg .. ioctl helper */ +/* + * get_arg .. ioctl helper + */ static int -get_arg(unsigned long arg, void *val, int len) +get_arg(void *b, void *val, int len) { - if (copy_from_user((void *) val, (void *) arg, len)) + if (len <= 0) + len = sizeof(void *); + if (copy_from_user((void *) val, b, len)) return -EFAULT; return 0; } -/* set arg .. ioctl helper */ +/* + * set arg .. ioctl helper + */ static int -set_arg(unsigned long arg, void *val,int len) +set_arg(void *b, void *val,int len) { - if (copy_to_user((void *) arg, (void *) val, len)) + if(len <= 0) + len = sizeof(void *); + if (copy_to_user(b, (void *) val, len)) return -EFAULT; return 0; } -static int -ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, - unsigned long arg) +/* + * ippp device ioctl + */ +int +isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) { - isdn_net_dev *idev; - struct ind_ppp *ind_ppp = NULL; - struct inl_ppp *inl_ppp = NULL; unsigned long val; - int r; - struct ipppd *is; + int r,i,j; + struct ippp_struct *is; + isdn_net_local *lp; struct isdn_ppp_comp_data data; - unsigned int cfg; - is = file->private_data; - - ipppd_debug(is, "cmd %#x", cmd); - - // FIXME that needs locking? - idev = is->idev; - if (idev) { - ind_ppp = idev->ind_priv; - inl_ppp = idev->mlp->inl_priv; - } - switch (cmd) { - case PPPIOCGUNIT: /* get ppp/isdn unit number */ - r = set_arg(arg, &is->unit, sizeof(is->unit)); - break; - case PPPIOCGDEBUG: - r = set_arg(arg, &is->debug, sizeof(is->debug)); - break; - case PPPIOCSDEBUG: - r = get_arg(arg, &val, sizeof(val)); - if (r) - break; - is->debug = val; - if (idev) { - ind_ppp->debug = val; - inl_ppp->debug = val; - } - break; - case PPPIOCGCOMPRESSORS: - { - unsigned long protos[8]; - ippp_ccp_get_compressors(protos); - r = set_arg(arg, protos, sizeof(protos)); - break; - } - default: - r = -ENOTTY; - break; - } + is = (struct ippp_struct *) file->private_data; + lp = is->lp; - if (r != -ENOTTY) - goto out; + if (is->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state); - if (!idev) { - r = -ENODEV; - goto out; - } + if (!(is->state & IPPP_OPEN)) + return -EINVAL; switch (cmd) { - case PPPIOCBUNDLE: - r = get_arg(arg, &val, sizeof(val)); - if (r) + case PPPIOCBUNDLE: +#ifdef CONFIG_ISDN_MPP + if (!(is->state & IPPP_CONNECT)) + return -EINVAL; + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) + return r; + printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", + (int) min, (int) is->unit, (int) val); + return isdn_ppp_bundle(is, val); +#else + return -1; +#endif break; - - r = ippp_mp_bundle(idev, val); - break; - case PPPIOCGIFNAME: - r = set_arg(arg, idev->name, strlen(idev->name)+1); - break; - case PPPIOCGMPFLAGS: /* get configuration flags */ - r = set_arg(arg, &inl_ppp->mp_cfg, sizeof(inl_ppp->mp_cfg)); - break; - case PPPIOCSMPFLAGS: /* set configuration flags */ - r = get_arg(arg, &val, sizeof(val)); - if (r) + case PPPIOCGUNIT: /* get ppp/isdn unit number */ + if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) ))) + return r; break; - inl_ppp->mp_cfg = val; - break; - case PPPIOCGFLAGS: /* get configuration flags */ - cfg = ind_ppp->pppcfg | ippp_ccp_get_flags(ind_ppp->ccp); - r = set_arg(arg, &cfg, sizeof(cfg)); - break; - case PPPIOCSFLAGS: /* set configuration flags */ - r = get_arg(arg, &val, sizeof(val)); - if (r) + case PPPIOCGIFNAME: + if(!lp) + return -EINVAL; + if ((r = set_arg((void *) arg, lp->name, strlen(lp->name)))) + return r; break; - if ((val & SC_ENABLE_IP) && !(ind_ppp->pppcfg & SC_ENABLE_IP)) { - ind_ppp->pppcfg = val; - /* OK .. we are ready to send buffers */ - isdn_net_online(idev); + case PPPIOCGMPFLAGS: /* get configuration flags */ + if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) ))) + return r; break; - } - ind_ppp->pppcfg = val; - break; - case PPPIOCGIDLE: /* get idle time information */ - { - struct ppp_idle pidle; - pidle.xmit_idle = pidle.recv_idle = idev->huptimer; - r = set_arg(arg, &pidle,sizeof(pidle)); - break; - } - case PPPIOCSMRU: /* set receive unit size for PPP */ - r = get_arg(arg, &val, sizeof(val)); - if (r) + case PPPIOCSMPFLAGS: /* set configuration flags */ + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) + return r; + is->mpppcfg = val; break; - r = ippp_ccp_set_mru(ind_ppp->ccp, val); - break; - case PPPIOCSMPMRU: - break; - case PPPIOCSMPMTU: - break; - case PPPIOCSMAXCID: /* set the maximum compression slot id */ - r = get_arg(arg, &val, sizeof(val)); - if (r) + case PPPIOCGFLAGS: /* get configuration flags */ + if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) ))) + return r; break; - r = ippp_vj_set_maxcid(idev, val); - break; - case PPPIOCSCOMPRESSOR: - r = get_arg(arg, &data, sizeof(data)); - if (r) + case PPPIOCSFLAGS: /* set configuration flags */ + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { + return r; + } + if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { + if (lp) { + /* OK .. we are ready to send buffers */ + is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */ + netif_wake_queue(&lp->netdev->dev); + break; + } + } + is->pppcfg = val; break; - r = isdn_ppp_set_compressor(idev, &data); - break; - case PPPIOCGCALLINFO: - { - isdn_net_local *mlp; - struct isdn_net_phone *phone; - struct pppcallinfo pci; - int i; - memset(&pci, 0, sizeof(pci)); - - mlp = idev->mlp; - strlcpy(pci.local_num, mlp->msn, sizeof(pci.local_num)); - i = 0; - list_for_each_entry(phone, &mlp->phone[1], list) { - if (i++ == idev->dial) { - strlcpy(pci.remote_num,phone->num,sizeof(pci.remote_num)); - break; + case PPPIOCGIDLE: /* get idle time information */ + if (lp) { + struct ppp_idle pidle; + pidle.xmit_idle = pidle.recv_idle = lp->huptimer; + if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle)))) + return r; } - } - pci.charge_units = idev->charge; - if (idev->outgoing) - pci.calltype = CALLTYPE_OUTGOING; - else - pci.calltype = CALLTYPE_INCOMING; - if (mlp->flags & ISDN_NET_CALLBACK) - pci.calltype |= CALLTYPE_CALLBACK; - r = set_arg(arg, &pci, sizeof(pci)); - break; - } - default: - r = -ENOTTY; - break; - } - out: - return r; -} - -/* --- fops ------------------------------------------------------------- */ - -struct file_operations isdn_ppp_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ipppd_read, - .write = ipppd_write, - .poll = ipppd_poll, - .ioctl = ipppd_ioctl, - .open = ipppd_open, - .release = ipppd_release, -}; - -/* --- ipppd_queue_read ------------------------------------------------- */ - -/* Queue packets for ipppd to read(). */ - -static int -ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len) -{ - struct sk_buff *skb; - unsigned char *p; - int retval; - - if (is->state != IPPPD_ST_CONNECTED) { - printk(KERN_DEBUG "ippp: device not connected.\n"); - retval = -ENOTCONN; - goto out; - } - if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) { - printk(KERN_WARNING "ippp: Queue is full\n"); - retval = -EBUSY; - goto out; - } - skb = dev_alloc_skb(len + 4); - if (!skb) { - printk(KERN_WARNING "ippp: Can't alloc buf\n"); - retval = -ENOMEM; - goto out; - } - p = skb_put(skb, 4); - p += put_u8(p, PPP_ALLSTATIONS); - p += put_u8(p, PPP_UI); - p += put_u16(p, proto); - memcpy(skb_put(skb, len), buf, len); - - skb_queue_tail(&is->rq, skb); - wake_up(&is->wq); - - retval = len; - out: - return retval; -} - -/* ====================================================================== */ -/* interface to isdn_net_lib */ -/* ====================================================================== */ - - -/* Prototypes */ -static int -isdn_ppp_if_get_unit(char *namebuf); - -static void -isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb, u16 proto); - -static struct sk_buff * -isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask); - -/* New CCP stuff */ -static void -isdn_ppp_dev_kick_up(void *priv); - -/* - * frame log (debug) - */ -void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) -{ - int cnt, - j, - i; - char buf[80]; - - if (len < maxlen) - maxlen = len; - - for (i = 0, cnt = 0; cnt < maxlen; i++) { - for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) - sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]); - printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf); + break; + case PPPIOCSMRU: /* set receive unit size for PPP */ + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) + return r; + is->mru = val; + break; + case PPPIOCSMPMRU: + break; + case PPPIOCSMPMTU: + break; + case PPPIOCSMAXCID: /* set the maximum compression slot id */ + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) + return r; + val++; + if (is->maxcid != val) { +#ifdef CONFIG_ISDN_PPP_VJ + struct slcompress *sltmp; +#endif + if (is->debug & 0x1) + printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); + is->maxcid = val; +#ifdef CONFIG_ISDN_PPP_VJ + sltmp = slhc_init(16, val); + if (!sltmp) { + printk(KERN_ERR "ippp, can't realloc slhc struct\n"); + return -ENOMEM; + } + if (is->slcomp) + slhc_free(is->slcomp); + is->slcomp = sltmp; +#endif + } + break; + case PPPIOCGDEBUG: + if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) ))) + return r; + break; + case PPPIOCSDEBUG: + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) + return r; + is->debug = val; + break; + case PPPIOCGCOMPRESSORS: + { + unsigned long protos[8] = {0,}; + struct isdn_ppp_compressor *ipc = ipc_head; + while(ipc) { + j = ipc->num / (sizeof(long)*8); + i = ipc->num % (sizeof(long)*8); + if(j < 8) + protos[j] |= (0x1<next; + } + if ((r = set_arg((void *) arg,protos,8*sizeof(long) ))) + return r; + } + break; + case PPPIOCSCOMPRESSOR: + if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data)))) + return r; + return isdn_ppp_set_compressor(is, &data); + case PPPIOCGCALLINFO: + { + struct pppcallinfo pci; + memset((char *) &pci,0,sizeof(struct pppcallinfo)); + if(lp) + { + strncpy(pci.local_num,lp->msn,63); + if(lp->dial) { + strncpy(pci.remote_num,lp->dial->num,63); + } + pci.charge_units = lp->charge; + if(lp->outgoing) + pci.calltype = CALLTYPE_OUTGOING; + else + pci.calltype = CALLTYPE_INCOMING; + if(lp->flags & ISDN_NET_CALLBACK) + pci.calltype |= CALLTYPE_CALLBACK; + } + return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo)); + } +#ifdef CONFIG_IPPP_FILTER + case PPPIOCSPASS: + case PPPIOCSACTIVE: + { + struct sock_fprog uprog, *filtp; + struct sock_filter *code = NULL; + int len, err; + + if (copy_from_user(&uprog, (void *) arg, sizeof(uprog))) + return -EFAULT; + if (uprog.len > 0 && uprog.len < 65536) { + len = uprog.len * sizeof(struct sock_filter); + code = kmalloc(len, GFP_KERNEL); + if (code == NULL) + return -ENOMEM; + if (copy_from_user(code, uprog.filter, len)) { + kfree(code); + return -EFAULT; + } + err = sk_chk_filter(code, uprog.len); + if (err) { + kfree(code); + return err; + } + } + filtp = (cmd == PPPIOCSPASS) ? &is->pass_filter : &is->active_filter; + if (filtp->filter) + kfree(filtp->filter); + filtp->filter = code; + filtp->len = uprog.len; + break; + } +#endif /* CONFIG_IPPP_FILTER */ + default: + break; } + return 0; } -void -ippp_push_proto(struct ind_ppp *ind_ppp, struct sk_buff *skb, u16 proto) +unsigned int +isdn_ppp_poll(struct file *file, poll_table * wait) { - if (skb_headroom(skb) < 2) { - isdn_BUG(); - return; - } - if ((ind_ppp->pppcfg & SC_COMP_PROT) && proto <= 0xff) - put_u8(skb_push(skb, 1), proto); - else - put_u16(skb_push(skb, 2), proto); + u_int mask; + struct ippp_buf_queue *bf, *bl; + u_long flags; + struct ippp_struct *is; -} + is = file->private_data; -static void -ippp_push_ac(struct ind_ppp *ind_ppp, struct sk_buff *skb) -{ - unsigned char *p; + if (is->debug & 0x2) + printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", + MINOR(file->f_dentry->d_inode->i_rdev)); - if (skb_headroom(skb) < 2) { - isdn_BUG(); - return; + /* just registers wait_queue hook. This doesn't really wait. */ + poll_wait(file, &is->wq, wait); + + if (!(is->state & IPPP_OPEN)) { + if(is->state == IPPP_CLOSEWAIT) + return POLLHUP; + printk(KERN_DEBUG "isdn_ppp: device not open\n"); + return POLLERR; } - if (ind_ppp->pppcfg & SC_COMP_AC) - return; + /* we're always ready to send .. */ + mask = POLLOUT | POLLWRNORM; - p = skb_push(skb, 2); - p += put_u8(p, PPP_ALLSTATIONS); - p += put_u8(p, PPP_UI); + spin_lock_irqsave(&is->buflock, flags); + bl = is->last; + bf = is->first; + /* + * if IPPP_NOBLOCK is set we return even if we have nothing to read + */ + if (bf->next != bl || (is->state & IPPP_NOBLOCK)) { + is->state &= ~IPPP_NOBLOCK; + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_irqrestore(&is->buflock, flags); + return mask; } /* - * unbind isdn_net_local <=> ippp-device - * note: it can happen, that we hangup/free the master before the slaves - * in this case we bind another lp to the master device + * fill up isdn_ppp_read() queue .. */ -static void -isdn_ppp_unbind(isdn_net_dev *idev) -{ - struct ind_ppp *ind_ppp = idev->ind_priv; - struct ipppd *is = ind_ppp->ipppd; - - if (!is) { - isdn_BUG(); - return; - } - ipppd_debug(is, ""); - - if (is->state != IPPPD_ST_ASSIGNED) - isdn_BUG(); - is->state = IPPPD_ST_OPEN; - - /* is->idev will be invalid shortly */ - ippp_ccp_free(ind_ppp->ccp); - - is->idev = NULL; - /* lose the reference we took on isdn_ppp_bind */ - ipppd_put(is); - ind_ppp->ipppd = NULL; +static int +isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) +{ + struct ippp_buf_queue *bf, *bl; + u_long flags; + u_char *nbuf; + struct ippp_struct *is; - kfree(ind_ppp); - idev->ind_priv = NULL; + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { + printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); + return 0; + } + is = ippp_table[slot]; - return; + if (!(is->state & IPPP_CONNECT)) { + printk(KERN_DEBUG "ippp: device not activated.\n"); + return 0; + } + nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC); + if (!nbuf) { + printk(KERN_WARNING "ippp: Can't alloc buf\n"); + return 0; + } + nbuf[0] = PPP_ALLSTATIONS; + nbuf[1] = PPP_UI; + nbuf[2] = proto >> 8; + nbuf[3] = proto & 0xff; + memcpy(nbuf + 4, buf, len); + + spin_lock_irqsave(&is->buflock, flags); + bf = is->first; + bl = is->last; + + if (bf == bl) { + printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n"); + bf = bf->next; + kfree(bf->buf); + is->first = bf; + } + bl->buf = (char *) nbuf; + bl->len = len + 4; + + is->last = bl->next; + spin_unlock_irqrestore(&is->buflock, flags); + wake_up_interruptible(&is->wq); + return len; } /* - * bind isdn_net_local <=> ippp-device + * read() .. non-blocking: ipppd calls it only after select() + * reports, that there is data */ + int -isdn_ppp_bind(isdn_net_dev *idev) +isdn_ppp_read(int min, struct file *file, char *buf, int count) { - struct ind_ppp *ind_ppp; - int unit = 0; - unsigned long flags; - int retval = 0; - struct ipppd *ipppd; - - if (idev->ind_priv) { - isdn_BUG(); - return -EIO; - } - ind_ppp = kmalloc(sizeof(struct ind_ppp), GFP_KERNEL); - if (!ind_ppp) - return -ENOMEM; - - spin_lock_irqsave(&ipppds_lock, flags); - if (idev->pppbind < 0) { /* device not bound to ippp device ? */ - struct list_head *l; - char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ - memset(exclusive, 0, ISDN_MAX_CHANNELS); - /* step through net devices to find exclusive minors */ - list_for_each(l, &isdn_net_devs) { - isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list); - if (p->pppbind >= 0 && p->pppbind < ISDN_MAX_CHANNELS) - exclusive[p->pppbind] = 1; - } - /* - * search a free device / slot - */ - list_for_each_entry(ipppd, &ipppds, ipppds) { - if (!ipppd) - continue; - if (ipppd->state != IPPPD_ST_OPEN) - continue; - if (!exclusive[ipppd->minor]) - goto found; - } - } else { - list_for_each_entry(ipppd, &ipppds, ipppds) { - if (!ipppd) - continue; - if (ipppd->state != IPPPD_ST_OPEN) - continue; - if (ipppd->minor == idev->pppbind) - goto found; - } - } + struct ippp_struct *is; + struct ippp_buf_queue *b; + int r; + u_long flags; + u_char *save_buf; - printk(KERN_INFO "isdn_ppp_bind: no ipppd\n"); - retval = -ESRCH; - goto err; + is = file->private_data; - found: - unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */ - if (unit < 0) { - printk(KERN_INFO "isdn_ppp_bind: invalid interface name %s.\n", idev->name); - retval = -ENODEV; - goto err; - } - - ipppd->unit = unit; - ipppd->state = IPPPD_ST_ASSIGNED; - ipppd->idev = idev; - /* we hold a reference until isdn_ppp_unbind() */ - ipppd_get(ipppd); - spin_unlock_irqrestore(&ipppds_lock, flags); - - idev->ind_priv = ind_ppp; - ind_ppp->pppcfg = 0; /* config flags */ - ind_ppp->ipppd = ipppd; - ind_ppp->ccp = ippp_ccp_alloc(); - if (!ind_ppp->ccp) { - retval = -ENOMEM; - goto out; - } - ind_ppp->ccp->proto = PPP_COMPFRAG; - ind_ppp->ccp->priv = idev; - ind_ppp->ccp->alloc_skb = isdn_ppp_dev_alloc_skb; - ind_ppp->ccp->xmit = isdn_ppp_dev_xmit; - ind_ppp->ccp->kick_up = isdn_ppp_dev_kick_up; + if (!(is->state & IPPP_OPEN)) + return 0; - retval = ippp_mp_bind(idev); - if (retval) - goto out; - - return 0; + if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) + return r; - out: - ipppd->state = IPPPD_ST_OPEN; - ipppd_put(ipppd); - ind_ppp->ipppd = NULL; - kfree(ind_ppp); - idev->ind_priv = NULL; - return retval; + spin_lock_irqsave(&is->buflock, flags); + b = is->first->next; + save_buf = b->buf; + if (!save_buf) { + spin_unlock_irqrestore(&is->buflock, flags); + return -EAGAIN; + } + if (b->len < count) + count = b->len; + b->buf = NULL; + is->first = b; + + spin_unlock_irqrestore(&is->buflock, flags); + copy_to_user(buf, save_buf, count); + kfree(save_buf); - err: - spin_unlock_irqrestore(&ipppds_lock, flags); - kfree(ind_ppp); - return retval; + return count; } /* - * kick the ipppd on the device - * (wakes up daemon after B-channel connect) + * ipppd wanna write a packet to the card .. non-blocking */ -static void -isdn_ppp_connected(isdn_net_dev *idev) +int +isdn_ppp_write(int min, struct file *file, const char *buf, int count) { - struct ind_ppp *ind_ppp = idev->ind_priv; - struct ipppd *ipppd = ind_ppp->ipppd; + isdn_net_local *lp; + struct ippp_struct *is; + int proto; + unsigned char protobuf[4]; - ipppd_debug(ipppd, ""); + is = file->private_data; - ipppd->state = IPPPD_ST_CONNECTED; - ipppd->flags |= IPPPD_FL_WAKEUP; - wake_up(&ipppd->wq); -} + if (!(is->state & IPPP_CONNECT)) + return 0; -static void -isdn_ppp_disconnected(isdn_net_dev *idev) -{ - struct ind_ppp *ind_ppp = idev->ind_priv; - struct ipppd *ipppd = ind_ppp->ipppd; + lp = is->lp; - ipppd_debug(ipppd, ""); + /* -> push it directly to the lowlevel interface */ - if (ind_ppp->pppcfg & SC_ENABLE_IP) - isdn_net_offline(idev); + if (!lp) + printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); + else { + /* + * Don't reset huptimer for + * LCP packets. (Echo requests). + */ + if (copy_from_user(protobuf, buf, 4)) + return -EFAULT; + proto = PPP_PROTOCOL(protobuf); + if (proto != PPP_LCP) + lp->huptimer = 0; + + if (lp->isdn_device < 0 || lp->isdn_channel < 0) + return 0; + + if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && + lp->dialstate == 0 && + (lp->flags & ISDN_NET_CONNECTED)) { + unsigned short hl; + struct sk_buff *skb; + /* + * we need to reserve enought space in front of + * sk_buff. old call to dev_alloc_skb only reserved + * 16 bytes, now we are looking what the driver want + */ + hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; + skb = alloc_skb(hl+count, GFP_ATOMIC); + if (!skb) { + printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); + return count; + } + skb_reserve(skb, hl); + if (copy_from_user(skb_put(skb, count), buf, count)) + { + kfree_skb(skb); + return -EFAULT; + } + if (is->debug & 0x40) { + printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot); + } - if (ipppd->state != IPPPD_ST_CONNECTED) - isdn_BUG(); - - ipppd->state = IPPPD_ST_ASSIGNED; - ipppd->flags |= IPPPD_FL_HUP; - wake_up(&ipppd->wq); + isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */ - ippp_mp_disconnected(idev); + isdn_net_write_super(lp, skb); + } + } + return count; } /* @@ -807,44 +847,76 @@ isdn_ppp_disconnected(isdn_net_dev *idev int isdn_ppp_init(void) { + int i, + j; + +#ifdef CONFIG_ISDN_MPP + if( isdn_ppp_mp_bundle_array_init() < 0 ) + return -ENOMEM; +#endif /* CONFIG_ISDN_MPP */ + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (!(ippp_table[i] = (struct ippp_struct *) + kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { + printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); + for (j = 0; j < i; j++) + kfree(ippp_table[j]); + return -1; + } + memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); + spin_lock_init(&ippp_table[i]->buflock); + ippp_table[i]->state = 0; + ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; + ippp_table[i]->last = ippp_table[i]->rq; + + for (j = 0; j < NUM_RCV_BUFFS; j++) { + ippp_table[i]->rq[j].buf = NULL; + ippp_table[i]->rq[j].last = ippp_table[i]->rq + + (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS; + ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS; + } + } return 0; } void isdn_ppp_cleanup(void) { + int i; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + kfree(ippp_table[i]); + +#ifdef CONFIG_ISDN_MPP + if (isdn_ppp_bundle_arr) + kfree(isdn_ppp_bundle_arr); +#endif /* CONFIG_ISDN_MPP */ + } /* * check for address/control field and skip if allowed * retval != 0 -> discard packet silently */ -static int -isdn_ppp_skip_ac(struct ind_ppp *ind_ppp, struct sk_buff *skb) +static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) { - u8 val; - if (skb->len < 1) - return -EINVAL; - - get_u8(skb->data, &val); - if (val != PPP_ALLSTATIONS) { - /* if AC compression was not negotiated, but no AC present, - discard packet */ - if (ind_ppp->pppcfg & SC_REJ_COMP_AC) - return -EINVAL; + return -1; - return 0; - } - if (skb->len < 2) - return -EINVAL; + if (skb->data[0] == 0xff) { + if (skb->len < 2) + return -1; - get_u8(skb->data + 1, &val); - if (val != PPP_UI) - return -EINVAL; + if (skb->data[1] != 0x03) + return -1; - /* skip address/control (AC) field */ - skb_pull(skb, 2); + // skip address/control (AC) field + skb_pull(skb, 2); + } else { + if (is->pppcfg & SC_REJ_COMP_AC) + // if AC compression was not negotiated, but used, discard packet + return -1; + } return 0; } @@ -852,127 +924,262 @@ isdn_ppp_skip_ac(struct ind_ppp *ind_ppp * get the PPP protocol header and pull skb * retval < 0 -> discard packet silently */ -int -isdn_ppp_strip_proto(struct sk_buff *skb, u16 *proto) +static int isdn_ppp_strip_proto(struct sk_buff *skb) { - u8 val; - + int proto; + if (skb->len < 1) - return -EINVAL; + return -1; - get_u8(skb->data, &val); - if (val & 0x1) { - /* protocol field is compressed */ - *proto = val; + if (skb->data[0] & 0x1) { + // protocol field is compressed + proto = skb->data[0]; skb_pull(skb, 1); } else { if (skb->len < 2) - return -EINVAL; - get_u16(skb->data, proto); + return -1; + proto = ((int) skb->data[0] << 8) + skb->data[1]; skb_pull(skb, 2); } - return 0; + return proto; } + /* * handler for incoming packets on a syncPPP interface */ -static void -isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb) +void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { - struct ind_ppp *ind_ppp = idev->ind_priv; - struct ipppd *is = ind_ppp->ipppd; - u16 proto; - - if (!is) - goto err; - - if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: is:%p lp:%p unit:%d len:%d\n", - is, lp, is->unit, skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,-1); + struct ippp_struct *is; + int slot; + int proto; + + if (net_dev->local->master) + BUG(); // we're called with the master device always + + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", + lp->ppp_slot); + kfree_skb(skb); + return; } + is = ippp_table[slot]; - if (isdn_ppp_skip_ac(ind_ppp, skb) < 0) - goto err; - - if (isdn_ppp_strip_proto(skb, &proto)) - goto err; - - ippp_mp_receive(idev, skb, proto); - return; - - err: - lp->stats.rx_dropped++; - kfree_skb(skb); + if (is->debug & 0x4) { + printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n", + (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len); + isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot); + } + + if (isdn_ppp_skip_ac(is, skb) < 0) { + kfree_skb(skb); + return; + } + proto = isdn_ppp_strip_proto(skb); + if (proto < 0) { + kfree_skb(skb); + return; + } + +#ifdef CONFIG_ISDN_MPP + if (is->compflags & SC_LINK_DECOMP_ON) { + skb = isdn_ppp_decompress(skb, is, NULL, &proto); + if (!skb) // decompression error + return; + } + + if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP + if (proto == PPP_MP) { + isdn_ppp_mp_receive(net_dev, lp, skb); + return; + } + } +#endif + isdn_ppp_push_higher(net_dev, lp, skb, proto); } /* + * we receive a reassembled frame, MPPP has been taken care of before. * address/control and protocol have been stripped from the skb + * note: net_dev has to be master net_dev */ -void -ippp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto) +static void +isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto) { - isdn_net_local *lp = idev->mlp; - struct inl_ppp *inl_ppp = lp->inl_priv; - struct ind_ppp *ind_ppp = idev->ind_priv; - struct ipppd *is = ind_ppp->ipppd; + struct net_device *dev = &net_dev->dev; + struct ippp_struct *is, *mis; + isdn_net_local *mlp = NULL; + int slot; + + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n", + lp->ppp_slot); + goto drop_packet; + } + is = ippp_table[slot]; + + if (lp->master) { // FIXME? + mlp = (isdn_net_local *) lp->master->priv; + slot = mlp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n", + lp->ppp_slot); + goto drop_packet; + } + } + mis = ippp_table[slot]; if (is->debug & 0x10) { printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("rpush", skb->data, skb->len, 256, is->unit, -1); + isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } - /* all packets need to be passed through the compressor */ - skb = ippp_ccp_decompress(inl_ppp->ccp, skb, &proto); - if (!skb) /* decompression error */ - goto error; - + if (mis->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_decompress(skb, is, mis, &proto); + if (!skb) // decompression error + return; + } switch (proto) { case PPP_IPX: /* untested */ if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: IPX\n"); - isdn_netif_rx(idev, skb, htons(ETH_P_IPX)); + skb->protocol = htons(ETH_P_IPX); break; case PPP_IP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: IP\n"); - isdn_netif_rx(idev, skb, htons(ETH_P_IP)); + skb->protocol = htons(ETH_P_IP); break; case PPP_COMP: case PPP_COMPFRAG: printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); - goto drop; + goto drop_packet; +#ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); + if (net_dev->local->ppp_slot < 0) { + printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", + __FUNCTION__, net_dev->local->ppp_slot); + goto drop_packet; + } + if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { + printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); + goto drop_packet; + } + skb->protocol = htons(ETH_P_IP); + break; case PPP_VJC_COMP: - ippp_vj_decompress(idev, skb, proto); + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); + { + struct sk_buff *skb_old = skb; + int pkt_len; + skb = dev_alloc_skb(skb_old->len + 128); + + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); + skb = skb_old; + goto drop_packet; + } + skb_put(skb, skb_old->len + 128); + memcpy(skb->data, skb_old->data, skb_old->len); + if (net_dev->local->ppp_slot < 0) { + printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", + __FUNCTION__, net_dev->local->ppp_slot); + goto drop_packet; + } + pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, + skb->data, skb_old->len); + kfree_skb(skb_old); + if (pkt_len < 0) + goto drop_packet; + + skb_trim(skb, pkt_len); + skb->protocol = htons(ETH_P_IP); + } break; - case PPP_CCPFRAG: - ippp_ccp_receive_ccp(ind_ppp->ccp, skb); - goto ccp; +#endif case PPP_CCP: - ippp_ccp_receive_ccp(inl_ppp->ccp, skb); - ccp: + case PPP_CCPFRAG: + isdn_ppp_receive_ccp(net_dev,lp,skb,proto); /* Dont pop up ResetReq/Ack stuff to the daemon any longer - the job is done already */ if(skb->data[0] == CCP_RESETREQ || skb->data[0] == CCP_RESETACK) - goto free; + break; /* fall through */ default: - // FIXME use skb directly - ipppd_queue_read(is, proto, skb->data, skb->len); - goto free; + isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ + kfree_skb(skb); + return; + } + +#ifdef CONFIG_IPPP_FILTER + /* check if the packet passes the pass and active filters + * the filter instructions are constructed assuming + * a four-byte PPP header on each packet (which is still present) */ + skb_push(skb, 4); + skb->data[0] = 0; /* indicate inbound */ + + if (is->pass_filter.filter + && sk_run_filter(skb, is->pass_filter.filter, + is->pass_filter.len) == 0) { + if (is->debug & 0x2) + printk(KERN_DEBUG "IPPP: inbound frame filtered.\n"); + kfree_skb(skb); + return; } + if (!(is->active_filter.filter + && sk_run_filter(skb, is->active_filter.filter, + is->active_filter.len) == 0)) { + if (is->debug & 0x2) + printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n"); + lp->huptimer = 0; + if (mlp) + mlp->huptimer = 0; + } + skb_pull(skb, 4); +#else /* CONFIG_IPPP_FILTER */ + lp->huptimer = 0; + if (mlp) + mlp->huptimer = 0; +#endif /* CONFIG_IPPP_FILTER */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ return; - drop: - lp->stats.rx_dropped++; - free: + drop_packet: + net_dev->local->stats.rx_dropped++; kfree_skb(skb); - return; +} + +/* + * isdn_ppp_skb_push .. + * checks whether we have enough space at the beginning of the skb + * and allocs a new SKB if necessary + */ +static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len) +{ + struct sk_buff *skb = *skb_p; + + if(skb_headroom(skb) < len) { + struct sk_buff *nskb = skb_realloc_headroom(skb, len); - error: - lp->stats.rx_dropped++; + if (!nskb) { + printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n"); + dev_kfree_skb(skb); + return NULL; + } + printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len); + dev_kfree_skb(skb); + *skb_p = nskb; + return skb_push(nskb, len); + } + return skb_push(skb,len); } /* @@ -983,99 +1190,773 @@ ippp_receive(isdn_net_dev *idev, struct * skb isn't allowed!! */ -static int -isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) +int +isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + isdn_net_local *lp,*mlp; + isdn_net_dev *nd; + unsigned int proto = PPP_IP; /* 0x21 */ + struct ippp_struct *ipt,*ipts; + int slot, retval = 0; + + mlp = (isdn_net_local *) (netdev->priv); + nd = mlp->netdev; /* get master lp */ + + slot = mlp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", + mlp->ppp_slot); + kfree_skb(skb); + goto out; + } + ipts = ippp_table[slot]; + + if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ + if (ipts->debug & 0x1) + printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); + retval = 1; + goto out; + } + + switch (ntohs(skb->protocol)) { + case ETH_P_IP: + proto = PPP_IP; + break; + case ETH_P_IPX: + proto = PPP_IPX; /* untested */ + break; + default: + printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", + skb->protocol); + dev_kfree_skb(skb); + goto out; + } + + lp = isdn_net_get_locked_lp(nd); + if (!lp) { + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); + retval = 1; + goto out; + } + /* we have our lp locked from now on */ + + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", + lp->ppp_slot); + kfree_skb(skb); + goto unlock; + } + ipt = ippp_table[slot]; + + /* + * after this line .. requeueing in the device queue is no longer allowed!!! + */ + + /* Pull off the fake header we stuck on earlier to keep + * the fragmentation code happy. + */ + skb_pull(skb,IPPP_MAX_HEADER); + +#ifdef CONFIG_IPPP_FILTER + /* check if we should pass this packet + * the filter instructions are constructed assuming + * a four-byte PPP header on each packet */ + skb_push(skb, 4); + skb->data[0] = 1; /* indicate outbound */ + *(u_int16_t *)(skb->data + 2) = htons(proto); + + if (ipt->pass_filter.filter + && sk_run_filter(skb, ipt->pass_filter.filter, + ipt->pass_filter.len) == 0) { + if (ipt->debug & 0x4) + printk(KERN_DEBUG "IPPP: outbound frame filtered.\n"); + kfree_skb(skb); + goto unlock; + } + if (!(ipt->active_filter.filter + && sk_run_filter(skb, ipt->active_filter.filter, + ipt->active_filter.len) == 0)) { + if (ipt->debug & 0x4) + printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n"); + lp->huptimer = 0; + } + skb_pull(skb, 4); +#else /* CONFIG_IPPP_FILTER */ + lp->huptimer = 0; +#endif /* CONFIG_IPPP_FILTER */ + + if (ipt->debug & 0x4) + printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); + if (ipts->debug & 0x40) + isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot); + +#ifdef CONFIG_ISDN_PPP_VJ + if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ + struct sk_buff *new_skb; + unsigned short hl; + /* + * we need to reserve enought space in front of + * sk_buff. old call to dev_alloc_skb only reserved + * 16 bytes, now we are looking what the driver want. + */ + hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER; + /* + * Note: hl might still be insufficient because the method + * above does not account for a possibible MPPP slave channel + * which had larger HL header space requirements than the + * master. + */ + new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC); + if (new_skb) { + u_char *buf; + int pktlen; + + skb_reserve(new_skb, hl); + new_skb->dev = skb->dev; + skb_put(new_skb, skb->len); + buf = skb->data; + + pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, + &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); + + if (buf != skb->data) { + if (new_skb->data != buf) + printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n"); + dev_kfree_skb(skb); + skb = new_skb; + } else { + dev_kfree_skb(new_skb); + } + + skb_trim(skb, pktlen); + if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */ + proto = PPP_VJC_COMP; + skb->data[0] ^= SL_TYPE_COMPRESSED_TCP; + } else { + if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP) + proto = PPP_VJC_UNCOMP; + skb->data[0] = (skb->data[0] & 0x0f) | 0x40; + } + } + } +#endif + + /* + * normal (single link) or bundle compression + */ + if(ipts->compflags & SC_COMP_ON) { + /* We send compressed only if both down- und upstream + compression is negotiated, that means, CCP is up */ + if(ipts->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + } else { + printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); + } + } + + if (ipt->debug & 0x24) + printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); + +#ifdef CONFIG_ISDN_MPP + if (ipt->mpppcfg & SC_MP_PROT) { + /* we get mp_seqno from static isdn_net_local */ + long mp_seqno = ipts->mp_seqno; + ipts->mp_seqno++; + if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { + unsigned char *data = isdn_ppp_skb_push(&skb, 3); + if(!data) + goto unlock; + mp_seqno &= 0xfff; + data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */ + data[1] = mp_seqno & 0xff; + data[2] = proto; /* PID compression */ + } else { + unsigned char *data = isdn_ppp_skb_push(&skb, 5); + if(!data) + goto unlock; + data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ + data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ + data[2] = (mp_seqno >> 8) & 0xff; + data[3] = (mp_seqno >> 0) & 0xff; + data[4] = proto; /* PID compression */ + } + proto = PPP_MP; /* MP Protocol, 0x003d */ + } +#endif + + /* + * 'link in bundle' compression ... + */ + if(ipt->compflags & SC_LINK_COMP_ON) + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); + + if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { + unsigned char *data = isdn_ppp_skb_push(&skb,1); + if(!data) + goto unlock; + data[0] = proto & 0xff; + } + else { + unsigned char *data = isdn_ppp_skb_push(&skb,2); + if(!data) + goto unlock; + data[0] = (proto >> 8) & 0xff; + data[1] = proto & 0xff; + } + if(!(ipt->pppcfg & SC_COMP_AC)) { + unsigned char *data = isdn_ppp_skb_push(&skb,2); + if(!data) + goto unlock; + data[0] = 0xff; /* All Stations */ + data[1] = 0x03; /* Unnumbered information */ + } + + /* tx-stats are now updated via BSENT-callback */ + + if (ipts->debug & 0x40) { + printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot); + } + + isdn_net_writebuf_skb(lp, skb); + + unlock: + spin_unlock_bh(&lp->xmit_lock); + out: + return retval; +} + +#ifdef CONFIG_IPPP_FILTER +/* + * check if this packet may trigger auto-dial. + */ + +int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) +{ + struct ippp_struct *is = ippp_table[lp->ppp_slot]; + u_int16_t proto; + int drop = 0; + + switch (ntohs(skb->protocol)) { + case ETH_P_IP: + proto = PPP_IP; + break; + case ETH_P_IPX: + proto = PPP_IPX; + break; + default: + printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n", + skb->protocol); + return 1; + } + + /* the filter instructions are constructed assuming + * a four-byte PPP header on each packet. we have to + * temporarily remove part of the fake header stuck on + * earlier. + */ + skb_pull(skb, IPPP_MAX_HEADER - 4); + skb->data[0] = 1; /* indicate outbound */ + *(u_int16_t *)(skb->data + 2) = htons(proto); + + drop |= is->pass_filter.filter + && sk_run_filter(skb, is->pass_filter.filter, + is->pass_filter.len) == 0; + drop |= is->active_filter.filter + && sk_run_filter(skb, is->active_filter.filter, + is->active_filter.len) == 0; + + skb_push(skb, IPPP_MAX_HEADER - 4); + return drop; +} +#endif +#ifdef CONFIG_ISDN_MPP + +/* this is _not_ rfc1990 header, but something we convert both short and long + * headers to for convinience's sake: + * byte 0 is flags as in rfc1990 + * bytes 1...4 is 24-bit seqence number converted to host byte order + */ +#define MP_HEADER_LEN 5 + +#define MP_LONGSEQ_MASK 0x00ffffff +#define MP_SHORTSEQ_MASK 0x00000fff +#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK +#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK +#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1) +#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1) + +/* sequence-wrap safe comparisions (for long sequence)*/ +#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT) +#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT) +#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT) +#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT) + +#define MP_SEQ(f) ((*(u32*)(f->data+1))) +#define MP_FLAGS(f) (f->data[0]) + +static int isdn_ppp_mp_bundle_array_init(void) +{ + int i; + int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); + if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz, + GFP_KERNEL)) == NULL ) + return -ENOMEM; + memset(isdn_ppp_bundle_arr, 0, sz); + for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) + spin_lock_init(&isdn_ppp_bundle_arr[i].lock); + return 0; +} + +static ippp_bundle * isdn_ppp_mp_bundle_alloc(void) { - isdn_net_local *mlp = ndev->priv; - struct inl_ppp *inl_ppp = mlp->inl_priv; - struct ind_ppp *ind_ppp; - isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online); - u16 proto = PPP_IP; /* 0x21 */ - struct ipppd *ipppd; + int i; + for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) + if (isdn_ppp_bundle_arr[i].ref_ct <= 0) + return (isdn_ppp_bundle_arr + i); + return NULL; +} + +static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) +{ + struct ippp_struct * is; + + if (lp->ppp_slot < 0) { + printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", + __FUNCTION__, lp->ppp_slot); + return(-EINVAL); + } + + is = ippp_table[lp->ppp_slot]; + if (add_to) { + if( lp->netdev->pb ) + lp->netdev->pb->ref_ct--; + lp->netdev->pb = add_to; + } else { /* first link in a bundle */ + is->mp_seqno = 0; + if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) + return -ENOMEM; + lp->next = lp->last = lp; /* nobody else in a queue */ + lp->netdev->pb->frags = NULL; + lp->netdev->pb->frames = 0; + lp->netdev->pb->seq = LONG_MAX; + } + lp->netdev->pb->ref_ct++; + + is->last_link_seqno = 0; + return 0; +} - ndev->trans_start = jiffies; +static u32 isdn_ppp_mp_get_seq( int short_seq, + struct sk_buff * skb, u32 last_seq ); +static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, + struct sk_buff * from, struct sk_buff * to ); +static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff * from, struct sk_buff * to ); +static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); +static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); + +static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff *skb) +{ + struct ippp_struct *is; + isdn_net_local * lpq; + ippp_bundle * mp; + isdn_mppp_stats * stats; + struct sk_buff * newfrag, * frag, * start, *nextf; + u32 newseq, minseq, thisseq; + unsigned long flags; + int slot; - if (list_empty(&mlp->online)) - return isdn_net_autodial(skb, ndev); + spin_lock_irqsave(&net_dev->pb->lock, flags); + mp = net_dev->pb; + stats = &mp->stats; + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", + __FUNCTION__, lp->ppp_slot); + stats->frame_drops++; + dev_kfree_skb(skb); + spin_unlock_irqrestore(&mp->lock, flags); + return; + } + is = ippp_table[slot]; + if( ++mp->frames > stats->max_queue_len ) + stats->max_queue_len = mp->frames; + + if (is->debug & 0x8) + isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb); - switch (ntohs(skb->protocol)) { - case ETH_P_IP: - proto = PPP_IP; - break; - case ETH_P_IPX: - proto = PPP_IPX; /* untested */ + newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, + skb, is->last_link_seqno); + + + /* if this packet seq # is less than last already processed one, + * toss it right away, but check for sequence start case first + */ + if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) { + mp->seq = newseq; /* the first packet: required for + * rfc1990 non-compliant clients -- + * prevents constant packet toss */ + } else if( MP_LT(newseq, mp->seq) ) { + stats->frame_drops++; + isdn_ppp_mp_free_skb(mp, skb); + spin_unlock_irqrestore(&mp->lock, flags); + return; + } + + /* find the minimum received sequence number over all links */ + is->last_link_seqno = minseq = newseq; + for (lpq = net_dev->queue;;) { + slot = lpq->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", + __FUNCTION__, lpq->ppp_slot); + } else { + u32 lls = ippp_table[slot]->last_link_seqno; + if (MP_LT(lls, minseq)) + minseq = lls; + } + if ((lpq = lpq->next) == net_dev->queue) break; - default: - printk(KERN_INFO "isdn_ppp: skipped unsupported protocol: %#x.\n", - skb->protocol); - goto drop; } + if (MP_LT(minseq, mp->seq)) + minseq = mp->seq; /* can't go beyond already processed + * packets */ + newfrag = skb; + + /* if this new fragment is before the first one, then enqueue it now. */ + if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { + newfrag->next = frag; + mp->frags = frag = newfrag; + newfrag = NULL; + } + + start = MP_FLAGS(frag) & MP_BEGIN_FRAG && + MP_SEQ(frag) == mp->seq ? frag : NULL; + + /* + * main fragment traversing loop + * + * try to accomplish several tasks: + * - insert new fragment into the proper sequence slot (once that's done + * newfrag will be set to NULL) + * - reassemble any complete fragment sequence (non-null 'start' + * indicates there is a continguous sequence present) + * - discard any incomplete sequences that are below minseq -- due + * to the fact that sender always increment sequence number, if there + * is an incomplete sequence below minseq, no new fragments would + * come to complete such sequence and it should be discarded + * + * loop completes when we accomplished the following tasks: + * - new fragment is inserted in the proper sequence ('newfrag' is + * set to NULL) + * - we hit a gap in the sequence, so no reassembly/processing is + * possible ('start' would be set to NULL) + * + * algorightm for this code is derived from code in the book + * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) + */ + while (start != NULL || newfrag != NULL) { + + thisseq = MP_SEQ(frag); + nextf = frag->next; + + /* drop any duplicate fragments */ + if (newfrag != NULL && thisseq == newseq) { + isdn_ppp_mp_free_skb(mp, newfrag); + newfrag = NULL; + } + + /* insert new fragment before next element if possible. */ + if (newfrag != NULL && (nextf == NULL || + MP_LT(newseq, MP_SEQ(nextf)))) { + newfrag->next = nextf; + frag->next = nextf = newfrag; + newfrag = NULL; + } + + if (start != NULL) { + /* check for misplaced start */ + if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { + printk(KERN_WARNING"isdn_mppp(seq %d): new " + "BEGIN flag with no prior END", thisseq); + stats->seqerrs++; + stats->frame_drops++; + start = isdn_ppp_mp_discard(mp, start,frag); + nextf = frag->next; + } + } else if (MP_LE(thisseq, minseq)) { + if (MP_FLAGS(frag) & MP_BEGIN_FRAG) + start = frag; + else { + if (MP_FLAGS(frag) & MP_END_FRAG) + stats->frame_drops++; + if( mp->frags == frag ) + mp->frags = nextf; + isdn_ppp_mp_free_skb(mp, frag); + frag = nextf; + continue; + } + } + + /* if start is non-null and we have end fragment, then + * we have full reassembly sequence -- reassemble + * and process packet now + */ + if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { + minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; + /* Reassemble the packet then dispatch it */ + isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); + + start = NULL; + frag = NULL; + + mp->frags = nextf; + } + + /* check if need to update start pointer: if we just + * reassembled the packet and sequence is contiguous + * then next fragment should be the start of new reassembly + * if sequence is contiguous, but we haven't reassembled yet, + * keep going. + * if sequence is not contiguous, either clear everyting + * below low watermark and set start to the next frag or + * clear start ptr. + */ + if (nextf != NULL && + ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { + /* if we just reassembled and the next one is here, + * then start another reassembly. */ + + if (frag == NULL) { + if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) + start = nextf; + else + { + printk(KERN_WARNING"isdn_mppp(seq %d):" + " END flag with no following " + "BEGIN", thisseq); + stats->seqerrs++; + } + } - idev = isdn_net_get_xmit_dev(mlp); - if (!idev) { - printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); - goto stop; + } else { + if ( nextf != NULL && frag != NULL && + MP_LT(thisseq, minseq)) { + /* we've got a break in the sequence + * and we not at the end yet + * and we did not just reassembled + *(if we did, there wouldn't be anything before) + * and we below the low watermark + * discard all the frames below low watermark + * and start over */ + stats->frame_drops++; + mp->frags = isdn_ppp_mp_discard(mp,start,nextf); + } + /* break in the sequence, no reassembly */ + start = NULL; + } + + frag = nextf; + } /* while -- main loop */ + + if (mp->frags == NULL) + mp->frags = frag; + + /* rather straighforward way to deal with (not very) possible + * queue overflow */ + if (mp->frames > MP_MAX_QUEUE_LEN) { + stats->overflows++; + while (mp->frames > MP_MAX_QUEUE_LEN) { + frag = mp->frags->next; + isdn_ppp_mp_free_skb(mp, mp->frags); + mp->frags = frag; + } } - ind_ppp = idev->ind_priv; - if (!(ind_ppp->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - isdn_BUG(); - goto stop; + spin_unlock_irqrestore(&mp->lock, flags); +} + +static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) +{ + struct sk_buff * frag = lp->netdev->pb->frags; + struct sk_buff * nextfrag; + while( frag ) { + nextfrag = frag->next; + isdn_ppp_mp_free_skb(lp->netdev->pb, frag); + frag = nextfrag; } - ipppd = ind_ppp->ipppd; - idev->huptimer = 0; + lp->netdev->pb->frags = NULL; +} - if (ipppd->debug & 0x40) - isdn_ppp_frame_log("xmit0", skb->data, skb->len, 256, ipppd->unit, -1); +static u32 isdn_ppp_mp_get_seq( int short_seq, + struct sk_buff * skb, u32 last_seq ) +{ + u32 seq; + int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG); + + if( !short_seq ) + { + seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK; + skb_push(skb,1); + } + else + { + /* convert 12-bit short seq number to 24-bit long one + */ + seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK; + + /* check for seqence wrap */ + if( !(seq & MP_SHORTSEQ_MAXBIT) && + (last_seq & MP_SHORTSEQ_MAXBIT) && + (unsigned long)last_seq <= MP_LONGSEQ_MAX ) + seq |= (last_seq + MP_SHORTSEQ_MAX+1) & + (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); + else + seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); + + skb_push(skb, 3); /* put converted seqence back in skb */ + } + *(u32*)(skb->data+1) = seq; /* put seqence back in _host_ byte + * order */ + skb->data[0] = flags; /* restore flags */ + return seq; +} + +struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, + struct sk_buff * from, struct sk_buff * to ) +{ + if( from ) + while (from != to) { + struct sk_buff * next = from->next; + isdn_ppp_mp_free_skb(mp, from); + from = next; + } + return from; +} - /* after this line,requeueing is no longer allowed! */ - skb = ippp_vj_compress(idev, skb, &proto); +void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff * from, struct sk_buff * to ) +{ + ippp_bundle * mp = net_dev->pb; + int proto; + struct sk_buff * skb; + unsigned int tot_len; - /* normal (single link) or bundle compression */ - skb = ippp_ccp_compress(inl_ppp->ccp, skb, &proto); + if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", + __FUNCTION__, lp->ppp_slot); + return; + } + if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) + printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " + "len %d\n", MP_SEQ(from), from->len ); + skb = from; + skb_pull(skb, MP_HEADER_LEN); + mp->frames--; + } else { + struct sk_buff * frag; + int n; - if (ipppd->debug & 0x40) - isdn_ppp_frame_log("xmit1", skb->data, skb->len, 32, ipppd->unit, -1); + for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) + tot_len += frag->len - MP_HEADER_LEN; - ippp_push_proto(ind_ppp, skb, proto); - ippp_mp_xmit(idev, skb); - return 0; + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) + printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " + "to %d, len %d\n", MP_SEQ(from), + (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); + if( (skb = dev_alloc_skb(tot_len)) == NULL ) { + printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " + "of size %d\n", tot_len); + isdn_ppp_mp_discard(mp, from, to); + return; + } - drop: - kfree_skb(skb); - mlp->stats.tx_dropped++; - return 0; + while( from != to ) { + unsigned int len = from->len - MP_HEADER_LEN; - stop: - netif_stop_queue(ndev); - return 1; + memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len); + frag = from->next; + isdn_ppp_mp_free_skb(mp, from); + from = frag; + } + } + proto = isdn_ppp_strip_proto(skb); + isdn_ppp_push_higher(net_dev, lp, skb, proto); } -void -ippp_xmit(isdn_net_dev *idev, struct sk_buff *skb) +static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb) +{ + dev_kfree_skb(skb); + mp->frames--; +} + +static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ) { - struct ind_ppp *ind_ppp = idev->ind_priv; - struct ipppd *ipppd = ind_ppp->ipppd; + printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n", + slot, (int) skb->len, + (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], + (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); +} - ippp_push_ac(ind_ppp, skb); +static int +isdn_ppp_bundle(struct ippp_struct *is, int unit) +{ + char ifn[IFNAMSIZ + 1]; + isdn_net_dev *p; + isdn_net_local *lp, *nlp; + int rc; + unsigned long flags; - if (ipppd->debug & 0x40) { - isdn_ppp_frame_log("xmit3", skb->data, skb->len, 32, ipppd->unit, -1); + sprintf(ifn, "ippp%d", unit); + p = isdn_net_findif(ifn); + if (!p) { + printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn); + return -EINVAL; } - - isdn_net_writebuf_skb(idev, skb); -} + spin_lock_irqsave(&p->pb->lock, flags); + + nlp = is->lp; + lp = p->queue; + if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS || + lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) { + printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n", + nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? + nlp->ppp_slot : lp->ppp_slot ); + rc = -EINVAL; + goto out; + } + + isdn_net_add_to_bundle(p, nlp); + + ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; + + /* maybe also SC_CCP stuff */ + ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & + (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); + ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & + (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); + rc = isdn_ppp_mp_init(nlp, p->pb); +out: + spin_unlock_irqrestore(&p->pb->lock, flags); + return rc; +} + +#endif /* CONFIG_ISDN_MPP */ + /* * network device ioctl handlers */ static int -isdn_ppp_dev_ioctl_stats(struct ifreq *ifr, struct net_device *dev) +isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) { - struct ppp_stats *res, t; + struct ppp_stats *res, + t; isdn_net_local *lp = (isdn_net_local *) dev->priv; - struct inl_ppp *inl_ppp = lp->inl_priv; - struct slcompress *slcomp; int err; res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; @@ -1095,8 +1976,8 @@ isdn_ppp_dev_ioctl_stats(struct ifreq *i t.p.ppp_obytes = lp->stats.tx_bytes; t.p.ppp_oerrors = lp->stats.tx_errors; #ifdef CONFIG_ISDN_PPP_VJ - slcomp = inl_ppp->slcomp; - if (slcomp) { + if (slot >= 0 && ippp_table[slot]->slcomp) { + struct slcompress *slcomp = ippp_table[slot]->slcomp; t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; t.vj.vjs_compressed = slcomp->sls_o_compressed; t.vj.vjs_searches = slcomp->sls_o_searches; @@ -1125,21 +2006,20 @@ isdn_ppp_dev_ioctl(struct net_device *de return -EINVAL; switch (cmd) { - #define PPP_VERSION "2.3.7" - case SIOCGPPPVER: - r = (char *) ifr->ifr_ifru.ifru_data; - len = strlen(PPP_VERSION) + 1; - if (copy_to_user(r, PPP_VERSION, len)) - error = -EFAULT; - break; + case SIOCGPPPVER: + r = (char *) ifr->ifr_ifru.ifru_data; + len = strlen(PPP_VERSION) + 1; + if (copy_to_user(r, PPP_VERSION, len)) + error = -EFAULT; + break; - case SIOCGPPPSTATS: - error = isdn_ppp_dev_ioctl_stats(ifr, dev); - break; - default: - error = -EINVAL; - break; + case SIOCGPPPSTATS: + error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev); + break; + default: + error = -EINVAL; + break; } return error; } @@ -1170,6 +2050,76 @@ isdn_ppp_if_get_unit(char *name) return unit; } + +int +isdn_ppp_dial_slave(char *name) +{ +#ifdef CONFIG_ISDN_MPP + isdn_net_dev *ndev; + isdn_net_local *lp; + struct net_device *sdev; + + if (!(ndev = isdn_net_findif(name))) + return 1; + lp = ndev->local; + if (!(lp->flags & ISDN_NET_CONNECTED)) + return 5; + + sdev = lp->slave; + while (sdev) { + isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + if (!(mlp->flags & ISDN_NET_CONNECTED)) + break; + sdev = mlp->slave; + } + if (!sdev) + return 2; + + isdn_net_dial_req((isdn_net_local *) sdev->priv); + return 0; +#else + return -1; +#endif +} + +int +isdn_ppp_hangup_slave(char *name) +{ +#ifdef CONFIG_ISDN_MPP + isdn_net_dev *ndev; + isdn_net_local *lp; + struct net_device *sdev; + + if (!(ndev = isdn_net_findif(name))) + return 1; + lp = ndev->local; + if (!(lp->flags & ISDN_NET_CONNECTED)) + return 5; + + sdev = lp->slave; + while (sdev) { + isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + + if (mlp->slave) { /* find last connected link in chain */ + isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv; + + if (!(nlp->flags & ISDN_NET_CONNECTED)) + break; + } else if (mlp->flags & ISDN_NET_CONNECTED) + break; + + sdev = mlp->slave; + } + if (!sdev) + return 2; + + isdn_net_hangup(sdev); + return 0; +#else + return -1; +#endif +} + /* * PPP compression stuff */ @@ -1178,172 +2128,860 @@ isdn_ppp_if_get_unit(char *name) /* Push an empty CCP Data Frame up to the daemon to wake it up and let it generate a CCP Reset-Request or tear down CCP altogether */ -static void isdn_ppp_dev_kick_up(void *priv) +static void isdn_ppp_ccp_kickup(struct ippp_struct *is) { - isdn_net_dev *idev = priv; - struct ind_ppp *ind_ppp = idev->ind_priv; - - ipppd_queue_read(ind_ppp->ipppd, PPP_COMPFRAG, NULL, 0); + isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot); } -static void isdn_ppp_lp_kick_up(void *priv) +/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, + but absolutely nontrivial. The most abstruse problem we are facing is + that the generation, reception and all the handling of timeouts and + resends including proper request id management should be entirely left + to the (de)compressor, but indeed is not covered by the current API to + the (de)compressor. The API is a prototype version from PPP where only + some (de)compressors have yet been implemented and all of them are + rather simple in their reset handling. Especially, their is only one + outstanding ResetAck at a time with all of them and ResetReq/-Acks do + not have parameters. For this very special case it was sufficient to + just return an error code from the decompressor and have a single + reset() entry to communicate all the necessary information between + the framework and the (de)compressor. Bad enough, LZS is different + (and any other compressor may be different, too). It has multiple + histories (eventually) and needs to Reset each of them independently + and thus uses multiple outstanding Acks and history numbers as an + additional parameter to Reqs/Acks. + All that makes it harder to port the reset state engine into the + kernel because it is not just the same simple one as in (i)pppd but + it must be able to pass additional parameters and have multiple out- + standing Acks. We are trying to achieve the impossible by handling + reset transactions independent by their id. The id MUST change when + the data portion changes, thus any (de)compressor who uses more than + one resettable state must provide and recognize individual ids for + each individual reset transaction. The framework itself does _only_ + differentiate them by id, because it has no other semantics like the + (de)compressor might. + This looks like a major redesign of the interface would be nice, + but I don't have an idea how to do it better. */ + +/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is + getting that lengthy because there is no simple "send-this-frame-out" + function above but every wrapper does a bit different. Hope I guess + correct in this hack... */ + +static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len) { - isdn_net_local *lp = priv; - isdn_net_dev *idev; - struct ind_ppp *ind_ppp; - - if (list_empty(&lp->online)) { - isdn_BUG(); + struct sk_buff *skb; + unsigned char *p; + int hl; + int cnt = 0; + isdn_net_local *lp = is->lp; + + /* Alloc large enough skb */ + hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; + skb = alloc_skb(len + hl + 16,GFP_ATOMIC); + if(!skb) { + printk(KERN_WARNING + "ippp: CCP cannot send reset - out of memory\n"); return; } - idev = list_entry(lp->online.next, isdn_net_dev, online); - ind_ppp = idev->ind_priv; - ipppd_queue_read(ind_ppp->ipppd, PPP_COMP, NULL, 0); -} + skb_reserve(skb, hl); -/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */ + /* We may need to stuff an address and control field first */ + if(!(is->pppcfg & SC_COMP_AC)) { + p = skb_put(skb, 2); + *p++ = 0xff; + *p++ = 0x03; + } + + /* Stuff proto, code, id and length */ + p = skb_put(skb, 6); + *p++ = (proto >> 8); + *p++ = (proto & 0xff); + *p++ = code; + *p++ = id; + cnt = 4 + len; + *p++ = (cnt >> 8); + *p++ = (cnt & 0xff); + + /* Now stuff remaining bytes */ + if(len) { + p = skb_put(skb, len); + memcpy(p, data, len); + } + + /* skb is now ready for xmit */ + printk(KERN_DEBUG "Sending CCP Frame:\n"); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + isdn_net_write_super(lp, skb); +} + +/* Allocate the reset state vector */ +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) +{ + struct ippp_ccp_reset *r; + r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); + if(!r) { + printk(KERN_ERR "ippp_ccp: failed to allocate reset data" + " structure - no mem\n"); + return NULL; + } + memset(r, 0, sizeof(struct ippp_ccp_reset)); + printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r); + is->reset = r; + return r; +} -static struct sk_buff * -__isdn_ppp_alloc_skb(isdn_net_dev *idev, int len, unsigned int gfp_mask) +/* Destroy the reset state vector. Kill all pending timers first. */ +static void isdn_ppp_ccp_reset_free(struct ippp_struct *is) { - int hl = IPPP_MAX_HEADER + isdn_slot_hdrlen(idev->isdn_slot); - struct sk_buff *skb; + unsigned int id; - skb = alloc_skb(hl + len, gfp_mask); - if (!skb) - return NULL; + printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", + is->reset); + for(id = 0; id < 256; id++) { + if(is->reset->rs[id]) { + isdn_ppp_ccp_reset_free_state(is, (unsigned char)id); + } + } + kfree(is->reset); + is->reset = NULL; +} - skb_reserve(skb, hl); - return skb; +/* Free a given state and clear everything up for later reallocation */ +static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + + if(is->reset->rs[id]) { + printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); + rs = is->reset->rs[id]; + /* Make sure the kernel will not call back later */ + if(rs->ta) + del_timer(&rs->timer); + is->reset->rs[id] = NULL; + kfree(rs); + } else { + printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); + } } -struct sk_buff * -isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask) +/* The timer callback function which is called when a ResetReq has timed out, + aka has never been answered by a ResetAck */ +static void isdn_ppp_ccp_timer_callback(unsigned long closure) { - isdn_net_dev *idev = priv; + struct ippp_ccp_reset_state *rs = + (struct ippp_ccp_reset_state *)closure; - return __isdn_ppp_alloc_skb(idev, len, gfp_mask); + if(!rs) { + printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); + return; + } + if(rs->ta && rs->state == CCPResetSentReq) { + /* We are correct here */ + if(!rs->expra) { + /* Hmm, there is no Ack really expected. We can clean + up the state now, it will be reallocated if the + decompressor insists on another reset */ + rs->ta = 0; + isdn_ppp_ccp_reset_free_state(rs->is, rs->id); + return; + } + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); + /* Push it again */ + isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, + rs->data, rs->dlen); + /* Restart timer */ + rs->timer.expires = jiffies + HZ*5; + add_timer(&rs->timer); + } else { + printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", + rs->state); + } } -static struct sk_buff * -isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask) +/* Allocate a new reset transaction state */ +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, + unsigned char id) { - isdn_net_local *lp = priv; - isdn_net_dev *idev; - - if (list_empty(&lp->online)) { - isdn_BUG(); + struct ippp_ccp_reset_state *rs; + if(is->reset->rs[id]) { + printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", + id); return NULL; + } else { + rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); + if(!rs) + return NULL; + memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); + rs->state = CCPResetIdle; + rs->is = is; + rs->id = id; + rs->timer.data = (unsigned long)rs; + rs->timer.function = isdn_ppp_ccp_timer_callback; + is->reset->rs[id] = rs; + } + return rs; +} + + +/* A decompressor wants a reset with a set of parameters - do what is + necessary to fulfill it */ +static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, + struct isdn_ppp_resetparams *rp) +{ + struct ippp_ccp_reset_state *rs; + + if(rp->valid) { + /* The decompressor defines parameters by itself */ + if(rp->rsend) { + /* And he wants us to send a request */ + if(!(rp->idval)) { + printk(KERN_ERR "ippp_ccp: decompressor must" + " specify reset id\n"); + return; + } + if(is->reset->rs[rp->id]) { + /* There is already a transaction in existence + for this id. May be still waiting for a + Ack or may be wrong. */ + rs = is->reset->rs[rp->id]; + if(rs->state == CCPResetSentReq && rs->ta) { + printk(KERN_DEBUG "ippp_ccp: reset" + " trans still in progress" + " for id %d\n", rp->id); + } else { + printk(KERN_WARNING "ippp_ccp: reset" + " trans in wrong state %d for" + " id %d\n", rs->state, rp->id); + } + } else { + /* Ok, this is a new transaction */ + printk(KERN_DEBUG "ippp_ccp: new trans for id" + " %d to be started\n", rp->id); + rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); + if(!rs) { + printk(KERN_ERR "ippp_ccp: out of mem" + " allocing ccp trans\n"); + return; + } + rs->state = CCPResetSentReq; + rs->expra = rp->expra; + if(rp->dtval) { + rs->dlen = rp->dlen; + memcpy(rs->data, rp->data, rp->dlen); + } + /* HACK TODO - add link comp here */ + isdn_ppp_ccp_xmit_reset(is, PPP_CCP, + CCP_RESETREQ, rs->id, + rs->data, rs->dlen); + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; + } + } else { + printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); + } + } else { + /* The reset params are invalid. The decompressor does not + care about them, so we just send the minimal requests + and increase ids only when an Ack is received for a + given id */ + if(is->reset->rs[is->reset->lastid]) { + /* There is already a transaction in existence + for this id. May be still waiting for a + Ack or may be wrong. */ + rs = is->reset->rs[is->reset->lastid]; + if(rs->state == CCPResetSentReq && rs->ta) { + printk(KERN_DEBUG "ippp_ccp: reset" + " trans still in progress" + " for id %d\n", rp->id); + } else { + printk(KERN_WARNING "ippp_ccp: reset" + " trans in wrong state %d for" + " id %d\n", rs->state, rp->id); + } + } else { + printk(KERN_DEBUG "ippp_ccp: new trans for id" + " %d to be started\n", is->reset->lastid); + rs = isdn_ppp_ccp_reset_alloc_state(is, + is->reset->lastid); + if(!rs) { + printk(KERN_ERR "ippp_ccp: out of mem" + " allocing ccp trans\n"); + return; + } + rs->state = CCPResetSentReq; + /* We always expect an Ack if the decompressor doesn't + know better */ + rs->expra = 1; + rs->dlen = 0; + /* HACK TODO - add link comp here */ + isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, + rs->id, NULL, 0); + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; + } } - idev = list_entry(lp->online.next, isdn_net_dev, online); - return __isdn_ppp_alloc_skb(idev, len, gfp_mask); } -static void -isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb, u16 proto) -{ - isdn_net_dev *idev = priv; - struct ind_ppp *ind_ppp = idev->ind_priv; +/* An Ack was received for this id. This means we stop the timer and clean + up the state prior to calling the decompressors reset routine. */ +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs = is->reset->rs[id]; + + if(rs) { + if(rs->ta && rs->state == CCPResetSentReq) { + /* Great, we are correct */ + if(!rs->expra) + printk(KERN_DEBUG "ippp_ccp: ResetAck received" + " for id %d but not expected\n", id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received out of" + "sync for id %d\n", id); + } + if(rs->ta) { + rs->ta = 0; + del_timer(&rs->timer); + } + isdn_ppp_ccp_reset_free_state(is, id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" + " %d\n", id); + } + /* Make sure the simple reset stuff uses a new id next time */ + is->reset->lastid++; +} + +/* + * decompress packet + * + * if master = 0, we're trying to uncompress an per-link compressed packet, + * as opposed to an compressed reconstructed-from-MPPP packet. + * proto is updated to protocol field of uncompressed packet. + * + * retval: decompressed packet, + * same packet if uncompressed, + * NULL if decompression error + */ - ippp_push_proto(ind_ppp, skb, proto); - ippp_push_ac(ind_ppp, skb); - isdn_net_write_super(idev, skb); +static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, + int *proto) +{ + void *stat = NULL; + struct isdn_ppp_compressor *ipc = NULL; + struct sk_buff *skb_out; + int len; + struct ippp_struct *ri; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + + if(!master) { + // per-link decompression + stat = is->link_decomp_stat; + ipc = is->link_decompressor; + ri = is; + } else { + stat = master->decomp_stat; + ipc = master->decompressor; + ri = master; + } + + if (!ipc) { + // no decompressor -> we can't decompress. + printk(KERN_DEBUG "ippp: no decompressor defined!\n"); + return skb; + } + if (!stat) // if we have a compressor, stat has been set as well + BUG(); + + if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) { + // compressed packets are compressed by their protocol type + + // Set up reset params for the decompressor + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + + skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN); + len = ipc->decompress(stat, skb, skb_out, &rsparm); + kfree_skb(skb); + if (len <= 0) { + switch(len) { + case DECOMP_ERROR: + printk(KERN_INFO "ippp: decomp wants reset %s params\n", + rsparm.valid ? "with" : "without"); + + isdn_ppp_ccp_reset_trans(ri, &rsparm); + break; + case DECOMP_FATALERROR: + ri->pppcfg |= SC_DC_FERROR; + /* Kick ipppd to recognize the error */ + isdn_ppp_ccp_kickup(ri); + break; + } + kfree_skb(skb_out); + return NULL; + } + *proto = isdn_ppp_strip_proto(skb_out); + if (*proto < 0) { + kfree_skb(skb_out); + return NULL; + } + return skb_out; + } else { + // uncompressed packets are fed through the decompressor to + // update the decompressor state + ipc->incomp(stat, skb, *proto); + return skb; + } } -static void -isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb, u16 proto) +/* + * compress a frame + * type=0: normal/bundle compression + * =1: link compression + * returns original skb if we haven't compressed the frame + * and a new skb pointer if we've done it + */ +static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, + struct ippp_struct *is,struct ippp_struct *master,int type) { - isdn_net_local *lp = priv; - isdn_net_dev *idev; - struct ind_ppp *ind_ppp; + int ret; + int new_proto; + struct isdn_ppp_compressor *compressor; + void *stat; + struct sk_buff *skb_out; + + /* we do not compress control protocols */ + if(*proto < 0 || *proto > 0x3fff) { + return skb_in; + } + + if(type) { /* type=1 => Link compression */ + return skb_in; + } + else { + if(!master) { + compressor = is->compressor; + stat = is->comp_stat; + } + else { + compressor = master->compressor; + stat = master->comp_stat; + } + new_proto = PPP_COMP; + } - if (list_empty(&lp->online)) { - isdn_BUG(); - return; + if(!compressor) { + printk(KERN_ERR "isdn_ppp: No compressor set!\n"); + return skb_in; + } + if(!stat) { + printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); + return skb_in; } - idev = list_entry(lp->online.next, isdn_net_dev, online); - ind_ppp = idev->ind_priv; - ippp_push_proto(ind_ppp, skb, proto); - ippp_push_ac(ind_ppp, skb); - isdn_net_write_super(idev, skb); + + /* Allow for at least 150 % expansion (for now) */ + skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 + + skb_headroom(skb_in), GFP_ATOMIC); + if(!skb_out) + return skb_in; + skb_reserve(skb_out, skb_headroom(skb_in)); + + ret = (compressor->compress)(stat,skb_in,skb_out,*proto); + if(!ret) { + dev_kfree_skb(skb_out); + return skb_in; + } + + dev_kfree_skb(skb_in); + *proto = new_proto; + return skb_out; } -static int -isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *data) +/* + * we received a CCP frame .. + * not a clean solution, but we MUST handle a few cases in the kernel + */ +static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, + struct sk_buff *skb,int proto) { - struct ippp_ccp *ccp; - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - struct ind_ppp *ind_ppp = idev->ind_priv; + struct ippp_struct *is; + struct ippp_struct *mis; + int len; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - if (data->flags & IPPP_COMP_FLAG_LINK) - ccp = ind_ppp->ccp; - else - ccp = inl_ppp->ccp; + printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", + lp->ppp_slot); + if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", + __FUNCTION__, lp->ppp_slot); + return; + } + is = ippp_table[lp->ppp_slot]; + isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + if(lp->master) { + int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: slot(%d) out of range\n", + __FUNCTION__, slot); + return; + } + mis = ippp_table[slot]; + } else + mis = is; + + switch(skb->data[0]) { + case CCP_CONFREQ: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable compression here!\n"); + if(proto == PPP_CCP) + mis->compflags &= ~SC_COMP_ON; + else + is->compflags &= ~SC_LINK_COMP_ON; + break; + case CCP_TERMREQ: + case CCP_TERMACK: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + if(proto == PPP_CCP) + mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + else + is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + break; + case CCP_CONFACK: + /* if we RECEIVE an ackowledge we enable the decompressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Enable decompression here!\n"); + if(proto == PPP_CCP) { + if (!mis->decompressor) + break; + mis->compflags |= SC_DECOMP_ON; + } else { + if (!is->decompressor) + break; + is->compflags |= SC_LINK_DECOMP_ON; + } + break; + + case CCP_RESETACK: + printk(KERN_DEBUG "Received ResetAck from peer\n"); + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + + if(proto == PPP_CCP) { + /* If a reset Ack was outstanding for this id, then + clean up the state engine */ + isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); + if(mis->decompressor && mis->decomp_stat) + mis->decompressor-> + reset(mis->decomp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: This is not easy to decide here */ + mis->compflags &= ~SC_DECOMP_DISCARD; + } + else { + isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); + if(is->link_decompressor && is->link_decomp_stat) + is->link_decompressor-> + reset(is->link_decomp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: neither here */ + is->compflags &= ~SC_LINK_DECOMP_DISCARD; + } + break; - return ippp_ccp_set_compressor(ccp, ind_ppp->ipppd->unit, data); + case CCP_RESETREQ: + printk(KERN_DEBUG "Received ResetReq from peer\n"); + /* Receiving a ResetReq means we must reset our compressor */ + /* Set up reset params for the reset entry */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + /* Isolate data length */ + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + if(proto == PPP_CCP) { + if(mis->compressor && mis->comp_stat) + mis->compressor-> + reset(mis->comp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + } + else { + if(is->link_compressor && is->link_comp_stat) + is->link_compressor-> + reset(is->link_comp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + } + /* Ack the Req as specified by rsparm */ + if(rsparm.valid) { + /* Compressor reset handler decided how to answer */ + if(rsparm.rsend) { + /* We should send a Frame */ + isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, + rsparm.idval ? rsparm.id + : skb->data[1], + rsparm.dtval ? + rsparm.data : NULL, + rsparm.dtval ? + rsparm.dlen : 0); + } else { + printk(KERN_DEBUG "ResetAck suppressed\n"); + } + } else { + /* We answer with a straight reflected Ack */ + isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, + skb->data[1], + len ? &skb->data[4] : NULL, + len); + } + break; + } } -// ISDN_NET_ENCAP_SYNCPPP -// ====================================================================== -static int -isdn_ppp_open(isdn_net_local *lp) +/* + * Daemon sends a CCP frame ... + */ + +/* TODO: Clean this up with new Reset semantics */ + +/* I believe the CCP handling as-is is done wrong. Compressed frames + * should only be sent/received after CCP reaches UP state, which means + * both sides have sent CONF_ACK. Currently, we handle both directions + * independently, which means we may accept compressed frames too early + * (supposedly not a problem), but may also mean we send compressed frames + * too early, which may turn out to be a problem. + * This part of state machine should actually be handled by (i)pppd, but + * that's too big of a change now. --kai + */ + +/* Actually, we might turn this into an advantage: deal with the RFC in + * the old tradition of beeing generous on what we accept, but beeing + * strict on what we send. Thus we should just + * - accept compressed frames as soon as decompression is negotiated + * - send compressed frames only when decomp *and* comp are negotiated + * - drop rx compressed frames if we cannot decomp (instead of pushing them + * up to ipppd) + * and I tried to modify this file according to that. --abp + */ + +static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) { - struct inl_ppp *inl_ppp; + struct ippp_struct *mis,*is; + int proto, slot = lp->ppp_slot; + unsigned char *data; - inl_ppp = kmalloc(sizeof(*inl_ppp), GFP_KERNEL); - if (!inl_ppp) - return -ENOMEM; + if(!skb || skb->len < 3) + return; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", + __FUNCTION__, slot); + return; + } + is = ippp_table[slot]; + /* Daemon may send with or without address and control field comp */ + data = skb->data; + if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { + data += 2; + if(skb->len < 5) + return; + } + + proto = ((int)data[0]<<8)+data[1]; + if(proto != PPP_CCP && proto != PPP_CCPFRAG) + return; - lp->inl_priv = inl_ppp; + printk(KERN_DEBUG "Received CCP frame from daemon:\n"); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); - inl_ppp->slcomp = ippp_vj_alloc(); - if (!inl_ppp->slcomp) - goto err; - - inl_ppp->ccp = ippp_ccp_alloc(); - if (!inl_ppp->ccp) - goto err_vj; - - inl_ppp->ccp->proto = PPP_COMP; - inl_ppp->ccp->priv = lp; - inl_ppp->ccp->alloc_skb = isdn_ppp_lp_alloc_skb; - inl_ppp->ccp->xmit = isdn_ppp_lp_xmit; - inl_ppp->ccp->kick_up = isdn_ppp_lp_kick_up; + if (lp->master) { + slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "%s: slot(%d) out of range\n", + __FUNCTION__, slot); + return; + } + mis = ippp_table[slot]; + } else + mis = is; + if (mis != is) + printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); - return 0; - - err_vj: - ippp_vj_free(inl_ppp->slcomp); - err: - kfree(inl_ppp); - lp->inl_priv = NULL; - return -ENOMEM; + switch(data[2]) { + case CCP_CONFREQ: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable decompression here!\n"); + if(proto == PPP_CCP) + is->compflags &= ~SC_DECOMP_ON; + else + is->compflags &= ~SC_LINK_DECOMP_ON; + break; + case CCP_TERMREQ: + case CCP_TERMACK: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + if(proto == PPP_CCP) + is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + else + is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + break; + case CCP_CONFACK: + /* if we SEND an ackowledge we can/must enable the compressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Enable compression here!\n"); + if(proto == PPP_CCP) { + if (!is->compressor) + break; + is->compflags |= SC_COMP_ON; + } else { + if (!is->compressor) + break; + is->compflags |= SC_LINK_COMP_ON; + } + break; + case CCP_RESETACK: + /* If we send a ACK we should reset our compressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Reset decompression state here!\n"); + printk(KERN_DEBUG "ResetAck from daemon passed by\n"); + if(proto == PPP_CCP) { + /* link to master? */ + if(is->compressor && is->comp_stat) + is->compressor->reset(is->comp_stat, 0, 0, + NULL, 0, NULL); + is->compflags &= ~SC_COMP_DISCARD; + } + else { + if(is->link_compressor && is->link_comp_stat) + is->link_compressor->reset(is->link_comp_stat, + 0, 0, NULL, 0, NULL); + is->compflags &= ~SC_LINK_COMP_DISCARD; + } + break; + case CCP_RESETREQ: + /* Just let it pass by */ + printk(KERN_DEBUG "ResetReq from daemon passed by\n"); + break; + } } -static void -isdn_ppp_close(isdn_net_local *lp) +int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) { - struct inl_ppp *inl_ppp = lp->inl_priv; - - ippp_ccp_free(inl_ppp->ccp); - ippp_vj_free(inl_ppp->slcomp); + ipc->next = ipc_head; + ipc->prev = NULL; + if(ipc_head) { + ipc_head->prev = ipc; + } + ipc_head = ipc; + return 0; +} - kfree(inl_ppp); - lp->inl_priv = NULL; +int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) +{ + if(ipc->prev) + ipc->prev->next = ipc->next; + else + ipc_head = ipc->next; + if(ipc->next) + ipc->next->prev = ipc->prev; + ipc->prev = ipc->next = NULL; + return 0; } -struct isdn_netif_ops isdn_ppp_ops = { - .hard_start_xmit = isdn_ppp_start_xmit, - .do_ioctl = isdn_ppp_dev_ioctl, - .flags = IFF_NOARP | IFF_POINTOPOINT, - .type = ARPHRD_PPP, - .receive = isdn_ppp_receive, - .connected = isdn_ppp_connected, - .disconnected = isdn_ppp_disconnected, - .bind = isdn_ppp_bind, - .unbind = isdn_ppp_unbind, - .open = isdn_ppp_open, - .close = isdn_ppp_close, -}; +static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) +{ + struct isdn_ppp_compressor *ipc = ipc_head; + int ret; + void *stat; + int num = data->num; + + if(is->debug & 0x10) + printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit, + (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num); + + /* If is has no valid reset state vector, we cannot allocate a + decompressor. The decompressor would cause reset transactions + sooner or later, and they need that vector. */ + + if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) { + printk(KERN_ERR "ippp_ccp: no reset data structure - can't" + " allow decompression.\n"); + return -ENOMEM; + } + + while(ipc) { + if(ipc->num == num) { + stat = ipc->alloc(data); + if(stat) { + ret = ipc->init(stat,data,is->unit,0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + stat = NULL; + break; + } + } + else { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + break; + } + if(data->flags & IPPP_COMP_FLAG_XMIT) { + if(data->flags & IPPP_COMP_FLAG_LINK) { + if(is->link_comp_stat) + is->link_compressor->free(is->link_comp_stat); + is->link_comp_stat = stat; + is->link_compressor = ipc; + } + else { + if(is->comp_stat) + is->compressor->free(is->comp_stat); + is->comp_stat = stat; + is->compressor = ipc; + } + } + else { + if(data->flags & IPPP_COMP_FLAG_LINK) { + if(is->link_decomp_stat) + is->link_decompressor->free(is->link_decomp_stat); + is->link_decomp_stat = stat; + is->link_decompressor = ipc; + } + else { + if(is->decomp_stat) + is->decompressor->free(is->decomp_stat); + is->decomp_stat = stat; + is->decompressor = ipc; + } + } + return 0; + } + ipc = ipc->next; + } + return -EINVAL; +} diff -puN -L drivers/isdn/i4l/isdn_ppp_ccp.c drivers/isdn/i4l/isdn_ppp_ccp.c~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ppp_ccp.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,657 +0,0 @@ -/* Linux ISDN subsystem, PPP CCP support - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include "isdn_ppp_ccp.h" -#include "isdn_common.h" -#include "isdn_net_lib.h" -#include "isdn_ppp.h" -#include - -/* ====================================================================== */ -enum ippp_ccp_reset_states { - CCPResetIdle, - CCPResetSentReq, - CCPResetRcvdReq, - CCPResetSentAck, - CCPResetRcvdAck -}; - -struct ippp_ccp_reset_state { - enum ippp_ccp_reset_states state;/* State of this transaction */ - struct ippp_ccp *ccp; /* Backlink */ - unsigned char id; /* id index */ - unsigned char ta:1; /* The timer is active (flag) */ - unsigned char expra:1; /* We expect a ResetAck at all */ - int dlen; /* Databytes stored in data */ - struct timer_list timer; /* For timeouts/retries */ - /* This is a hack but seems sufficient for the moment. We do not want - to have this be yet another allocation for some bytes, it is more - memory management overhead than the whole mess is worth. */ - unsigned char data[IPPP_RESET_MAXDATABYTES]; -}; - -/* The data structure keeping track of the currently outstanding CCP Reset - transactions. */ -struct ippp_ccp_reset { - struct ippp_ccp_reset_state *rs[256]; /* One per possible id */ - unsigned char lastid; /* Last id allocated */ -}; - -/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, - but absolutely nontrivial. The most abstruse problem we are facing is - that the generation, reception and all the handling of timeouts and - resends including proper request id management should be entirely left - to the (de)compressor, but indeed is not covered by the current API to - the (de)compressor. The API is a prototype version from PPP where only - some (de)compressors have yet been implemented and all of them are - rather simple in their reset handling. Especially, their is only one - outstanding ResetAck at a time with all of them and ResetReq/-Acks do - not have parameters. For this very special case it was sufficient to - just return an error code from the decompressor and have a single - reset() entry to communicate all the necessary information between - the framework and the (de)compressor. Bad enough, LZS is different - (and any other compressor may be different, too). It has multiple - histories (eventually) and needs to Reset each of them independently - and thus uses multiple outstanding Acks and history numbers as an - additional parameter to Reqs/Acks. - All that makes it harder to port the reset state engine into the - kernel because it is not just the same simple one as in (i)pppd but - it must be able to pass additional parameters and have multiple out- - standing Acks. We are trying to achieve the impossible by handling - reset transactions independent by their id. The id MUST change when - the data portion changes, thus any (de)compressor who uses more than - one resettable state must provide and recognize individual ids for - each individual reset transaction. The framework itself does _only_ - differentiate them by id, because it has no other semantics like the - (de)compressor might. - This looks like a major redesign of the interface would be nice, - but I don't have an idea how to do it better. */ - -/* ====================================================================== */ - -/* Free a given state and clear everything up for later reallocation */ -static void -ippp_ccp_reset_free_state(struct ippp_ccp *ccp, unsigned char id) -{ - struct ippp_ccp_reset_state *rs = ccp->reset->rs[id]; - - if (!rs) - return; - - if (rs->ta) // FIXME? - del_timer_sync(&rs->timer); - - kfree(rs); - ccp->reset->rs[id] = NULL; -} - -static void -do_xmit_reset(struct ippp_ccp *ccp, unsigned char code, unsigned char id, - unsigned char *data, int len) -{ - struct sk_buff *skb; - unsigned char *p; - u16 proto = ccp->proto == PPP_COMP ? PPP_CCP : PPP_CCPFRAG; - - skb = ccp->alloc_skb(ccp->priv, 4 + len, GFP_ATOMIC); - - p = skb_put(skb, 4); - p += put_u8 (p, code); - p += put_u8 (p, id); - p += put_u16(p, len + 4); - - if (len) - memcpy(skb_put(skb, len), data, len); - - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1); - - ccp->xmit(ccp->priv, skb, proto); -} - -/* The timer callback function which is called when a ResetReq has timed out, - aka has never been answered by a ResetAck */ -static void -isdn_ppp_ccp_timer_callback(unsigned long data) -{ - struct ippp_ccp_reset_state *rs = (struct ippp_ccp_reset_state *) data; - - if (!rs->ta) { - isdn_BUG(); - return; - } - if (rs->state != CCPResetSentReq) { - printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", - rs->state); - rs->ta = 0; - return; - } - /* We are correct here */ - if (!rs->expra) { - /* Hmm, there is no Ack really expected. We can clean - up the state now, it will be reallocated if the - decompressor insists on another reset */ - rs->ta = 0; - ippp_ccp_reset_free_state(rs->ccp, rs->id); - return; - } - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); - /* Push it again */ - do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen); - - mod_timer(&rs->timer, jiffies + 5 * HZ); -} - -/* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state * -ippp_ccp_reset_alloc_state(struct ippp_ccp *ccp, unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - - rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); - if(!rs) - return NULL; - memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); - rs->state = CCPResetIdle; - rs->ccp = ccp; - rs->id = id; - init_timer(&rs->timer); - rs->timer.data = (unsigned long)rs; - rs->timer.function = isdn_ppp_ccp_timer_callback; - - ccp->reset->rs[id] = rs; - return rs; -} - -/* A decompressor wants a reset with a set of parameters - do what is - necessary to fulfill it */ -static void -ippp_ccp_reset_xmit(struct ippp_ccp *ccp, - struct isdn_ppp_resetparams *rp) -{ - struct ippp_ccp_reset_state *rs; - int id; - - if (rp->valid) { - /* The decompressor defines parameters by itself */ - if (!rp->rsend) - return; - - /* And it wants us to send a request */ - if (!rp->idval) { - isdn_BUG(); - return; - } - id = rp->id; - } else { - /* The reset params are invalid. The decompressor does not - care about them, so we just send the minimal requests - and increase ids only when an Ack is received for a - given id */ - id = ccp->reset->lastid++; - /* We always expect an Ack if the decompressor doesn't - know better */ - rp->expra = 1; - rp->dtval = 0; - } - rs = ccp->reset->rs[id]; - if (rs) { - printk(KERN_INFO "ippp_ccp: reset xmit in wrong state %d " - "for id %d (%d)\n", rs->state, id, rs->ta); - return; - } - /* Ok, this is a new transaction */ - printk(KERN_DEBUG "ippp_ccp: new xmit for id %d\n", id); - rs = ippp_ccp_reset_alloc_state(ccp, id); - if(!rs) { - printk(KERN_INFO "ippp_ccp: out of mem allocing ccp trans\n"); - return; - } - rs->expra = rp->expra; - rs->id = id; - if (rp->dtval) { - rs->dlen = rp->dlen; - memcpy(rs->data, rp->data, rp->dlen); - } else { - rs->dlen = 0; - } - - rs->state = CCPResetSentReq; - do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen); - - /* Start the timer */ - rs->timer.expires = jiffies + 5*HZ; - add_timer(&rs->timer); - rs->ta = 1; -} - -/* ====================================================================== */ - -struct ippp_ccp * -ippp_ccp_alloc(void) -{ - struct ippp_ccp *ccp; - - ccp = kmalloc(sizeof(*ccp), GFP_ATOMIC); // FIXME - if (!ccp) - return NULL; - memset(ccp, 0, sizeof(*ccp)); - ccp->mru = 1524; /* MRU, default 1524 */ - ccp->reset = kmalloc(sizeof(*ccp->reset), GFP_ATOMIC); // FIXME alloc together? - if (!ccp->reset) { - kfree(ccp); - return NULL; - } - memset(ccp->reset, 0, sizeof(*ccp->reset)); - return ccp; -} - -void -ippp_ccp_free(struct ippp_ccp *ccp) -{ - int id; - - if (ccp->comp_stat) { - ccp->compressor->free(ccp->comp_stat); - module_put(ccp->compressor->owner); - } - if (ccp->decomp_stat) { - ccp->decompressor->free(ccp->decomp_stat); - module_put(ccp->decompressor->owner); - } - for (id = 0; id < 256; id++) { - if (ccp->reset->rs[id]) - ippp_ccp_reset_free_state(ccp, id); - } - kfree(ccp->reset); - kfree(ccp); -} - -int -ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru) -{ - ccp->mru = mru; - return 0; -} - -unsigned int -ippp_ccp_get_flags(struct ippp_ccp *ccp) -{ - return ccp->compflags & (SC_DC_ERROR|SC_DC_FERROR); -} - -/* - * compress a frame - * returns original skb if we did not compress the frame - * and a new skb otherwise - */ -struct sk_buff * -ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, u16 *proto) -{ - struct sk_buff *skb; - - if (!(ccp->compflags & (SC_COMP_ON|SC_DECOMP_ON))) { - /* We send compressed only if both down- und upstream - compression is negotiated, that means, CCP is up */ - return skb_in; - } - /* we do not compress control protocols */ - if (*proto > 0x3fff) { - return skb_in; - } - if (!ccp->compressor || !ccp->comp_stat) { - isdn_BUG(); - return skb_in; - } - /* Allow for at least 150 % expansion (for now) */ - skb = alloc_skb(skb_in->len*2 + skb_headroom(skb_in), GFP_ATOMIC); - if (!skb) - return skb_in; - - skb_reserve(skb, skb_headroom(skb_in)); - if (!ccp->compressor->compress(ccp->comp_stat, skb_in, skb, *proto)) { - dev_kfree_skb(skb); - return skb_in; - } - isdn_ppp_frame_log("comp in:", skb_in->data, skb_in->len, 20, -1, -1); - isdn_ppp_frame_log("comp out:", skb->data, skb->len, 20, -1, -1); - dev_kfree_skb(skb_in); - *proto = ccp->proto; - return skb; -} - -/* - * decompress packet - * - * proto is updated to protocol field of uncompressed packet. - * retval: decompressed packet, - * same packet if uncompressed, - * NULL if decompression error - */ - -struct sk_buff * -ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, u16 *proto) -{ - struct sk_buff *skb; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - int len; - - if (!(ccp->compflags & SC_DECOMP_ON)) { - return skb_in; - } - if (!ccp->decompressor || !ccp->decomp_stat) { - isdn_BUG(); - return skb_in; - } - if (*proto != ccp->proto) { - /* uncompressed packets are fed through the decompressor to - * update the decompressor state */ - ccp->decompressor->incomp(ccp->decomp_stat, skb_in, *proto); - return skb_in; - } - skb = dev_alloc_skb(ccp->mru + PPP_HDRLEN); // FIXME oom? - - // Set up reset params for the decompressor - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - - len = ccp->decompressor->decompress(ccp->decomp_stat, skb_in, skb, - &rsparm); - isdn_ppp_frame_log("deco in:", skb_in->data, skb_in->len, 20, -1, -1); - isdn_ppp_frame_log("deco out:", skb->data, skb->len, 20, -1, -1); - kfree_skb(skb_in); - - if (len <= 0) { - switch(len) { - case DECOMP_ERROR: - printk(KERN_INFO "ippp: decomp wants reset with%s params\n", - rsparm.valid ? "" : "out"); - - ippp_ccp_reset_xmit(ccp, &rsparm); - break; - case DECOMP_FATALERROR: - ccp->compflags |= SC_DC_FERROR; - /* Kick ipppd to recognize the error */ - ccp->kick_up(ccp->priv); - break; - } - kfree_skb(skb); - return NULL; - } - if (isdn_ppp_strip_proto(skb, proto)) { - kfree_skb(skb); - return NULL; - } - return skb; -} - -/* An Ack was received for this id. This means we stop the timer and clean - up the state prior to calling the decompressors reset routine. */ -static void -isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp *ccp, unsigned char id) -{ - struct ippp_ccp_reset_state *rs = ccp->reset->rs[id]; - - if (!rs) { - printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" - " %d\n", id); - return; - } - - if (rs->ta && rs->state == CCPResetSentReq) { - /* Great, we are correct */ - if(!rs->expra) - printk(KERN_DEBUG "ippp_ccp: ResetAck received" - " for id %d but not expected\n", id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received out of" - "sync for id %d\n", id); - } - if(rs->ta) { - rs->ta = 0; - del_timer(&rs->timer); - } - ippp_ccp_reset_free_state(ccp, id); -} - -void -ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) -{ - int len; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - isdn_ppp_frame_log("ccp-recv", skb->data, skb->len, 32, -1, -1); - - switch(skb->data[0]) { - case CCP_CONFREQ: - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Disable compression here!\n"); - - ccp->compflags &= ~SC_COMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - - ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); - break; - case CCP_CONFACK: - /* if we RECEIVE an ackowledge we enable the decompressor */ - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Enable decompression here!\n"); - - if (!ccp->decomp_stat) - break; - ccp->compflags |= SC_DECOMP_ON; - break; - case CCP_RESETACK: - printk(KERN_DEBUG "Received ResetAck from peer\n"); - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - - /* If a reset Ack was outstanding for this id, then - clean up the state engine */ - isdn_ppp_ccp_reset_ack_rcvd(ccp, skb->data[1]); - if (ccp->decomp_stat) - ccp->decompressor->reset(ccp->decomp_stat, - skb->data[0], skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: This is not easy to decide here */ - ccp->compflags &= ~SC_DECOMP_DISCARD; - break; - case CCP_RESETREQ: - printk(KERN_DEBUG "Received ResetReq from peer\n"); - /* Receiving a ResetReq means we must reset our compressor */ - /* Set up reset params for the reset entry */ - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - /* Isolate data length */ - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - if (ccp->comp_stat) - ccp->compressor->reset(ccp->comp_stat, - skb->data[0], skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - /* Ack the Req as specified by rsparm */ - if (rsparm.valid) { - /* Compressor reset handler decided how to answer */ - if (!rsparm.rsend) { - printk(KERN_DEBUG "ResetAck suppressed\n"); - return; - } - /* We should send a Frame */ - do_xmit_reset(ccp, CCP_RESETACK, - rsparm.idval ? rsparm.id : skb->data[1], - rsparm.data, - rsparm.dtval ? rsparm.dlen : 0); - return; - } - /* We answer with a straight reflected Ack */ - do_xmit_reset(ccp, CCP_RESETACK, skb->data[1], - skb->data + 4, len); - } -} - -void -ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) -{ - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1); - - switch (skb->data[2]) { - case CCP_CONFREQ: - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Disable decompression here!\n"); - - ccp->compflags &= ~SC_DECOMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - - ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); - break; - case CCP_CONFACK: - /* if we SEND an ackowledge we can/must enable the compressor */ - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Enable compression here!\n"); - - if (!ccp->compressor) - break; - - ccp->compflags |= SC_COMP_ON; - break; - case CCP_RESETACK: - /* If we send a ACK we should reset our compressor */ - if (ccp->debug & 0x10) - printk(KERN_DEBUG "Reset decompression state here!\n"); - - printk(KERN_DEBUG "ResetAck from daemon passed by\n"); - - if (!ccp->comp_stat) - break; - - ccp->compressor->reset(ccp->comp_stat, 0, 0, NULL, 0, NULL); - ccp->compflags &= ~SC_COMP_DISCARD; - break; - case CCP_RESETREQ: - /* Just let it pass by */ - printk(KERN_DEBUG "ResetReq from daemon passed by\n"); - break; - } -} - -static LIST_HEAD(ipc_head); -static spinlock_t ipc_head_lock = SPIN_LOCK_UNLOCKED; - -int -ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, - struct isdn_ppp_comp_data *data) -{ - struct isdn_ppp_compressor *ipc; - int ret; - void *stat; - int num = data->num; - - if (ccp->debug & 0x10) - printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit, - data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num); - - spin_lock(&ipc_head_lock); - list_for_each_entry(ipc, &ipc_head, list) { - if (ipc->num == num && - try_module_get(ipc->owner)) - goto found; - } - spin_unlock(&ipc_head_lock); - return -EINVAL; - - found: - spin_unlock(&ipc_head_lock); - - stat = ipc->alloc(data); - if (!stat) { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - goto err; - } - ret = ipc->init(stat, data, unit, 0); - if(!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - goto err; - } - if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (ccp->comp_stat) { - ccp->compressor->free(ccp->comp_stat); - module_put(ccp->compressor->owner); - } - ccp->comp_stat = stat; - ccp->compressor = ipc; - } else { - if (ccp->decomp_stat) { - ccp->decompressor->free(ccp->decomp_stat); - module_put(ccp->decompressor->owner); - } - ccp->decomp_stat = stat; - ccp->decompressor = ipc; - } - return 0; - - err: - module_put(ipc->owner); - return -EINVAL; -} - -void -ippp_ccp_get_compressors(unsigned long protos[8]) -{ - struct isdn_ppp_compressor *ipc; - int i, j; - - memset(protos, 0, sizeof(unsigned long) * 8); - - spin_lock(&ipc_head_lock); - list_for_each_entry(ipc, &ipc_head, list) { - j = ipc->num / (sizeof(long)*8); - i = ipc->num % (sizeof(long)*8); - if (j < 8) - protos[j] |= 1 << i; - } - spin_unlock(&ipc_head_lock); -} - -int -isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) -{ - spin_lock(&ipc_head_lock); - list_add_tail(&ipc->list, &ipc_head); - spin_unlock(&ipc_head_lock); - - return 0; -} - -int -isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) -{ - spin_lock(&ipc_head_lock); - list_del(&ipc->list); - spin_unlock(&ipc_head_lock); - - return 0; -} - diff -puN -L drivers/isdn/i4l/isdn_ppp_ccp.h drivers/isdn/i4l/isdn_ppp_ccp.h~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ppp_ccp.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,75 +0,0 @@ -/* Linux ISDN subsystem, PPP CCP support - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include -#include - -/* for ippp_ccp::flags */ - -#define SC_DECOMP_ON 0x01 -#define SC_COMP_ON 0x02 -#define SC_DECOMP_DISCARD 0x04 -#define SC_COMP_DISCARD 0x08 - -/* SC_DC_ERROR/FERROR go in here as well, but are defined elsewhere - - #define SC_DC_FERROR 0x00800000 - #define SC_DC_ERROR 0x00400000 -*/ - -struct ippp_ccp { - u16 proto; - struct isdn_ppp_compressor *compressor; - struct isdn_ppp_compressor *decompressor; - void *comp_stat; - void *decomp_stat; - unsigned long compflags; - struct ippp_ccp_reset *reset; - int mru; - int debug; - void *priv; - void (*xmit)(void *priv, struct sk_buff *skb, u16 proto); - void (*kick_up)(void *priv); - struct sk_buff *(*alloc_skb)(void *priv, int len, int gfp_mask); -}; - -struct ippp_ccp * -ippp_ccp_alloc(void); - -void -ippp_ccp_free(struct ippp_ccp *ccp); - -int -ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru); - -unsigned int -ippp_ccp_get_flags(struct ippp_ccp *ccp); - -struct sk_buff * -ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, u16 *proto); - -struct sk_buff * -ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb, u16 *proto); - -void -ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb); - -void -ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb); - -void -ippp_ccp_get_compressors(unsigned long protos[8]); - -int -ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, - struct isdn_ppp_comp_data *data); - - diff -puN drivers/isdn/i4l/isdn_ppp.h~i4l drivers/isdn/i4l/isdn_ppp.h --- 25/drivers/isdn/i4l/isdn_ppp.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_ppp.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,57 +1,43 @@ -/* Linux ISDN subsystem, functions for synchronous PPP (linklevel). +/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ -#include "isdn_net_lib.h" - -extern struct file_operations isdn_ppp_fops; -extern struct isdn_netif_ops isdn_ppp_ops; +#include /* for PPP_PROTOCOL */ +#include /* for isdn_ppp info */ -int isdn_ppp_init(void); -void isdn_ppp_cleanup(void); -int isdn_ppp_dial_slave(char *); -int isdn_ppp_hangup_slave(char *); - -struct inl_ppp { - unsigned long debug; - struct slcompress *slcomp; - struct ippp_ccp *ccp; /* CCP for this channel */ - unsigned int mp_cfg; - struct sk_buff_head mp_frags; /* fragments list */ - u32 mp_rxseq; /* last processed packet seq # */ - u32 mp_txseq; /* current tx seq # */ -}; - -struct ind_ppp { - struct ipppd *ipppd; /* /dev/ipppX which controls us */ - unsigned int pppcfg; - unsigned long debug; - struct ippp_ccp *ccp; /* CCP for this channel (multilink) */ - u32 mp_rxseq; /* last seq no seen on this channel */ -}; - -void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, - int unit, int slot); - -int -isdn_ppp_strip_proto(struct sk_buff *skb, u16 *proto); - -void -ippp_push_proto(struct ind_ppp *ind_ppp, struct sk_buff *skb, u16 proto); +extern int isdn_ppp_read(int, struct file *, char *, int); +extern int isdn_ppp_write(int, struct file *, const char *, int); +extern int isdn_ppp_open(int, struct file *); +extern int isdn_ppp_init(void); +extern void isdn_ppp_cleanup(void); +extern int isdn_ppp_free(isdn_net_local *); +extern int isdn_ppp_bind(isdn_net_local *); +extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *); +extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *); +extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *); +extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int); +extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *); +extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); +extern void isdn_ppp_release(int, struct file *); +extern int isdn_ppp_dial_slave(char *); +extern void isdn_ppp_wakeup_daemon(isdn_net_local *); + +extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc); +extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc); + +#define IPPP_OPEN 0x01 +#define IPPP_CONNECT 0x02 +#define IPPP_CLOSEWAIT 0x04 +#define IPPP_NOBLOCK 0x08 +#define IPPP_ASSIGNED 0x10 -void -ippp_xmit(isdn_net_dev *idev, struct sk_buff *skb); - -void -ippp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto); +#define IPPP_MAX_HEADER 10 -struct sk_buff * -isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask); -#define IPPP_MAX_HEADER 10 diff -puN -L drivers/isdn/i4l/isdn_ppp_mp.c drivers/isdn/i4l/isdn_ppp_mp.c~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ppp_mp.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,353 +0,0 @@ -/* Linux ISDN subsystem, PPP CCP support - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include "isdn_ppp_mp.h" -#include "isdn_ppp_ccp.h" -#include "isdn_common.h" -#include "isdn_net_lib.h" -#include "isdn_ppp.h" - -/* ====================================================================== */ - -#define MP_END_FRAG 0x40 -#define MP_BEGIN_FRAG 0x80 - -#define MP_MAX_QUEUE_LEN 16 - -/* ====================================================================== */ - -int -ippp_mp_bind(isdn_net_dev *idev) -{ - struct ind_ppp *ind_ppp = idev->ind_priv; - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - - /* seq no last seen, maybe set to bundle min, when joining? */ - ind_ppp->mp_rxseq = 0; - - if (!list_empty(&idev->mlp->online)) - return 0; - - /* first channel for this link, do some setup */ - - inl_ppp->mp_cfg = 0; /* MPPP configuration */ - inl_ppp->mp_txseq = 0; /* MPPP tx sequence number */ - inl_ppp->mp_rxseq = (u32) -1; - skb_queue_head_init(&inl_ppp->mp_frags); - - return 0; -} - -int -ippp_mp_bundle(isdn_net_dev *idev, int unit) -{ - isdn_net_local *lp = idev->mlp; - char ifn[IFNAMSIZ + 1]; - isdn_net_dev *n_idev; - struct ind_ppp *ind_ppp; - - printk(KERN_DEBUG "%s: %s: slave unit: %d\n", - __FUNCTION__, idev->name, unit); - - sprintf(ifn, "ippp%d", unit); - list_for_each_entry(n_idev, &lp->slaves, slaves) { - if (strcmp(n_idev->name, ifn) == 0) - goto found; - } - - printk(KERN_INFO "%s: cannot find %s\n", __FUNCTION__, ifn); - return -ENODEV; - - found: - ind_ppp = n_idev->ind_priv; - if (!ind_ppp->ipppd) { - printk(KERN_INFO "%s: no ipppd?\n", __FUNCTION__); - return -ENXIO; - } - ind_ppp->pppcfg |= SC_ENABLE_IP; - isdn_net_online(n_idev); - - return 0; -} - -void -ippp_mp_disconnected(isdn_net_dev *idev) -{ - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - - if (!list_empty(&idev->mlp->online)) - return; - - /* we're the last link going down */ - skb_queue_purge(&inl_ppp->mp_frags); -} - -void -ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb) -{ - struct ind_ppp *ind_ppp = idev->ind_priv; - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - unsigned char *p; - u32 txseq; - u16 proto; - - if (!(inl_ppp->mp_cfg & SC_MP_PROT)) { - return ippp_xmit(idev, skb); - } - - /* we could do something smarter than just sending - * the complete packet as fragment... */ - - txseq = inl_ppp->mp_txseq++; - - if (inl_ppp->mp_cfg & SC_OUT_SHORT_SEQ) { - /* sequence number: 12bit */ - p = skb_push(skb, 2); - p[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((txseq >> 8) & 0xf); - p[1] = txseq & 0xff; - } else { - /* sequence number: 24bit */ - p = skb_push(skb, 4); - p[0] = MP_BEGIN_FRAG | MP_END_FRAG; - p[1] = (txseq >> 16) & 0xff; - p[2] = (txseq >> 8) & 0xff; - p[3] = (txseq >> 0) & 0xff; - } - proto = PPP_MP; - skb = ippp_ccp_compress(ind_ppp->ccp, skb, &proto); - ippp_push_proto(ind_ppp, skb, proto); - ippp_xmit(idev, skb); -} - -static void mp_receive(isdn_net_dev *idev, struct sk_buff *skb); - -void -ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto) -{ - struct ind_ppp *ind_ppp = idev->ind_priv; - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - - if (inl_ppp->mp_cfg & SC_REJ_MP_PROT) - goto out; - - skb = ippp_ccp_decompress(ind_ppp->ccp, skb, &proto); - if (!skb) - goto drop; - - if (proto == PPP_MP) - return mp_receive(idev, skb); - - out: - return ippp_receive(idev, skb, proto); - - drop: - idev->mlp->stats.rx_errors++; - kfree_skb(skb); -} - -#define MP_LONGSEQ_MASK 0x00ffffff -#define MP_SHORTSEQ_MASK 0x00000fff -#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK -#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK -#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1) -#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1) - -/* sequence-wrap safe comparisions (for long sequence)*/ -#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT) -#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT) -#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT) -#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT) - -#define MP_SEQUENCE(skb) (skb)->priority -#define MP_FLAGS(skb) (skb)->cb[0] - -static u32 -get_seq(struct sk_buff *skb, u32 last_seq, int short_seq) -{ - u32 seq; - u16 shseq; - u8 flags; - int delta; - - get_u8(skb->data, &flags); - if (short_seq) { - /* convert 12-bit short seq number to 24-bit long one */ - get_u16(skb->data, &shseq); - delta = (shseq & MP_SHORTSEQ_MASK) - - (last_seq & MP_SHORTSEQ_MASK); - /* check for seqence wrap */ - if (delta < 0) - delta += MP_SHORTSEQ_MAX + 1; - - seq = last_seq + delta; - skb_pull(skb, 2); - } else { - get_u32(skb->data, &seq); - skb_pull(skb, 4); - } - seq &= MP_LONGSEQ_MASK; - MP_SEQUENCE(skb) = seq; - MP_FLAGS(skb) = flags; - return seq; -} - -static int -mp_insert_frag(struct sk_buff_head *frags, struct sk_buff *skb) -{ - struct sk_buff *p; - - /* If our queue of not yet reassembled fragments grows too - large, throw away the oldest fragment */ - if (skb_queue_len(frags) > MP_MAX_QUEUE_LEN) - kfree_skb(skb_dequeue(frags)); - - for (p = frags->next; p != (struct sk_buff *) frags; p = p->next) { - if (MP_LE(MP_SEQUENCE(skb), MP_SEQUENCE(p))) - break; - } - /* duplicate ? */ - if (MP_SEQUENCE(skb) == MP_SEQUENCE(p)) - return -EBUSY; - - __skb_insert(skb, p->prev, p, frags); - return 0; -} - -struct sk_buff * -mp_complete_seq(isdn_net_local *lp, struct sk_buff *b, struct sk_buff *e) -{ - struct sk_buff *p, *n, *skb; - int len = 0; - - if (b->next == e) { - /* sequence with only one frag */ - skb_unlink(b); - return b; - } - for (p = b, n = p->next; p != e; p = n, n = p->next ) { - len += p->len; - } - // FIXME check against mrru? - skb = dev_alloc_skb(len); - if (!skb) - lp->stats.rx_errors++; - - for (p = b, n = p->next; p != e; p = n, n = p->next ) { - if (skb) - memcpy(skb_put(skb, p->len), p->data, p->len); - - skb_unlink(p); - kfree_skb(p); - } - return skb; -} - -struct sk_buff * -mp_reassemble(isdn_net_local *lp) -{ - struct inl_ppp *inl_ppp = lp->inl_priv; - struct sk_buff_head *frags = &inl_ppp->mp_frags; - struct sk_buff *p, *n, *pp, *start; - u32 min_seq = inl_ppp->mp_rxseq; - u32 next_seq = 0; - - again: - start = NULL; - for (p = frags->next, n = p->next; p != (struct sk_buff *) frags; p = n, n = p->next ) { - if (!start) { - if (MP_FLAGS(p) & MP_BEGIN_FRAG) { - start = p; - next_seq = MP_SEQUENCE(p); - } else { - /* start frag is missing */ - goto frag_missing; - } - } - /* we've seen the first fragment of this series */ - if (MP_SEQUENCE(p) != next_seq) { - /* previous frag is missing */ - goto frag_missing; - } - if (MP_FLAGS(p) & MP_END_FRAG) { - /* we got a full sequence */ - return mp_complete_seq(lp, start, p->next); - } - next_seq = MP_SEQUENCE(p) + 1; - } - return NULL; - - frag_missing: - if (MP_SEQUENCE(p) - 1 > min_seq) - /* may come later */ - return NULL; - - /* for all fragments up to p */ - p = p->next; - for (pp = frags->next, n = pp->next; pp != p; pp = n, n = pp->next ) { - skb_unlink(pp); - kfree_skb(pp); - lp->stats.rx_errors++; - } - goto again; - -} - -static void -mp_receive(isdn_net_dev *idev, struct sk_buff *skb) -{ - isdn_net_local *lp = idev->mlp; - struct inl_ppp *inl_ppp = lp->inl_priv; - struct ind_ppp *ind_ppp = idev->ind_priv; - isdn_net_dev *qdev; - struct sk_buff_head *frags = &inl_ppp->mp_frags; - u32 seq; - u16 proto; - - if (skb->len < (inl_ppp->mp_cfg & SC_IN_SHORT_SEQ ? 2 : 4)) - goto drop; - - seq = get_seq(skb, ind_ppp->mp_rxseq, inl_ppp->mp_cfg & SC_IN_SHORT_SEQ); - ind_ppp->mp_rxseq = seq; - - if (inl_ppp->mp_rxseq == (u32) -1) { - /* first packet */ - inl_ppp->mp_rxseq = seq; - } - if (MP_LT(seq, inl_ppp->mp_rxseq)) { - goto drop; - } - /* Find the minimum sequence number received over all channels. - * No fragments with numbers lower than this will arrive later. */ - inl_ppp->mp_rxseq = seq; - list_for_each_entry(qdev, &lp->online, online) { - struct ind_ppp *ind_ppp = qdev->ind_priv; - if (MP_LT(ind_ppp->mp_rxseq, inl_ppp->mp_rxseq)) - inl_ppp->mp_rxseq = ind_ppp->mp_rxseq; - } - - /* Insert the skb into the list of received fragments, ordered by - * sequence number */ - if (mp_insert_frag(frags, skb)) - goto drop; - - while ((skb = mp_reassemble(lp))) { - if (isdn_ppp_strip_proto(skb, &proto)) { - kfree_skb(skb); - continue; - } - ippp_receive(idev, skb, proto); - } - return; - - drop: - lp->stats.rx_errors++; - kfree_skb(skb); -} diff -puN -L drivers/isdn/i4l/isdn_ppp_mp.h drivers/isdn/i4l/isdn_ppp_mp.h~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ppp_mp.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,58 +0,0 @@ -/* Linux ISDN subsystem, PPP CCP support - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * 1995,96 by Thinking Objects Software GmbH Wuerzburg - * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef __ISDN_PPP_MP_H__ -#define __ISDN_PPP_MP_H__ - -#include "isdn_net_lib.h" - -#ifdef CONFIG_ISDN_MPP - -int ippp_mp_bind(isdn_net_dev *idev); -void ippp_mp_disconnected(isdn_net_dev *idev); -int ippp_mp_bundle(isdn_net_dev *idev, int val); -void ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb); -void ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto); - -#else - -static inline int -ippp_mp_bind(isdn_net_dev *idev) -{ - return 0; -} - -static void -ippp_mp_disconnected(isdn_net_dev *idev) -{ -} - -static inline int -ippp_mp_bundle(isdn_net_dev *idev, int val) -{ - return -EINVAL; -} - -static inline void -ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb) -{ - ippp_xmit(idev, skb); -} - -static inline void -ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto) -{ - ippp_receive(idev, skb, proto); -} - -#endif - -#endif diff -puN -L drivers/isdn/i4l/isdn_ppp_vj.c drivers/isdn/i4l/isdn_ppp_vj.c~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ppp_vj.c +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,128 +0,0 @@ -/* Linux ISDN subsystem, PPP VJ header compression - * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include "isdn_ppp_vj.h" -#include "isdn_common.h" -#include "isdn_net_lib.h" -#include "isdn_ppp.h" - -struct slcompress * -ippp_vj_alloc(void) -{ - return slhc_init(16, 16); -} - -void -ippp_vj_free(struct slcompress *slcomp) -{ - slhc_free(slcomp); -} - -int -ippp_vj_set_maxcid(isdn_net_dev *idev, int val) -{ - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - struct slcompress *sltmp; - - sltmp = slhc_init(16, val + 1); - if (!sltmp) - return -ENOMEM; - - if (inl_ppp->slcomp) - slhc_free(inl_ppp->slcomp); - - inl_ppp->slcomp = sltmp; - return 0; -} - -void -ippp_vj_decompress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 proto) -{ - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - struct slcompress *slcomp = inl_ppp->slcomp; - struct sk_buff *skb; - int len; - - switch (proto) { - case PPP_VJC_UNCOMP: - if (slhc_remember(slcomp, skb_old->data, skb_old->len) <= 0) - goto drop; - - skb = skb_old; - break; - case PPP_VJC_COMP: - skb = dev_alloc_skb(skb_old->len + 128); - if (!skb) - goto drop; - - memcpy(skb->data, skb_old->data, skb_old->len); - len = slhc_uncompress(slcomp, skb->data, skb_old->len); - if (len < 0) - goto drop_both; - - skb_put(skb, len); - kfree_skb(skb_old); - break; - default: - isdn_BUG(); - goto drop; - } - isdn_netif_rx(idev, skb, htons(ETH_P_IP)); - return; - - drop_both: - kfree_skb(skb); - drop: - kfree_skb(skb_old); - idev->mlp->stats.rx_dropped++; -} - -struct sk_buff * -ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto) -{ - struct inl_ppp *inl_ppp = idev->mlp->inl_priv; - struct ind_ppp *ind_ppp = idev->ind_priv; - struct slcompress *slcomp = inl_ppp->slcomp; - struct sk_buff *skb; - unsigned char *buf; - int len; - - if (!(ind_ppp->pppcfg & SC_COMP_TCP) || *proto != PPP_IP) - return skb_old; - - skb = isdn_ppp_dev_alloc_skb(idev, skb_old->len, GFP_ATOMIC); - if (!skb) - return skb_old; - - skb_put(skb, skb_old->len); - buf = skb_old->data; - // FIXME flag should be per bundle - len = slhc_compress(slcomp, skb_old->data, skb_old->len, skb->data, - &buf, !(ind_ppp->pppcfg & SC_NO_TCP_CCID)); - - if (buf == skb_old->data) { - kfree_skb(skb); - skb = skb_old; - } else { - kfree_skb(skb_old); - } - skb_trim(skb, len); - - /* cslip style -> PPP */ - if ((skb->data[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) { - skb->data[0] &= ~SL_TYPE_COMPRESSED_TCP; - *proto = PPP_VJC_COMP; - } else if ((skb->data[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { - skb->data[0] &= ~SL_TYPE_UNCOMPRESSED_TCP; - skb->data[0] |= SL_TYPE_IP; - *proto = PPP_VJC_UNCOMP; - } - return skb; -} - diff -puN -L drivers/isdn/i4l/isdn_ppp_vj.h drivers/isdn/i4l/isdn_ppp_vj.h~i4l /dev/null --- 25/drivers/isdn/i4l/isdn_ppp_vj.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,61 +0,0 @@ -/* Linux ISDN subsystem, PPP VJ header compression - * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * 1999-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef __ISDN_PPP_VJ_H__ -#define __ISDN_PPP_VJ_H__ - -#include "isdn_net_lib.h" - -#ifdef CONFIG_ISDN_PPP_VJ - - -struct slcompress * -ippp_vj_alloc(void); - -void -ippp_vj_free(struct slcompress *slcomp); - -int -ippp_vj_set_maxcid(isdn_net_dev *idev, int val); - -void -ippp_vj_decompress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 proto); - -struct sk_buff * -ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto); - - -#else - - -static inline struct slcompress * -ippp_vj_alloc(void) -{ return (struct slcompress *) !NULL; } - -static inline void -ippp_vj_free(struct slcompress *slcomp) -{ } - -static inline int -ippp_vj_set_maxcid(isdn_net_dev *idev, int val) -{ return -EINVAL; } - -static inline struct sk_buff * -ippp_vj_decompress(struct slcompress *slcomp, struct sk_buff *skb_old, - u16 proto) -{ return skb_old; } - -static inline struct sk_buff * -ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto) -{ return skb_old; } - - -#endif - -#endif diff -puN drivers/isdn/i4l/isdn_tty.c~i4l drivers/isdn/i4l/isdn_tty.c --- 25/drivers/isdn/i4l/isdn_tty.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_tty.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,20 +1,17 @@ -/* Linux ISDN subsystem, tty functions and AT-command emulator +/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ + * + * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ +#undef ISDN_TTY_STAT_DEBUG -#define ISDN_TTY_STAT_DEBUG -#define ISDN_DEBUG_MODEM_HUP -#define ISDN_DEBUG_MODEM_VOICE -#define ISDN_DEBUG_MODEM_OPEN -#define ISDN_DEBUG_MODEM_IOCTL -#define ISDN_DEBUG_MODEM_ICALL - -#include +#include #include #include "isdn_common.h" #include "isdn_tty.h" @@ -24,51 +21,33 @@ #define VBUFX (VBUF/16) #endif -#define RING_TIMEOUT (5*HZ) /* repeat RING every 5 secs */ #define FIX_FILE_TRANSFER #define DUMMY_HAYES_AT /* Prototypes */ -static void isdn_tty_modem_xmit(struct modem_info *info); static int isdn_tty_edit_at(const char *, int, modem_info *, int); -static void isdn_tty_escape_timer(unsigned long data); -static void isdn_tty_ring_timer(unsigned long data); -static void isdn_tty_connect_timer(unsigned long data); -static void isdn_tty_check_esc(struct modem_info *info, - const unsigned char *p, int count); +static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *, int); static void isdn_tty_modem_reset_regs(modem_info *, int); static void isdn_tty_cmd_ATA(modem_info *); static void isdn_tty_flush_buffer(struct tty_struct *); static void isdn_tty_modem_result(int, modem_info *); -static int isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c); -static int isdn_tty_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb); #ifdef CONFIG_ISDN_AUDIO static int isdn_tty_countDLE(unsigned char *, int); #endif -static int -isdn_tty_event_callback(struct isdn_slot *slot, int pr, void *arg) -{ - switch (pr) { - case EV_DATA_IND: - return isdn_tty_rcv_skb(slot, arg); - default: - return isdn_tty_stat_callback(slot, arg); - } -} - /* Leave this unchanged unless you know what you do! */ #define MODEM_PARANOIA_CHECK #define MODEM_DO_RESTART -struct isdn_modem isdn_mdm; - static int bit2si[8] = {1, 5, 7, 7, 7, 7, 7, 7}; static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; +char *isdn_tty_revision = "$Revision: 1.1.2.3 $"; + + /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() * to stuff incoming data directly into a tty's flip-buffer. This * is done to speed up tty-receiving if the receive-queue is empty. @@ -124,166 +103,78 @@ isdn_tty_try_read(modem_info * info, str return 0; } -/* - * isdn_slot_readbchan() tries to get data from the read-queue. - * It MUST be called with interrupts off. - */ -static int -isdn_tty_readbchan(struct modem_info *info, u_char * buf, u_char * fp, int len) -{ - int count; - u_int count_pull; - int count_put; - int dflag; - struct sk_buff *skb; - u_char *cp; - - if (skb_queue_empty(&info->rpqueue)) - return 0; - - if (len > info->rcvcount) - len = info->rcvcount; - cp = buf; - count = 0; - while (len) { - if (!(skb = skb_peek(&info->rpqueue))) - break; -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_LOCK(skb)) - break; - ISDN_AUDIO_SKB_LOCK(skb) = 1; - if (ISDN_AUDIO_SKB_DLECOUNT(skb) || info->DLEflag) { - char *p = skb->data; - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (len > 0)) { - len--; - if (info->DLEflag) { - *cp++ = DLE; - info->DLEflag = 0; - } else { - *cp++ = *p; - if (*p == DLE) { - info->DLEflag = 1; - (ISDN_AUDIO_SKB_DLECOUNT(skb))--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { -#endif - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((int)(count_pull = skb->len) > len) { - count_pull = len; - dflag = 0; - } - count_put = count_pull; - memcpy(cp, skb->data, count_put); - cp += count_put; - len -= count_put; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - count += count_put; - if (fp) { - memset(fp, 0, count_put); - fp += count_put; - } - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ - if (fp) - *(fp - 1) = 0xff; -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - skb = skb_dequeue(&info->rpqueue); - dev_kfree_skb(skb); - } else { - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb, count_pull); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - info->rcvcount -= count_put; - } - return count; -} - /* isdn_tty_readmodem() is called periodically from within timer-interrupt. * It tries getting received data from the receive queue an stuff it into * the tty's flip-buffer. */ -static void -isdn_tty_readmodem(unsigned long data) +void +isdn_tty_readmodem(void) { - struct modem_info *info = (struct modem_info *) data; + int resched = 0; + int midx; + int i; int c; int r; - ulong flags; struct tty_struct *tty; + modem_info *info; - if (!info->online) - return; - - r = 0; -#ifdef CONFIG_ISDN_AUDIO - isdn_audio_eval_dtmf(info); - if ((info->vonline & 1) && (info->emu.vpar[1])) - isdn_audio_eval_silence(info); -#endif - if ((tty = info->tty)) { - if (info->mcr & UART_MCR_RTS) { - c = TTY_FLIPBUF_SIZE - tty->flip.count; - if (c > 0) { - save_flags(flags); - cli(); - r = isdn_tty_readbchan(info, - tty->flip.char_buf_ptr, - tty->flip.flag_buf_ptr, c); - /* CISCO AsyncPPP Hack */ - if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) - memset(tty->flip.flag_buf_ptr, 0, r); - tty->flip.count += r; - tty->flip.flag_buf_ptr += r; - tty->flip.char_buf_ptr += r; - if (r) - schedule_delayed_work(&tty->flip.work, 1); - restore_flags(flags); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if ((midx = dev->m_idx[i]) >= 0) { + info = &dev->mdm.info[midx]; + if (info->online) { + r = 0; +#ifdef CONFIG_ISDN_AUDIO + isdn_audio_eval_dtmf(info); + if ((info->vonline & 1) && (info->emu.vpar[1])) + isdn_audio_eval_silence(info); +#endif + if ((tty = info->tty)) { + if (info->mcr & UART_MCR_RTS) { + c = TTY_FLIPBUF_SIZE - tty->flip.count; + if (c > 0) { + r = isdn_readbchan(info->isdn_driver, info->isdn_channel, + tty->flip.char_buf_ptr, + tty->flip.flag_buf_ptr, c, 0); + /* CISCO AsyncPPP Hack */ + if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) + memset(tty->flip.flag_buf_ptr, 0, r); + tty->flip.count += r; + tty->flip.flag_buf_ptr += r; + tty->flip.char_buf_ptr += r; + if (r) + schedule_delayed_work(&tty->flip.work, 1); + } + } else + r = 1; + } else + r = 1; + if (r) { + info->rcvsched = 0; + resched = 1; + } else + info->rcvsched = 1; } - } else - r = 1; - } else - r = 1; - - if (r) { - info->rcvsched = 0; - mod_timer(&info->read_timer, jiffies + 4); - } else - info->rcvsched = 1; + } + } + if (!resched) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); } -static int -isdn_tty_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb) +int +isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) { ulong flags; + int midx; #ifdef CONFIG_ISDN_AUDIO int ifmt; #endif modem_info *info; - info = slot->priv; + if ((midx = dev->m_idx[i]) < 0) { + /* if midx is invalid, packet is not for tty */ + return 0; + } + info = &dev->mdm.info[midx]; #ifdef CONFIG_ISDN_AUDIO ifmt = 1; @@ -315,12 +206,6 @@ isdn_tty_rcv_skb(struct isdn_slot *slot, skb_pull(skb, 4); } #ifdef CONFIG_ISDN_AUDIO - if ((size_t)skb_headroom(skb) < sizeof(isdnaudio_header)) { - printk(KERN_WARNING - "isdn_audio: insufficient skb_headroom, dropping\n"); - kfree_skb(skb); - return 1; - } ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; ISDN_AUDIO_SKB_LOCK(skb) = 0; if (info->vonline & 1) { @@ -364,53 +249,49 @@ isdn_tty_rcv_skb(struct isdn_slot *slot, #endif #endif /* Try to deliver directly via tty-flip-buf if queue is empty */ - save_flags(flags); - cli(); - if (skb_queue_empty(&info->rpqueue)) + spin_lock_irqsave(&info->readlock, flags); + if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) if (isdn_tty_try_read(info, skb)) { - restore_flags(flags); + spin_unlock_irqrestore(&info->readlock, flags); return 1; } /* Direct deliver failed or queue wasn't empty. * Queue up for later dequeueing via timer-irq. */ - isdn_tty_queue_tail(info, skb, skb->len + __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb); + dev->drv[di]->rcvcount[channel] += + (skb->len #ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_DLECOUNT(skb) #endif - ); - restore_flags(flags); + ); + spin_unlock_irqrestore(&info->readlock, flags); /* Schedule dequeuing */ - if ((get_isdn_dev())->modempoll && info->rcvsched) - mod_timer(&info->read_timer, jiffies + 4); + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); return 1; } void isdn_tty_cleanup_xmit(modem_info * info) { - unsigned long flags; - - save_flags(flags); - cli(); skb_queue_purge(&info->xmit_queue); #ifdef CONFIG_ISDN_AUDIO skb_queue_purge(&info->dtmf_queue); #endif - restore_flags(flags); } static void isdn_tty_tint(modem_info * info) { struct sk_buff *skb = skb_dequeue(&info->xmit_queue); - int len, - slen; + int len, slen; if (!skb) return; len = skb->len; - if ((slen = isdn_slot_write(info->isdn_slot, skb)) == len) { + if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, + info->isdn_channel, 1, skb)) == len) { struct tty_struct *tty = info->tty; info->send_outstanding++; info->msr &= ~UART_MSR_CTS; @@ -573,11 +454,11 @@ isdn_tty_senddown(modem_info * info) atomic_inc(&info->xmit_lock); if (!(atomic_dec_and_test(&info->xmit_lock))) return; - if (info->isdn_slot < 0) { + if (info->isdn_driver < 0) { info->xmit_count = 0; return; } - skb_res = isdn_slot_hdrlen(info->isdn_slot); + skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 2) audio_len = buflen * voice_cf[info->emu.vpar[3]]; @@ -677,8 +558,6 @@ isdn_tty_modem_ncarrier(modem_info * inf { if (info->ncarrier) { info->nc_timer.expires = jiffies + HZ; - info->nc_timer.function = isdn_tty_modem_do_ncarrier; - info->nc_timer.data = (unsigned long) info; add_timer(&info->nc_timer); } } @@ -721,8 +600,9 @@ isdn_tty_dial(char *n, modem_info * info int usg = ISDN_USAGE_MODEM; int si = 7; int l2 = m->mdmreg[REG_L2PROT]; - ulong flags; - struct isdn_slot *slot; + u_long flags; + isdn_ctrl cmd; + int i; int j; for (j = 7; j >= 0; j--) @@ -743,39 +623,58 @@ isdn_tty_dial(char *n, modem_info * info } #endif m->mdmreg[REG_SI1I] = si2bit[si]; - save_flags(flags); - cli(); - slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (!slot) { - restore_flags(flags); + spin_lock_irqsave(&dev->lock, flags); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); + if (i < 0) { + spin_unlock_irqrestore(&dev->lock, flags); isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { - struct dial_info dial = { - .l2_proto = l2, - .l3_proto = m->mdmreg[REG_L3PROT], - .si1 = si, - .si2 = m->mdmreg[REG_SI2], - .msn = m->msn, - .phone = n, - }; - - info->isdn_slot = slot; - slot->usage |= ISDN_USAGE_MODEM; - slot->priv = info; - slot->event_cb = isdn_tty_event_callback; + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; info->last_dir = 1; - info->last_l2 = l2; strcpy(info->last_num, n); - restore_flags(flags); + isdn_info_update(); + spin_unlock_irqrestore(&dev->lock, flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + info->last_l2 = l2; + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); #ifdef CONFIG_ISDN_TTY_FAX if (l2 == ISDN_PROTO_L2_FAX) { - dial.fax = info->fax; + cmd.parm.fax = info->fax; info->fax->direction = ISDN_TTY_FAX_CONN_OUT; } #endif + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + sprintf(cmd.parm.setup.phone, "%s", n); + sprintf(cmd.parm.setup.eazmsn, "%s", + isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.parm.setup.si1 = si; + cmd.parm.setup.si2 = m->mdmreg[REG_SI2]; + cmd.command = ISDN_CMD_DIAL; info->dialing = 1; - isdn_slot_dial(info->isdn_slot, &dial); - mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ); + info->emu.carrierwait = 0; + strcpy(dev->num[i], n); + isdn_info_update(); + isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } } @@ -787,15 +686,19 @@ void isdn_tty_modem_hup(modem_info * info, int local) { isdn_ctrl cmd; - struct isdn_slot *slot; + int di, ch; if (!info) return; - slot = info->isdn_slot; - if (!slot) + di = info->isdn_driver; + ch = info->isdn_channel; + if (di < 0 || ch < 0) return; + info->isdn_driver = -1; + info->isdn_channel = -1; + #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); #endif @@ -837,15 +740,21 @@ isdn_tty_modem_hup(modem_info * info, in info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); info->lsr |= UART_LSR_TEMT; - if (local) - isdn_slot_command(slot, ISDN_CMD_HANGUP, &cmd); + if (local) { + cmd.driver = di; + cmd.command = ISDN_CMD_HANGUP; + cmd.arg = ch; + isdn_command(&cmd); + } + isdn_all_eaz(di, ch); info->emu.mdmreg[REG_RINGCNT] = 0; - skb_queue_purge(&info->rpqueue); - slot->priv = NULL; - slot->event_cb = NULL; - isdn_slot_free(slot); - info->isdn_slot = NULL; + isdn_free_channel(di, ch, 0); + + if (info->drv_index >= 0) { + dev->m_idx[info->drv_index] = -1; + info->drv_index = -1; + } } /* @@ -875,10 +784,11 @@ isdn_tty_suspend(char *id, modem_info * printk(KERN_DEBUG "Msusp ttyI%d\n", info->line); #endif l = strlen(id); - if ((info->isdn_slot >= 0)) { + if ((info->isdn_driver >= 0)) { cmd.parm.cmsg.Length = l+18; cmd.parm.cmsg.Command = CAPI_FACILITY; cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ cmd.parm.cmsg.para[1] = 0; cmd.parm.cmsg.para[2] = l + 3; @@ -886,7 +796,10 @@ isdn_tty_suspend(char *id, modem_info * cmd.parm.cmsg.para[4] = 0; cmd.parm.cmsg.para[5] = l; strncpy(&cmd.parm.cmsg.para[6], id, l); - isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd); + cmd.command = CAPI_PUT_MESSAGE; + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + isdn_command(&cmd); } } @@ -905,7 +818,7 @@ isdn_tty_resume(char *id, modem_info * i int l2 = m->mdmreg[REG_L2PROT]; isdn_ctrl cmd; ulong flags; - struct isdn_slot *slot; + int i; int j; int l; @@ -928,28 +841,44 @@ isdn_tty_resume(char *id, modem_info * i } #endif m->mdmreg[REG_SI1I] = si2bit[si]; - save_flags(flags); - cli(); - slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (!slot) { - restore_flags(flags); + spin_lock_irqsave(&dev->lock, flags); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); + if (i < 0) { + spin_unlock_irqrestore(&dev->lock, flags); isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { - info->isdn_slot = slot; - slot->usage |= ISDN_USAGE_MODEM; - slot->priv = info; - slot->event_cb = isdn_tty_event_callback; + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; info->last_dir = 1; // strcpy(info->last_num, n); - restore_flags(flags); + isdn_info_update(); + spin_unlock_irqrestore(&dev->lock, flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; info->last_l2 = l2; - cmd.arg = l2 << 8; - isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd); - cmd.arg = m->mdmreg[REG_L3PROT] << 8; - isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd); + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; cmd.parm.cmsg.Length = l+18; cmd.parm.cmsg.Command = CAPI_FACILITY; cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ cmd.parm.cmsg.para[1] = 0; cmd.parm.cmsg.para[2] = l+3; @@ -957,11 +886,12 @@ isdn_tty_resume(char *id, modem_info * i cmd.parm.cmsg.para[4] = 0; cmd.parm.cmsg.para[5] = l; strncpy(&cmd.parm.cmsg.para[6], id, l); + cmd.command =CAPI_PUT_MESSAGE; info->dialing = 1; // strcpy(dev->num[i], n); isdn_info_update(); - isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd); - mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ); + isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } } @@ -977,7 +907,7 @@ isdn_tty_send_msg(modem_info * info, ate int l2 = m->mdmreg[REG_L2PROT]; isdn_ctrl cmd; ulong flags; - struct isdn_slot *slot; + int i; int j; int l; @@ -1004,45 +934,62 @@ isdn_tty_send_msg(modem_info * info, ate } #endif m->mdmreg[REG_SI1I] = si2bit[si]; - save_flags(flags); - cli(); - slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (!slot) { - restore_flags(flags); + spin_lock_irqsave(&dev->lock, flags); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); + if (i < 0) { + spin_unlock_irqrestore(&dev->lock, flags); isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { - info->isdn_slot = slot; - slot->usage |= ISDN_USAGE_MODEM; - slot->priv = info; - slot->event_cb = isdn_tty_event_callback; + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; info->last_dir = 1; - restore_flags(flags); + isdn_info_update(); + spin_unlock_irqrestore(&dev->lock, flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; info->last_l2 = l2; - cmd.arg = l2 << 8; - isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd); - cmd.arg = m->mdmreg[REG_L3PROT] << 8; - isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd); + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; cmd.parm.cmsg.Length = l+14; cmd.parm.cmsg.Command = CAPI_MANUFACTURER; cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; cmd.parm.cmsg.para[0] = l+1; strncpy(&cmd.parm.cmsg.para[1], msg, l); cmd.parm.cmsg.para[l+1] = 0xd; + cmd.command =CAPI_PUT_MESSAGE; /* info->dialing = 1; strcpy(dev->num[i], n); isdn_info_update(); */ - isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd); + isdn_command(&cmd); } } static inline int -isdn_tty_paranoia_check(modem_info * info, char *name, const char *routine) +isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine) { #ifdef MODEM_PARANOIA_CHECK if (!info) { printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n", - name, routine); + name, routine); return 1; } if (info->magic != ISDN_ASYNC_MAGIC) { @@ -1119,12 +1066,9 @@ isdn_tty_change_speed(modem_info * info) static int isdn_tty_startup(modem_info * info) { - ulong flags; - if (info->flags & ISDN_ASYNC_INITIALIZED) return 0; - save_flags(flags); - cli(); + isdn_lock_drivers(); #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line); #endif @@ -1142,7 +1086,6 @@ isdn_tty_startup(modem_info * info) info->flags |= ISDN_ASYNC_INITIALIZED; info->msr |= (UART_MSR_DSR | UART_MSR_CTS); info->send_outstanding = 0; - restore_flags(flags); return 0; } @@ -1153,15 +1096,12 @@ isdn_tty_startup(modem_info * info) static void isdn_tty_shutdown(modem_info * info) { - ulong flags; - if (!(info->flags & ISDN_ASYNC_INITIALIZED)) return; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line); #endif - save_flags(flags); - cli(); /* Disable interrupts */ + isdn_unlock_drivers(); info->msr &= ~UART_MSR_RI; if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); @@ -1177,7 +1117,6 @@ isdn_tty_shutdown(modem_info * info) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ISDN_ASYNC_INITIALIZED; - restore_flags(flags); } /* isdn_tty_write() is the main send-routine. It is called from the upper @@ -1207,8 +1146,8 @@ isdn_tty_write(struct tty_struct *tty, i c = count; if (c > info->xmit_size - info->xmit_count) c = info->xmit_size - info->xmit_count; - if (info->isdn_slot && c > isdn_slot_maxbufsize(info->isdn_slot)) - c = isdn_slot_maxbufsize(info->isdn_slot); + if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize) + c = dev->drv[info->isdn_driver]->maxbufsize; if (c <= 0) break; if ((info->online > 1) @@ -1216,17 +1155,17 @@ isdn_tty_write(struct tty_struct *tty, i || (info->vonline & 3) #endif ) { - if (from_user) { - if (copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c)) { - total = -EFAULT; - goto out; - } - } else - memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); #ifdef CONFIG_ISDN_AUDIO if (!info->vonline) #endif - isdn_tty_check_esc(info, &info->xmit_buf[info->xmit_count], c); + isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c, + &(m->pluscount), + &(m->lastplus), + from_user); + if (from_user) + copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c); + else + memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); #ifdef CONFIG_ISDN_AUDIO if (info->vonline) { int cc = isdn_tty_handleDLEdown(info, m, c); @@ -1265,9 +1204,12 @@ isdn_tty_write(struct tty_struct *tty, i if (info->vonline & 4) { /* ETX seen */ isdn_ctrl c; + c.command = ISDN_CMD_FAXCMD; + c.driver = info->isdn_driver; + c.arg = info->isdn_channel; c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL; c.parm.aux.subcmd = ETX; - isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c); + isdn_command(&c); } info->vonline = 0; #ifdef ISDN_DEBUG_MODEM_VOICE @@ -1296,9 +1238,12 @@ isdn_tty_write(struct tty_struct *tty, i } atomic_dec(&info->xmit_lock); if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) { - isdn_tty_modem_xmit(info); + if (m->mdmreg[REG_DXMT] & BIT_DXMT) { + isdn_tty_senddown(info); + isdn_tty_tint(info); + } + isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); } -out: if (from_user) up(&info->write_sem); return total; @@ -1334,22 +1279,16 @@ static void isdn_tty_flush_buffer(struct tty_struct *tty) { modem_info *info; - unsigned long flags; - save_flags(flags); - cli(); if (!tty) { - restore_flags(flags); return; } info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) { - restore_flags(flags); return; } isdn_tty_cleanup_xmit(info); info->xmit_count = 0; - restore_flags(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -1364,7 +1303,7 @@ isdn_tty_flush_chars(struct tty_struct * if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars")) return; if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) - isdn_tty_modem_xmit(info); + isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); } /* @@ -1424,105 +1363,73 @@ isdn_tty_get_lsr_info(modem_info * info, { u_char status; uint result; - ulong flags; - save_flags(flags); - cli(); status = info->lsr; - restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); return put_user(result, (uint *) value); } static int -isdn_tty_get_modem_info(modem_info * info, uint * value) +isdn_tty_tiocmget(struct tty_struct *tty, struct file *file) { - u_char control, - status; - uint result; - ulong flags; + modem_info *info = (modem_info *) tty->driver_data; + u_char control, status; + + if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); +#endif control = info->mcr; - save_flags(flags); - cli(); status = info->msr; - restore_flags(flags); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - return put_user(result, (uint *) value); } static int -isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value) +isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { - uint arg; - int pre_dtr; + modem_info *info = (modem_info *) tty->driver_data; + + if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; - if (get_user(arg, (uint *) value)) - return -EFAULT; - switch (cmd) { - case TIOCMBIS: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line); -#endif - if (arg & TIOCM_RTS) { - info->mcr |= UART_MCR_RTS; - } - if (arg & TIOCM_DTR) { - info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); - } - break; - case TIOCMBIC: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line); -#endif - if (arg & TIOCM_RTS) { - info->mcr &= ~UART_MCR_RTS; - } - if (arg & TIOCM_DTR) { - info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { - isdn_tty_modem_reset_regs(info, 0); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); -#endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_hup(info, 1); - } - } - break; - case TIOCMSET: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear); #endif - pre_dtr = (info->mcr & UART_MCR_DTR); - info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); - if (pre_dtr |= (info->mcr & UART_MCR_DTR)) { - if (!(info->mcr & UART_MCR_DTR)) { - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { - isdn_tty_modem_reset_regs(info, 0); + + if (set & TIOCM_RTS) + info->mcr |= UART_MCR_RTS; + if (set & TIOCM_DTR) { + info->mcr |= UART_MCR_DTR; + isdn_tty_modem_ncarrier(info); + } + + if (clear & TIOCM_RTS) + info->mcr &= ~UART_MCR_RTS; + if (clear & TIOCM_DTR) { + info->mcr &= ~UART_MCR_DTR; + if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { + isdn_tty_modem_reset_regs(info, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMSET\n"); + printk(KERN_DEBUG "Mhup in TIOCMSET\n"); #endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_hup(info, 1); - } - } else - isdn_tty_modem_ncarrier(info); - } - break; - default: - return -EINVAL; + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_hup(info, 1); + } } return 0; } @@ -1572,15 +1479,6 @@ isdn_tty_ioctl(struct tty_struct *tty, s ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; - case TIOCMGET: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); -#endif - return isdn_tty_get_modem_info(info, (uint *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return isdn_tty_set_modem_info(info, cmd, (uint *) arg); case TIOCSERGETLSR: /* Get line status register */ #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); @@ -1623,7 +1521,6 @@ isdn_tty_block_til_ready(struct tty_stru { DECLARE_WAITQUEUE(wait, NULL); int do_clocal = 0; - unsigned long flags; int retval; /* @@ -1649,11 +1546,18 @@ isdn_tty_block_til_ready(struct tty_stru */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) + return -EBUSY; info->flags |= ISDN_ASYNC_NORMAL_ACTIVE; return 0; } - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1667,11 +1571,8 @@ isdn_tty_block_til_ready(struct tty_stru printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n", info->line, info->count); #endif - save_flags(flags); - cli(); if (!(tty_hung_up_p(filp))) info->count--; - restore_flags(flags); info->blocked_open++; while (1) { set_current_state(TASK_INTERRUPTIBLE); @@ -1687,7 +1588,8 @@ isdn_tty_block_til_ready(struct tty_stru #endif break; } - if (!(info->flags & ISDN_ASYNC_CLOSING) && + if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ISDN_ASYNC_CLOSING) && (do_clocal || (info->msr & UART_MSR_DCD))) { break; } @@ -1728,11 +1630,10 @@ isdn_tty_open(struct tty_struct *tty, st modem_info *info; int retval, line; - line = tty->index; if (line < 0 || line > ISDN_MAX_CHANNELS) return -ENODEV; - info = &isdn_mdm.info[line]; + info = &dev->mdm.info[line]; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) return -ENODEV; if (!try_module_get(info->owner)) { @@ -1740,7 +1641,7 @@ isdn_tty_open(struct tty_struct *tty, st return -ENODEV; } #ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, + printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, info->count); #endif info->count++; @@ -1768,7 +1669,7 @@ isdn_tty_open(struct tty_struct *tty, st #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line); #endif - (get_isdn_dev())->modempoll++; + dev->modempoll++; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_open normal exit\n"); #endif @@ -1779,23 +1680,15 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp) { modem_info *info = (modem_info *) tty->driver_data; - ulong flags; ulong timeout; - if (!info) + if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close")) return; - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close")) - goto out; - - #warning need fixing /kkeil - save_flags(flags); - cli(); if (tty_hung_up_p(filp)) { - restore_flags(flags); #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n"); #endif - goto out; + return; } if ((tty->count == 1) && (info->count != 1)) { /* @@ -1815,13 +1708,21 @@ isdn_tty_close(struct tty_struct *tty, s info->count = 0; } if (info->count) { - restore_flags(flags); #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n"); #endif - goto out; + return; } info->flags |= ISDN_ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + tty->closing = 1; /* * At this point we stop accepting input. To do this, we @@ -1830,7 +1731,7 @@ isdn_tty_close(struct tty_struct *tty, s * line status register. */ if (info->flags & ISDN_ASYNC_INITIALIZED) { - tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1844,7 +1745,7 @@ isdn_tty_close(struct tty_struct *tty, s break; } } - (get_isdn_dev())->modempoll--; + dev->modempoll--; isdn_tty_shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); @@ -1853,6 +1754,7 @@ isdn_tty_close(struct tty_struct *tty, s info->tty = 0; info->ncarrier = 0; tty->closing = 0; + module_put(info->owner); if (info->blocked_open) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/2); @@ -1860,12 +1762,9 @@ isdn_tty_close(struct tty_struct *tty, s } info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); - restore_flags(flags); #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_close normal exit\n"); #endif - out: - module_put(info->owner); } /* @@ -1880,7 +1779,7 @@ isdn_tty_hangup(struct tty_struct *tty) return; isdn_tty_shutdown(info); info->count = 0; - info->flags &= ~ISDN_ASYNC_NORMAL_ACTIVE; + info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1988,13 +1887,12 @@ modem_write_profile(atemu * m) memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); - if ((get_isdn_dev())->profd) - kill_pg_info(SIGIO, SEND_SIG_PRIV, - process_group((get_isdn_dev())->profd)); + if (dev->profd) + send_sig(SIGIO, dev->profd, 1); } static struct tty_operations modem_ops = { - .open = isdn_tty_open, + .open = isdn_tty_open, .close = isdn_tty_close, .write = isdn_tty_write, .flush_chars = isdn_tty_flush_chars, @@ -2006,16 +1904,18 @@ static struct tty_operations modem_ops = .unthrottle = isdn_tty_unthrottle, .set_termios = isdn_tty_set_termios, .hangup = isdn_tty_hangup, + .tiocmget = isdn_tty_tiocmget, + .tiocmset = isdn_tty_tiocmset, }; int -isdn_tty_init(void) +isdn_tty_modem_init(void) { - struct isdn_modem *m; - int i, retval; - modem_info *info; + isdn_modem_t *m; + int i, retval; + modem_info *info; - m = &isdn_mdm; + m = &dev->mdm; m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS); if (!m->tty_modem) return -ENOMEM; @@ -2027,7 +1927,7 @@ isdn_tty_init(void) m->tty_modem->subtype = SERIAL_TYPE_NORMAL; m->tty_modem->init_termios = tty_std_termios; m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - m->tty_modem->flags = TTY_DRIVER_REAL_RAW; + m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; m->tty_modem->driver_name = "isdn_tty"; tty_set_operations(m->tty_modem, &modem_ops); retval = tty_register_driver(m->tty_modem); @@ -2040,10 +1940,14 @@ isdn_tty_init(void) #ifdef CONFIG_ISDN_TTY_FAX if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) { printk(KERN_ERR "Could not allocate fax t30-buffer\n"); - return -3; + retval = -ENOMEM; + goto err_unregister; } #endif +#ifdef MODULE info->owner = THIS_MODULE; +#endif + spin_lock_init(&info->readlock); init_MUTEX(&info->write_sem); sprintf(info->last_cause, "0000"); sprintf(info->last_num, "none"); @@ -2061,41 +1965,27 @@ isdn_tty_init(void) info->blocked_open = 0; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - info->isdn_slot = NULL; - init_timer(&info->escape_timer); - info->escape_timer.data = (unsigned long) info; - info->escape_timer.function = isdn_tty_escape_timer; - init_timer(&info->ring_timer); - info->ring_timer.data = (unsigned long) info; - info->ring_timer.function = isdn_tty_ring_timer; - init_timer(&info->connect_timer); - info->connect_timer.data = (unsigned long) info; - info->connect_timer.function = isdn_tty_connect_timer; - init_timer(&info->read_timer); - info->read_timer.data = (unsigned long) info; - info->read_timer.function = isdn_tty_readmodem; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - skb_queue_head_init(&info->rpqueue); + info->isdn_driver = -1; + info->isdn_channel = -1; + info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; + init_timer(&info->nc_timer); + info->nc_timer.function = isdn_tty_modem_do_ncarrier; + info->nc_timer.data = (unsigned long) info; skb_queue_head_init(&info->xmit_queue); #ifdef CONFIG_ISDN_AUDIO skb_queue_head_init(&info->dtmf_queue); #endif - info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL); - if (!info->xmit_buf) { + if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) { printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); -#ifdef CONFIG_ISDN_TTY_FAX - kfree(info->fax); -#endif - goto err_unregister_cua; + retval = -ENOMEM; + goto err_unregister; } /* Make room for T.70 header */ info->xmit_buf += 4; } return 0; - - err_unregister_cua: +err_unregister: for (i--; i >= 0; i--) { info = &m->info[i]; #ifdef CONFIG_ISDN_TTY_FAX @@ -2117,19 +2007,19 @@ isdn_tty_exit(void) int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &isdn_mdm.info[i]; + info = &dev->mdm.info[i]; isdn_tty_cleanup_xmit(info); - skb_queue_purge(&info->rpqueue); #ifdef CONFIG_ISDN_TTY_FAX kfree(info->fax); #endif kfree(info->xmit_buf - 4); } - tty_unregister_driver(isdn_mdm.tty_modem); - put_tty_driver(isdn_mdm.tty_modem); - isdn_mdm.tty_modem = NULL; + tty_unregister_driver(dev->mdm.tty_modem); + put_tty_driver(dev->mdm.tty_modem); + dev->mdm.tty_modem = NULL; } + /* * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) * match the MSN against the MSNs (glob patterns) defined for tty_emulator, @@ -2193,11 +2083,12 @@ isdn_tty_match_icall(char *cid, atemu *e * CID is longer. */ int -isdn_tty_find_icall(struct isdn_slot *slot, setup_parm *setup) +isdn_tty_find_icall(int di, int ch, setup_parm *setup) { char *eaz; int i; int wret; + int idx; int si1; int si2; char *nr; @@ -2219,69 +2110,76 @@ isdn_tty_find_icall(struct isdn_slot *sl printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif wret = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&dev->lock, flags); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &isdn_mdm.info[i]; + modem_info *info = &dev->mdm.info[i]; if (info->count == 0) continue; if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ + idx = isdn_dc2minor(di, ch); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret); - printk(KERN_DEBUG "m_fi: sl=%d flags=%08lx drv=%d ch=%d usg=%d\n", sl, + printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx, info->flags, info->isdn_driver, info->isdn_channel, - slot->usage); + dev->usage[idx]); #endif if ( #ifndef FIX_FILE_TRANSFER (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) && #endif - (!info->isdn_slot)) { + (info->isdn_driver == -1) && + (info->isdn_channel == -1) && + (USG_NONE(dev->usage[idx]))) { int matchret; - if ((matchret = isdn_tty_match_icall(eaz, &info->emu, slot->di)) > wret) + if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret) wret = matchret; if (!matchret) { /* EAZ is matching */ - info->isdn_slot = slot; - slot->usage |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); - slot->priv = info; - slot->event_cb = isdn_tty_event_callback; - strcpy(slot->num, nr); + info->isdn_driver = di; + info->isdn_channel = ch; + info->drv_index = idx; + dev->m_idx[idx] = info->line; + dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; + dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); + strcpy(dev->num[idx], nr); strcpy(info->emu.cpn, eaz); info->emu.mdmreg[REG_SI1I] = si2bit[si1]; info->emu.mdmreg[REG_PLAN] = setup->plan; info->emu.mdmreg[REG_SCREEN] = setup->screen; - restore_flags(flags); + isdn_info_update(); + spin_unlock_irqrestore(&dev->lock, flags); printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, info->line); info->msr |= UART_MSR_RI; isdn_tty_modem_result(RESULT_RING, info); - mod_timer(&info->ring_timer, jiffies + RING_TIMEOUT); + isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return 1; } } } } - restore_flags(flags); + spin_unlock_irqrestore(&dev->lock, flags); printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, - (wret != 2)? "rejected" : "ignored"); + ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored"); return (wret == 2)?3:0; } #define TTY_IS_ACTIVE(info) \ - (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) + (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) -static int -isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c) +int +isdn_tty_stat_callback(int i, isdn_ctrl *c) { - isdn_ctrl cmd; + int mi; modem_info *info; char *e; - info = slot->priv; - if (1) { + if (i < 0) + return 0; + if ((mi = dev->m_idx[i]) >= 0) { + info = &dev->mdm.info[mi]; switch (c->command) { case ISDN_STAT_CINF: printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num); @@ -2294,12 +2192,16 @@ isdn_tty_stat_callback(struct isdn_slot #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line); #endif - info->msr |= UART_MSR_CTS; - if (info->send_outstanding) - if (!(--info->send_outstanding)) - info->lsr |= UART_LSR_TEMT; - isdn_tty_tint(info); - return 1; + if ((info->isdn_driver == c->driver) && + (info->isdn_channel == c->arg)) { + info->msr |= UART_MSR_CTS; + if (info->send_outstanding) + if (!(--info->send_outstanding)) + info->lsr |= UART_LSR_TEMT; + isdn_tty_tint(info); + return 1; + } + break; case ISDN_STAT_CAUSE: #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line); @@ -2326,7 +2228,6 @@ isdn_tty_stat_callback(struct isdn_slot #endif if (TTY_IS_ACTIVE(info)) { if (info->dialing == 1) { - isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTB, &cmd); info->dialing = 2; return 1; } @@ -2376,14 +2277,14 @@ isdn_tty_stat_callback(struct isdn_slot info->last_dir = 0; info->dialing = 0; info->rcvsched = 1; - if (USG_MODEM(slot->usage)) { + if (USG_MODEM(dev->usage[i])) { if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { strcpy(info->emu.connmsg, c->parm.num); isdn_tty_modem_result(RESULT_CONNECT, info); } else isdn_tty_modem_result(RESULT_CONNECT64000, info); } - if (USG_VOICE(slot->usage)) + if (USG_VOICE(dev->usage[i])) isdn_tty_modem_result(RESULT_VCON, info); return 1; } @@ -2400,6 +2301,34 @@ isdn_tty_stat_callback(struct isdn_slot return 1; } break; + case ISDN_STAT_NODCH: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line); +#endif + if (TTY_IS_ACTIVE(info)) { + if (info->dialing) { + info->dialing = 0; + info->last_l2 = -1; + info->last_si = 0; + sprintf(info->last_cause, "0000"); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); + } + isdn_tty_modem_hup(info, 0); + return 1; + } + break; + case ISDN_STAT_UNLOAD: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line); +#endif + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + info = &dev->mdm.info[i]; + if (info->isdn_driver == c->driver) { + if (info->online) + isdn_tty_modem_hup(info, 1); + } + } + return 1; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_STAT_FAXIND: if (TTY_IS_ACTIVE(info)) { @@ -2443,7 +2372,7 @@ isdn_tty_at_cout(char *msg, modem_info * atemu *m = &info->emu; char *p; char c; - ulong flags; + u_long flags; struct sk_buff *skb = 0; char *sp = 0; @@ -2451,30 +2380,22 @@ isdn_tty_at_cout(char *msg, modem_info * printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&info->readlock, flags); tty = info->tty; if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) { - restore_flags(flags); + spin_unlock_irqrestore(&info->readlock, flags); return; } /* use queue instead of direct flip, if online and */ /* data is in queue or flip buffer is full */ if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) || - (!skb_queue_empty(&info->rpqueue)))) { - skb = alloc_skb(strlen(msg) -#ifdef CONFIG_ISDN_AUDIO - + sizeof(isdnaudio_header) -#endif - , GFP_ATOMIC); + (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) { + skb = alloc_skb(strlen(msg), GFP_ATOMIC); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&info->readlock, flags); return; } -#ifdef CONFIG_ISDN_AUDIO - skb_reserve(skb, sizeof(isdnaudio_header)); -#endif sp = skb_put(skb, strlen(msg)); #ifdef CONFIG_ISDN_AUDIO ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; @@ -2505,13 +2426,15 @@ isdn_tty_at_cout(char *msg, modem_info * } } if (skb) { - isdn_tty_queue_tail(info, skb, skb->len); - restore_flags(flags); + __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb); + dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len; + spin_unlock_irqrestore(&info->readlock, flags); /* Schedule dequeuing */ - if ((get_isdn_dev())->modempoll && info->rcvsched) - mod_timer(&info->read_timer, jiffies + 4); + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + } else { - restore_flags(flags); + spin_unlock_irqrestore(&info->readlock, flags); schedule_delayed_work(&tty->flip.work, 1); } } @@ -2522,7 +2445,7 @@ isdn_tty_at_cout(char *msg, modem_info * static void isdn_tty_on_hook(modem_info * info) { - if (info->isdn_slot) { + if (info->isdn_channel >= 0) { #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n"); #endif @@ -2539,56 +2462,54 @@ isdn_tty_off_hook(void) #define PLUSWAIT1 (HZ/2) /* 0.5 sec. */ #define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */ -static void -isdn_tty_escape_timer(unsigned long data) -{ - struct modem_info *info = (struct modem_info *) data; - - if (!info->online) - return; - - info->emu.pluscount = 0; - info->online = 0; - isdn_tty_modem_result(RESULT_OK, info); -} - /* * Check Buffer for Modem-escape-sequence, activate timer-callback to * isdn_tty_modem_escape() if sequence found. + * + * Parameters: + * p pointer to databuffer + * plus escape-character + * count length of buffer + * pluscount count of valid escape-characters so far + * lastplus timestamp of last character */ -static void isdn_tty_check_esc(struct modem_info *info, - const unsigned char *p, int count) +static void +isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, + u_long *lastplus, int from_user) { - unsigned char plus = info->emu.mdmreg[REG_ESC]; + char cbuf[3]; if (plus > 127) return; - if (count > 3) { p += count - 3; count = 3; - info->emu.pluscount = 0; - info->emu.lastplus = jiffies; + *pluscount = 0; } - for (; count > 0; info->emu.lastplus = jiffies, count--) { - if (*(p++) != plus) { - info->emu.pluscount = 0; - continue; - } - if (info->emu.pluscount == 0) { - if (time_after(jiffies, info->emu.lastplus + PLUSWAIT2)) - info->emu.pluscount = 1; - } else { - if (time_after(jiffies, info->emu.lastplus + PLUSWAIT1)) - info->emu.pluscount = 1; - else - info->emu.pluscount++; - } + if (from_user) { + copy_from_user(cbuf, p, count); + p = cbuf; + } + while (count > 0) { + if (*(p++) == plus) { + if ((*pluscount)++) { + /* Time since last '+' > 0.5 sec. ? */ + if (time_after(jiffies, *lastplus + PLUSWAIT1)) + *pluscount = 1; + } else { + /* Time since last non-'+' < 1.5 sec. ? */ + if (time_before(jiffies, *lastplus + PLUSWAIT2)) + *pluscount = 0; + } + if ((*pluscount == 3) && (count == 1)) + isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1); + if (*pluscount > 3) + *pluscount = 1; + } else + *pluscount = 0; + *lastplus = jiffies; + count--; } - if (info->emu.pluscount == 3) - mod_timer(&info->escape_timer, jiffies + PLUSWAIT2); - else - del_timer(&info->escape_timer); } /* @@ -2606,7 +2527,6 @@ isdn_tty_modem_result(int code, modem_in {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR", "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", "RINGING", "NO MSN/EAZ", "VCON", "RUNG"}; - ulong flags; char s[ISDN_MSNLEN+10]; switch (code) { @@ -2622,16 +2542,12 @@ isdn_tty_modem_result(int code, modem_in (info->flags & ISDN_ASYNC_CLOSING), (!info->tty)); #endif - save_flags(flags); - cli(); m->mdmreg[REG_RINGCNT] = 0; del_timer(&info->nc_timer); info->ncarrier = 0; if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { - restore_flags(flags); return; } - restore_flags(flags); #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 1) { #ifdef ISDN_DEBUG_MODEM_VOICE @@ -2683,7 +2599,7 @@ isdn_tty_modem_result(int code, modem_in /* print CID, _before_ _every_ ring */ if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) { isdn_tty_at_cout("\r\nCALLER NUMBER: ", info); - isdn_tty_at_cout(info->isdn_slot->num, info); + isdn_tty_at_cout(dev->num[info->drv_index], info); if (m->mdmreg[REG_CDN] & BIT_CDN) { isdn_tty_at_cout("\r\nCALLED NUMBER: ", info); isdn_tty_at_cout(info->emu.cpn, info); @@ -2712,7 +2628,7 @@ isdn_tty_modem_result(int code, modem_in (m->mdmreg[REG_RINGCNT] == 1)) { isdn_tty_at_cout("\r\n", info); isdn_tty_at_cout("CALLER NUMBER: ", info); - isdn_tty_at_cout(info->isdn_slot->num, info); + isdn_tty_at_cout(dev->num[info->drv_index], info); if (m->mdmreg[REG_CDN] & BIT_CDN) { isdn_tty_at_cout("\r\nCALLED NUMBER: ", info); isdn_tty_at_cout(info->emu.cpn, info); @@ -2762,18 +2678,16 @@ isdn_tty_modem_result(int code, modem_in } } if (code == RESULT_NO_CARRIER) { - save_flags(flags); - cli(); if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { - restore_flags(flags); return; } if (info->tty->ldisc.flush_buffer) info->tty->ldisc.flush_buffer(info->tty); - if (info->flags & ISDN_ASYNC_CHECK_CD) { + if ((info->flags & ISDN_ASYNC_CHECK_CD) && + (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && + (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { tty_hangup(info->tty); } - restore_flags(flags); } } @@ -3222,7 +3136,7 @@ isdn_tty_cmd_ATA(modem_info * info) if (info->msr & UART_MSR_RI) { /* Accept incoming call */ info->last_dir = 0; - strcpy(info->last_num, info->isdn_slot->num); + strcpy(info->last_num, dev->num[info->drv_index]); m->mdmreg[REG_RINGCNT] = 0; info->msr &= ~UART_MSR_RI; l2 = m->mdmreg[REG_L2PROT]; @@ -3236,20 +3150,28 @@ isdn_tty_cmd_ATA(modem_info * info) l2 = ISDN_PROTO_L2_X75I; } #endif - cmd.arg = l2 << 8; + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = info->isdn_channel + (l2 << 8); info->last_l2 = l2; - isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd); - cmd.arg = m->mdmreg[REG_L3PROT] << 8; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); #ifdef CONFIG_ISDN_TTY_FAX if (l2 == ISDN_PROTO_L2_FAX) { cmd.parm.fax = info->fax; info->fax->direction = ISDN_TTY_FAX_CONN_IN; } #endif - isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_ACCEPTD; info->dialing = 16; - isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTD, &cmd); - mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ); + info->emu.carrierwait = 0; + isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } else isdn_tty_modem_result(RESULT_NO_ANSWER, info); } @@ -3293,7 +3215,7 @@ isdn_tty_cmd_PLUSF(char **p, modem_info #ifdef CONFIG_ISDN_TTY_FAX case '1': p[0]++; - if (!((get_isdn_dev())->global_features & + if (!(dev->global_features & ISDN_FEATURE_L3_FCLASS1)) PARSE_ERROR1; m->mdmreg[REG_SI1] = 1; @@ -3304,7 +3226,7 @@ isdn_tty_cmd_PLUSF(char **p, modem_info break; case '2': p[0]++; - if (!((get_isdn_dev())->global_features & + if (!(dev->global_features & ISDN_FEATURE_L3_FCLASS2)) PARSE_ERROR1; m->mdmreg[REG_SI1] = 1; @@ -3326,10 +3248,10 @@ isdn_tty_cmd_PLUSF(char **p, modem_info p[0]++; strcpy(rs, "\r\n0,"); #ifdef CONFIG_ISDN_TTY_FAX - if ((get_isdn_dev())->global_features & + if (dev->global_features & ISDN_FEATURE_L3_FCLASS1) strcat(rs, "1,"); - if ((get_isdn_dev())->global_features & + if (dev->global_features & ISDN_FEATURE_L3_FCLASS2) strcat(rs, "2,"); #endif @@ -3604,10 +3526,12 @@ isdn_tty_cmd_PLUSV(char **p, modem_info PARSE_ERROR1; m->vpar[4] = par1; m->vpar[5] = par2; - cmd.arg = ISDN_AUDIO_SETDD << 8; + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_AUDIO; + cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8); cmd.parm.num[0] = par1; cmd.parm.num[1] = par2; - isdn_slot_command(info->isdn_slot, ISDN_CMD_AUDIO, &cmd); + isdn_command(&cmd); break; } else if (*p[0] == '?') { @@ -3919,34 +3843,99 @@ isdn_tty_edit_at(const char *p, int coun return total; } -static void -isdn_tty_ring_timer(unsigned long data) +/* + * Switch all modem-channels who are online and got a valid + * escape-sequence 1.5 seconds ago, to command-mode. + * This function is called every second via timer-interrupt from within + * timer-dispatcher isdn_timer_function() + */ +void +isdn_tty_modem_escape(void) { - struct modem_info *info = (struct modem_info *) data; - - if (!(info->msr & UART_MSR_RI)) - return; + int ton = 0; + int i; + int midx; - isdn_tty_modem_result(RESULT_RING, info); - mod_timer(&info->ring_timer, jiffies + RING_TIMEOUT); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (USG_MODEM(dev->usage[i])) + if ((midx = dev->m_idx[i]) >= 0) { + modem_info *info = &dev->mdm.info[midx]; + if (info->online) { + ton = 1; + if ((info->emu.pluscount == 3) && + time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) { + info->emu.pluscount = 0; + info->online = 0; + isdn_tty_modem_result(RESULT_OK, info); + } + } + } + isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton); } - -static void -isdn_tty_modem_xmit(struct modem_info *info) + +/* + * Put a RING-message to all modem-channels who have the RI-bit set. + * This function is called every second via timer-interrupt from within + * timer-dispatcher isdn_timer_function() + */ +void +isdn_tty_modem_ring(void) { - isdn_tty_senddown(info); - isdn_tty_tint(info); + int ton = 0; + int i; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; + if (info->msr & UART_MSR_RI) { + ton = 1; + isdn_tty_modem_result(RESULT_RING, info); + } + } + isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); } -static void -isdn_tty_connect_timer(unsigned long data) +/* + * For all online tty's, try sending data to + * the lower levels. + */ +void +isdn_tty_modem_xmit(void) { - struct modem_info *info = (struct modem_info *) data; + int ton = 1; + int i; - if (info->dialing) { - info->dialing = 0; - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - isdn_tty_modem_hup(info, 1); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; + if (info->online) { + ton = 1; + isdn_tty_senddown(info); + isdn_tty_tint(info); + } } + isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); } +/* + * Check all channels if we have a 'no carrier' timeout. + * Timeout value is set by Register S7. + */ +void +isdn_tty_carrier_timeout(void) +{ + int ton = 0; + int i; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; + if (info->dialing) { + if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { + info->dialing = 0; + isdn_tty_modem_result(RESULT_NO_CARRIER, info); + isdn_tty_modem_hup(info, 1); + } + else + ton = 1; + } + } + isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton); +} diff -puN drivers/isdn/i4l/isdn_ttyfax.c~i4l drivers/isdn/i4l/isdn_ttyfax.c --- 25/drivers/isdn/i4l/isdn_ttyfax.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_ttyfax.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,6 @@ -/* Linux ISDN subsystem, tty_fax AT-command emulator +/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) * Copyright 1999 by Ralf Spachmann (mel@melware.de) @@ -6,6 +8,7 @@ * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ #undef ISDN_TTY_FAX_STAT_DEBUG @@ -16,8 +19,26 @@ #include "isdn_tty.h" #include "isdn_ttyfax.h" + +static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $"; + #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } +static char * +isdn_getrev(const char *revision) +{ + char *rev; + char *p; + + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; +} + /* * Fax Class 2 Modem results * @@ -53,7 +74,7 @@ isdn_tty_fax_modem_result(int code, mode case 2: /* +FCON */ /* Append CPN, if enabled */ if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) && - (!(info->isdn_slot->usage & ISDN_USAGE_OUTGOING))) { + (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) { sprintf(rs, "/%s", m->cpn); isdn_tty_at_cout(rs, info); } @@ -265,7 +286,7 @@ isdn_tty_fax_bitorder(modem_info * info, __u8 RightMask; __u8 fBit; __u8 Data; - u_int i; + int i; if (!info->fax->bor) { for (i = 0; i < skb->len; i++) { @@ -301,9 +322,8 @@ isdn_tty_cmd_FCLASS1(char **p, modem_inf static char *cmd[] = {"AE", "TS", "RS", "TM", "RM", "TH", "RH"}; isdn_ctrl c; - int par; - struct isdn_slot *slot; - unsigned long flags; + int par, i; + u_long flags; for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) @@ -340,32 +360,46 @@ isdn_tty_cmd_FCLASS1(char **p, modem_inf default: PARSE_ERROR1; } + c.command = ISDN_CMD_FAXCMD; #ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n", c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]); #endif - if (!info->isdn_slot) { - save_flags(flags); - cli(); + if (info->isdn_driver < 0) { if ((c.parm.aux.subcmd == AT_EQ_VALUE) || (c.parm.aux.subcmd == AT_COMMAND)) { - restore_flags(flags); PARSE_ERROR1; } + spin_lock_irqsave(&dev->lock, flags); /* get a temporary connection to the first free fax driver */ - slot = isdn_get_free_slot(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX, - ISDN_PROTO_L3_FCLASS1, -1, -1, "00"); - if (!slot) { - restore_flags(flags); + i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX, + ISDN_PROTO_L3_FCLASS1, -1, -1, "00"); + if (i < 0) { + spin_unlock_irqrestore(&dev->lock, flags); PARSE_ERROR1; } - info->isdn_slot = slot; - isdn_slot_command(slot, ISDN_CMD_FAXCMD, &c); - isdn_slot_free(slot); - info->isdn_slot = NULL; - restore_flags(flags); + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + spin_unlock_irqrestore(&dev->lock, flags); + c.driver = info->isdn_driver; + c.arg = info->isdn_channel; + isdn_command(&c); + spin_lock_irqsave(&dev->lock, flags); + isdn_free_channel(info->isdn_driver, info->isdn_channel, + ISDN_USAGE_FAX); + info->isdn_driver = -1; + info->isdn_channel = -1; + if (info->drv_index >= 0) { + dev->m_idx[info->drv_index] = -1; + info->drv_index = -1; + } + spin_unlock_irqrestore(&dev->lock, flags); } else { - isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c); + c.driver = info->isdn_driver; + c.arg = info->isdn_channel; + isdn_command(&c); } return 1; } @@ -766,7 +800,10 @@ isdn_tty_cmd_FCLASS2(char **p, modem_inf printk(KERN_DEBUG "isdn_tty: Fax FDR\n"); #endif f->code = ISDN_TTY_FAX_DR; - isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_FAXCMD; + isdn_command(&cmd); if (f->phase == ISDN_FAX_PHASE_B) { f->phase = ISDN_FAX_PHASE_C; } else if (f->phase == ISDN_FAX_PHASE_D) { @@ -818,7 +855,10 @@ isdn_tty_cmd_FCLASS2(char **p, modem_inf #endif if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) { f->code = ISDN_TTY_FAX_DT; - isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_FAXCMD; + isdn_command(&cmd); if (f->phase == ISDN_FAX_PHASE_D) { f->phase = ISDN_FAX_PHASE_C; isdn_tty_fax_modem_result(7, info); /* CONNECT */ @@ -873,7 +913,10 @@ isdn_tty_cmd_FCLASS2(char **p, modem_inf PARSE_ERROR1; f->fet = par; f->code = ISDN_TTY_FAX_ET; - isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_FAXCMD; + isdn_command(&cmd); #ifdef ISDN_TTY_FAX_STAT_DEBUG printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par); #endif @@ -1043,7 +1086,8 @@ isdn_tty_cmd_FCLASS2(char **p, modem_inf #ifdef ISDN_TTY_FAX_STAT_DEBUG printk(KERN_DEBUG "isdn_tty: FREV?\n"); #endif - sprintf(rs, "\r\nRev: 1.0"); + strcpy(rss, isdn_tty_fax_revision); + sprintf(rs, "\r\nRev: %s", isdn_getrev(rss)); isdn_tty_at_cout(rs, info); return 0; } diff -puN drivers/isdn/i4l/isdn_ttyfax.h~i4l drivers/isdn/i4l/isdn_ttyfax.h --- 25/drivers/isdn/i4l/isdn_ttyfax.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_ttyfax.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,6 @@ -/* Linux ISDN subsystem, tty_fax related functions +/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * header for Linux ISDN subsystem, tty_fax related functions (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) * Copyright 1999 by Ralf Spachmann (mel@melware.de) @@ -6,6 +8,7 @@ * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ diff -puN drivers/isdn/i4l/isdn_tty.h~i4l drivers/isdn/i4l/isdn_tty.h --- 25/drivers/isdn/i4l/isdn_tty.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_tty.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,10 +1,13 @@ -/* Linux ISDN subsystem, tty related functions +/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * header for Linux ISDN subsystem, tty related functions (linklevel). * * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ #include @@ -98,31 +101,22 @@ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2)) -extern int isdn_tty_init(void); -extern int isdn_tty_find_icall(struct isdn_slot *slot, setup_parm *setup); +extern void isdn_tty_modem_escape(void); +extern void isdn_tty_modem_ring(void); +extern void isdn_tty_carrier_timeout(void); +extern void isdn_tty_modem_xmit(void); +extern int isdn_tty_modem_init(void); +extern void isdn_tty_exit(void); +extern void isdn_tty_readmodem(void); +extern int isdn_tty_find_icall(int, int, setup_parm *); extern void isdn_tty_cleanup_xmit(modem_info *); -extern int isdn_tty_capi_facility(capi_msg *cm); +extern int isdn_tty_stat_callback(int, isdn_ctrl *); +extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); +extern int isdn_tty_capi_facility(capi_msg *cm); extern void isdn_tty_at_cout(char *, modem_info *); extern void isdn_tty_modem_hup(modem_info *, int); #ifdef CONFIG_ISDN_TTY_FAX -extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *); -extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *); +extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *); +extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *); extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *); #endif - -extern int isdn_tty_init(void); -extern void isdn_tty_exit(void); - -struct isdn_modem { - struct tty_driver *tty_modem; /* tty-device */ - modem_info info[ISDN_MAX_CHANNELS]; /* Private data */ -}; - -extern struct isdn_modem isdn_mdm; - -static inline void -isdn_tty_queue_tail(modem_info *info, struct sk_buff *skb, int len) -{ - __skb_queue_tail(&info->rpqueue, skb); - info->rcvcount += len; -} diff -puN drivers/isdn/i4l/isdn_v110.c~i4l drivers/isdn/i4l/isdn_v110.c --- 25/drivers/isdn/i4l/isdn_v110.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_v110.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,22 +1,27 @@ -/* Linux ISDN subsystem, V.110 +/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, V.110 related functions (linklevel). * * Copyright by Thomas Pfeiffer (pfeiffer@pds.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ #include #include #include #include +#include #include #include "isdn_v110.h" -#include "isdn_common.h" #undef ISDN_V110_DEBUG +char *isdn_v110_revision = "$Revision: 1.1.2.2 $"; + #define V110_38400 255 #define V110_19200 15 #define V110_9600 3 @@ -82,7 +87,7 @@ FlipBits(unsigned char c, int keylen) * structures and returns a pointer to these. */ static isdn_v110_stream * -do_isdn_v110_open(unsigned char key, int hdrlen, int maxsize) +isdn_v110_open(unsigned char key, int hdrlen, int maxsize) { int i; isdn_v110_stream *v; @@ -127,8 +132,8 @@ do_isdn_v110_open(unsigned char key, int } /* isdn_v110_close frees private V.110 data structures */ -static void -do_isdn_v110_close(isdn_v110_stream * v) +void +isdn_v110_close(isdn_v110_stream * v) { if (v == NULL) return; @@ -510,94 +515,101 @@ buffer_full: return nskb; } - -void -isdn_v110_open(struct isdn_slot *slot, struct isdn_v110 *iv110) -{ - isdn_v110_stream *v; - int hdrlen = isdn_slot_hdrlen(slot); - int maxsize = isdn_slot_maxbufsize(slot); - - atomic_inc(&iv110->v110use); - switch (iv110->v110emu) { - case ISDN_PROTO_L2_V11096: - iv110->v110 = do_isdn_v110_open(V110_9600, hdrlen, maxsize); - break; - case ISDN_PROTO_L2_V11019: - iv110->v110 = do_isdn_v110_open(V110_19200, hdrlen, maxsize); - break; - case ISDN_PROTO_L2_V11038: - iv110->v110 = do_isdn_v110_open(V110_38400, hdrlen, maxsize); - break; - } - if ((v = iv110->v110)) { - while (v->SyncInit) { - struct sk_buff *skb = isdn_v110_sync(v); - if (isdn_slot_write(slot, skb) <= 0) { - dev_kfree_skb(skb); - /* Unable to send, try later */ - break; - } - v->SyncInit--; - v->skbidle++; - } - } else - printk(KERN_WARNING "isdn_v110: Couldn't open stream\n"); - atomic_dec(&iv110->v110use); -} - -void -isdn_v110_close(struct isdn_slot *slot, struct isdn_v110 *iv110) -{ - while (1) { - atomic_inc(&iv110->v110use); - if (atomic_dec_and_test(&iv110->v110use)) { - do_isdn_v110_close(iv110->v110); - iv110->v110 = NULL; - break; - } - } -} - int -isdn_v110_bsent(struct isdn_slot *slot, struct isdn_v110 *iv110) +isdn_v110_stat_callback(int idx, isdn_ctrl * c) { - isdn_v110_stream *v = iv110->v110; - int i, ret; + isdn_v110_stream *v = NULL; + int i; + int ret; - /* Keep the send-queue of the driver filled - * with frames: - * If number of outstanding frames < 3, - * send down an Idle-Frame (or an Sync-Frame, if - * v->SyncInit != 0). - */ - atomic_inc(&iv110->v110use); - if (v->skbidle > 0) { - v->skbidle--; - ret = 1; - } else { - if (v->skbuser > 0) - v->skbuser--; - ret = 0; - } - for (i = v->skbuser + v->skbidle; i < 2; i++) { - struct sk_buff *skb; - if (v->SyncInit > 0) - skb = isdn_v110_sync(v); - else - skb = isdn_v110_idle(v); - if (skb) { - if (isdn_slot_write(slot, skb) <= 0) { - dev_kfree_skb(skb); - break; + if (idx < 0) + return 0; + switch (c->command) { + case ISDN_STAT_BSENT: + /* Keep the send-queue of the driver filled + * with frames: + * If number of outstanding frames < 3, + * send down an Idle-Frame (or an Sync-Frame, if + * v->SyncInit != 0). + */ + if (!(v = dev->v110[idx])) + return 0; + atomic_inc(&dev->v110use[idx]); + if (v->skbidle > 0) { + v->skbidle--; + ret = 1; } else { - if (v->SyncInit) - v->SyncInit--; - v->skbidle++; + if (v->skbuser > 0) + v->skbuser--; + ret = 0; + } + for (i = v->skbuser + v->skbidle; i < 2; i++) { + struct sk_buff *skb; + if (v->SyncInit > 0) + skb = isdn_v110_sync(v); + else + skb = isdn_v110_idle(v); + if (skb) { + if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) { + dev_kfree_skb(skb); + break; + } else { + if (v->SyncInit) + v->SyncInit--; + v->skbidle++; + } + } else + break; + } + atomic_dec(&dev->v110use[idx]); + return ret; + case ISDN_STAT_DHUP: + case ISDN_STAT_BHUP: + while (1) { + atomic_inc(&dev->v110use[idx]); + if (atomic_dec_and_test(&dev->v110use[idx])) { + isdn_v110_close(dev->v110[idx]); + dev->v110[idx] = NULL; + break; + } + mdelay(1); } - } else break; + case ISDN_STAT_BCONN: + if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) { + int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen; + int maxsize = dev->drv[c->driver]->interface->maxbufsize; + atomic_inc(&dev->v110use[idx]); + switch (dev->v110emu[idx]) { + case ISDN_PROTO_L2_V11096: + dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize); + break; + case ISDN_PROTO_L2_V11019: + dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize); + break; + case ISDN_PROTO_L2_V11038: + dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize); + break; + default:; + } + if ((v = dev->v110[idx])) { + while (v->SyncInit) { + struct sk_buff *skb = isdn_v110_sync(v); + if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) { + dev_kfree_skb(skb); + /* Unable to send, try later */ + break; + } + v->SyncInit--; + v->skbidle++; + } + } else + printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx); + atomic_dec(&dev->v110use[idx]); + } + break; + default: + return 0; } - atomic_dec(&iv110->v110use); - return ret; + return 0; } diff -puN drivers/isdn/i4l/isdn_v110.h~i4l drivers/isdn/i4l/isdn_v110.h --- 25/drivers/isdn/i4l/isdn_v110.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_v110.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,19 +1,16 @@ -/* Linux ISDN subsystem, V.110 related functions +/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, V.110 related functions (linklevel). * * Copyright by Thomas Pfeiffer (pfeiffer@pds.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ -#ifndef ISDN_V110_H -#define ISDN_V110_H - -struct isdn_v110 { - int v110emu; /* V.110 emulator-mode 0=none */ - atomic_t v110use; /* Usage-Semaphore for stream */ - isdn_v110_stream *v110; /* V.110 private data */ -}; +#ifndef _isdn_v110_h_ +#define _isdn_v110_h_ /* * isdn_v110_encode will take raw data and encode it using V.110 @@ -26,10 +23,7 @@ extern struct sk_buff *isdn_v110_encode( */ extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *); -extern void isdn_v110_open(struct isdn_slot *slot, struct isdn_v110 *iv110); - -extern void isdn_v110_close(struct isdn_slot *slot, struct isdn_v110 *iv110); - -extern int isdn_v110_bsent(struct isdn_slot *slot, struct isdn_v110 *iv110); +extern int isdn_v110_stat_callback(int, isdn_ctrl *); +extern void isdn_v110_close(isdn_v110_stream * v); #endif diff -puN drivers/isdn/i4l/isdn_x25iface.c~i4l drivers/isdn/i4l/isdn_x25iface.c --- 25/drivers/isdn/i4l/isdn_x25iface.c~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_x25iface.c 2004-02-09 22:19:20.000000000 -0800 @@ -1,10 +1,10 @@ -/* * Linux ISDN subsystem, X.25 related functions +/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * Linux ISDN subsystem, X.25 related functions * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. - */ - -/* + * * stuff needed to support the Linux X.25 PLP code on top of devices that * can provide a lab_b service using the concap_proto mechanism. * This module supports a network interface wich provides lapb_sematics @@ -17,6 +17,7 @@ * */ +/* #include */ #include #include #include @@ -63,7 +64,7 @@ static struct concap_proto_ops ix25_pops /* error message helper function */ static void illegal_state_warn( unsigned state, unsigned char firstbyte) { - printk( KERN_WARNING "isdn_x25iface: firstbyte %x invalid in" + printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in" "current state %d\n",firstbyte, state ); } @@ -72,7 +73,7 @@ static int pdata_is_bad( ix25_pdata_t * if( pda && pda -> magic == ISDN_X25IFACE_MAGIC ) return 0; printk( KERN_WARNING - "isdn_x25iface_xxx: invalid pointer to proto data\n" ); + "isdn_x25iface_xxx: illegal pointer to proto data\n" ); return 1; } @@ -87,6 +88,7 @@ struct concap_proto * isdn_x25iface_prot tmp -> state = WAN_UNCONFIGURED; /* private data space used to hold the concap_proto data. Only to be accessed via the returned pointer */ + spin_lock_init(&tmp->priv.lock); tmp -> priv.dops = NULL; tmp -> priv.net_dev = NULL; tmp -> priv.pops = &ix25_pops; @@ -111,9 +113,7 @@ int isdn_x25iface_proto_close(struct con return -1; } IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) ); - save_flags(flags); - cli(); /* avoid races with incoming events calling pops methods while - cprot members are inconsistent */ + spin_lock_irqsave(&cprot->lock, flags); cprot -> dops = NULL; cprot -> net_dev = NULL; tmp = cprot -> proto_data; @@ -122,8 +122,7 @@ int isdn_x25iface_proto_close(struct con } else { tmp -> state = WAN_UNCONFIGURED; } - restore_flags(flags); - + spin_unlock_irqrestore(&cprot->lock, flags); return ret; } @@ -176,14 +175,12 @@ int isdn_x25iface_proto_restart(struct c isdn_x25iface_proto_close(cprot); return -1; } - save_flags(flags); - cli(); /* avoid races with incoming events calling pops methods while - cprot members are inconsistent */ + spin_lock_irqsave(&cprot->lock, flags); cprot -> net_dev = ndev; cprot -> pops = &ix25_pops; cprot -> dops = dops; pda -> state = WAN_DISCONNECTED; - restore_flags(flags); + spin_unlock_irqrestore(&cprot->lock, flags); return 0; } @@ -222,8 +219,6 @@ int isdn_x25iface_connect_ind(struct con printk(KERN_WARNING "isdn_x25iface_connect_ind while unconfigured %s\n" , MY_DEVNAME(cprot->net_dev) ); - if (skb) - dev_kfree_skb(skb); return -1; } *state_p = WAN_CONNECTED; @@ -334,7 +329,7 @@ int isdn_x25iface_xmit(struct concap_pro " options not yet supported\n"); break; default: - printk(KERN_WARNING "isdn_x25iface_xmit: frame with invalid" + printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal" " first byte %x ignored:\n", firstbyte); } dev_kfree_skb(skb); diff -puN drivers/isdn/i4l/isdn_x25iface.h~i4l drivers/isdn/i4l/isdn_x25iface.h --- 25/drivers/isdn/i4l/isdn_x25iface.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/isdn_x25iface.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,16 +1,17 @@ -/* Linux ISDN subsystem, x.25 related functions +/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ + * + * header for Linux ISDN subsystem, x.25 related functions * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. + * */ #ifndef _LINUX_ISDN_X25IFACE_H #define _LINUX_ISDN_X25IFACE_H #define ISDN_X25IFACE_MAGIC 0x1e75a2b9 - -#undef DEBUG_ISDN_X25 - +/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */ #ifdef DEBUG_ISDN_X25 # define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args) #else @@ -25,6 +26,8 @@ extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt; extern struct concap_proto * isdn_x25iface_proto_new(void); + + #endif diff -puN drivers/isdn/i4l/Kconfig~i4l drivers/isdn/i4l/Kconfig --- 25/drivers/isdn/i4l/Kconfig~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -2,25 +2,6 @@ # Old ISDN4Linux config # -config ISDN_NET_SIMPLE - bool ' Support raw-IP and other simple protocols' - depends on INET - help - This options enables 'raw IP over ISDN', 'ethernet over ISDN', - 'raw IP with UI header' and 'IP + type field' encapsulations. - - If you never heard of any of those, you probably want to say N. - -config ISDN_NET_CISCO - bool ' Support CISCO router protocols' - depends on INET - help - This options enables 'CISCO HDLC' encapsulation with - optional support for CISCO keep-alive frames. - - Unless you want to connect to a Cisco Router in HDLC mode, - you probably want to say N. - config ISDN_PPP bool "Support synchronous PPP" depends on INET @@ -85,7 +66,7 @@ config ISDN_TTY_FAX config ISDN_X25 bool "X.25 PLP on top of ISDN" - depends on X25 && BROKEN + depends on X25 help This feature provides the X.25 protocol over ISDN connections. See for more information @@ -124,3 +105,27 @@ config ISDN_DIVERSION Please read the file . endmenu + +comment "ISDN4Linux hardware drivers" + depends on NET && ISDN && ISDN_I4L + +source "drivers/isdn/hisax/Kconfig" + + +menu "Active cards" + depends on NET && ISDN && ISDN_I4L!=n + +source "drivers/isdn/icn/Kconfig" + +source "drivers/isdn/pcbit/Kconfig" + +source "drivers/isdn/sc/Kconfig" + +source "drivers/isdn/act2000/Kconfig" + +source "drivers/isdn/tpam/Kconfig" + +source "drivers/isdn/hysdn/Kconfig" + +endmenu + diff -puN drivers/isdn/i4l/Makefile~i4l drivers/isdn/i4l/Makefile --- 25/drivers/isdn/i4l/Makefile~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/i4l/Makefile 2004-02-09 22:19:20.000000000 -0800 @@ -2,18 +2,17 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN) += isdn.o +obj-$(CONFIG_ISDN_I4L) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o # Multipart objects. -isdn-y := isdn_net_lib.o isdn_fsm.o isdn_tty.o \ - isdn_v110.o isdn_common.o -isdn-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o -isdn-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o -isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o -isdn-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o -isdn-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o +isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o + +# Optional parts of multipart objects. + +isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o -isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o +isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o + diff -puN drivers/isdn/icn/Kconfig~i4l drivers/isdn/icn/Kconfig --- 25/drivers/isdn/icn/Kconfig~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/icn/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # config ISDN_DRV_ICN tristate "ICN 2B and 4B support" - depends on ISDN && ISA + depends on ISDN_I4L && ISA help This enables support for two kinds of ISDN-cards made by a German company called ICN. 2B is the standard version for a single ISDN diff -puN drivers/isdn/Kconfig~i4l drivers/isdn/Kconfig --- 25/drivers/isdn/Kconfig~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -4,8 +4,8 @@ menu "ISDN subsystem" -config ISDN_BOOL - bool "ISDN support" +config ISDN + tristate "ISDN support" depends on NET ---help--- ISDN ("Integrated Services Digital Networks", called RNIS in France) @@ -22,9 +22,9 @@ config ISDN_BOOL menu "Old ISDN4Linux" - depends on NET && ISDN_BOOL && BROKEN_ON_SMP + depends on NET && ISDN -config ISDN +config ISDN_I4L tristate "Old ISDN4Linux (obsolete)" ---help--- This driver allows you to use an ISDN-card for networking @@ -41,18 +41,18 @@ config ISDN Therefore the old ISDN4Linux layer is becoming obsolete. It is still usable, though, if you select this option. -if ISDN +if ISDN_I4L source "drivers/isdn/i4l/Kconfig" endif endmenu comment "CAPI subsystem" - depends on NET && ISDN_BOOL + depends on NET && ISDN config ISDN_CAPI tristate "CAPI2.0 support" - depends on ISDN_BOOL + depends on ISDN help This provides the CAPI (Common ISDN Application Programming Interface, a standard making it easy for programs to access ISDN diff -puN drivers/isdn/Makefile~i4l drivers/isdn/Makefile --- 25/drivers/isdn/Makefile~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/Makefile 2004-02-09 22:19:20.000000000 -0800 @@ -2,7 +2,7 @@ # Object files in subdirectories -obj-$(CONFIG_ISDN) += i4l/ +obj-$(CONFIG_ISDN_I4L) += i4l/ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_ISDN_CAPI) += hardware/ obj-$(CONFIG_ISDN_DIVERSION) += divert/ diff -puN drivers/isdn/pcbit/Kconfig~i4l drivers/isdn/pcbit/Kconfig --- 25/drivers/isdn/pcbit/Kconfig~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/pcbit/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # config ISDN_DRV_PCBIT tristate "PCBIT-D support" - depends on ISDN && ISA + depends on ISDN_I4L && ISA help This enables support for the PCBIT ISDN-card. This card is manufactured in Portugal by Octal. For running this card, diff -puN drivers/isdn/sc/Kconfig~i4l drivers/isdn/sc/Kconfig --- 25/drivers/isdn/sc/Kconfig~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/sc/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # config ISDN_DRV_SC tristate "Spellcaster support" - depends on ISDN && ISA + depends on ISDN_I4L && ISA help This enables support for the Spellcaster BRI ISDN boards. This driver currently builds only in a modularized version. diff -puN drivers/isdn/tpam/Kconfig~i4l drivers/isdn/tpam/Kconfig --- 25/drivers/isdn/tpam/Kconfig~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/isdn/tpam/Kconfig 2004-02-09 22:19:20.000000000 -0800 @@ -3,7 +3,7 @@ # config ISDN_DRV_TPAM tristate "Auvertech TurboPAM support (EXPERIMENTAL)" - depends on EXPERIMENTAL && ISDN && PCI + depends on EXPERIMENTAL && ISDN_I4L && PCI help This enables support for the Auvertech TurboPAM ISDN-card. For running this card, additional firmware is necessary, which has diff -puN drivers/Makefile~i4l drivers/Makefile --- 25/drivers/Makefile~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/drivers/Makefile 2004-02-09 22:19:20.000000000 -0800 @@ -45,7 +45,7 @@ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ -obj-$(CONFIG_ISDN_BOOL) += isdn/ +obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ diff -puN include/linux/concap.h~i4l include/linux/concap.h --- 25/include/linux/concap.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/include/linux/concap.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: concap.h,v 1.2.8.1 2001/09/23 22:25:05 kai Exp $ +/* $Id: concap.h,v 1.3.2.2 2004/01/12 23:08:35 keil Exp $ * * Copyright 1997 by Henner Eisen * @@ -31,6 +31,7 @@ struct concap_proto{ struct net_device *net_dev; /* net device using our service */ struct concap_device_ops *dops; /* callbacks provided by device */ struct concap_proto_ops *pops; /* callbacks provided by us */ + spinlock_t lock; int flags; void *proto_data; /* protocol specific private data, to be accessed via *pops methods only*/ diff -puN include/linux/isdn/capilli.h~i4l include/linux/isdn/capilli.h --- 25/include/linux/isdn/capilli.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/include/linux/isdn/capilli.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: capilli.h,v 1.4.8.1 2001/09/23 22:24:33 kai Exp $ +/* $Id: capilli.h,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ * * Kernel CAPI 2.0 Driver Interface for Linux * @@ -85,6 +85,22 @@ void capi_ctr_resume_output(struct capi_ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb); // --------------------------------------------------------------------------- +// needed for AVM capi drivers + +struct capi_driver { + char name[32]; /* driver name */ + char revision[32]; + + int (*add_card)(struct capi_driver *driver, capicardparams *data); + + /* management information for kcapi */ + struct list_head list; +}; + +void register_capi_driver(struct capi_driver *driver); +void unregister_capi_driver(struct capi_driver *driver); + +// --------------------------------------------------------------------------- // library functions for use by hardware controller drivers void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize); diff -puN -L include/linux/isdn/fsm.h include/linux/isdn/fsm.h~i4l /dev/null --- 25/include/linux/isdn/fsm.h +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,58 +0,0 @@ -/* Linux ISDN subsystem, finite state machine - * - * Author Karsten Keil - * Copyright by Karsten Keil - * 2001-2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef __ISDN_FSM_H__ -#define __ISDN_FSM_H__ - -#include -#include - -struct fsm_inst; - -typedef int (*fsm_fn)(struct fsm_inst *, int, void *); - -struct fsm { - fsm_fn *jumpmatrix; - int st_cnt, ev_cnt, fn_cnt; - char **st_str, **ev_str; - struct fsm_node *fn_tbl; -}; - -struct fsm_inst { - struct fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct fsm_inst *, char *, ...); -}; - -struct fsm_node { - int st, ev; - fsm_fn fn; -}; - -struct fsm_timer { - struct fsm_inst *fi; - struct timer_list tl; - int ev; - void *arg; -}; - -int fsm_new(struct fsm *fsm); -void fsm_free(struct fsm *fsm); -int fsm_event(struct fsm_inst *fi, int event, void *arg); -void fsm_change_state(struct fsm_inst *fi, int newstate); -void fsm_init_timer(struct fsm_inst *fi, struct fsm_timer *ft); -int fsm_add_timer(struct fsm_timer *ft, int timeout, int event); -void fsm_mod_timer(struct fsm_timer *ft, int timeout, int event); -void fsm_del_timer(struct fsm_timer *ft); - -#endif diff -puN include/linux/isdn.h~i4l include/linux/isdn.h --- 25/include/linux/isdn.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/include/linux/isdn.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,9 +1,10 @@ -/* Linux ISDN subsystem, main header +/* $Id: isdn.h,v 1.125.2.3 2004/02/10 01:07:14 keil Exp $ + * + * Main header for the Linux ISDN subsystem (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. @@ -14,7 +15,6 @@ #define __ISDN_H__ #include -#include #ifdef CONFIG_COBALT_MICRO_SERVER /* Save memory */ @@ -75,7 +75,7 @@ #define ISDN_NET_ENCAP_UIHDLC 5 #define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */ #define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt*/ -#define ISDN_NET_ENCAP_NR 8 +#define ISDN_NET_ENCAP_MAX_ENCAP ISDN_NET_ENCAP_X25IFACE /* Facility which currently uses an ISDN-channel */ #define ISDN_USAGE_NONE 0 @@ -94,48 +94,48 @@ #define ISDN_CMSGLEN 50 /* Length of CONNECT-Message to add for Modem */ #define ISDN_MSNLEN 32 -#define NET_DV 0x06 /* Data version for isdn_net_ioctl_cfg */ -#define TTY_DV 0x06 /* Data version for iprofd etc. */ +#define NET_DV 0x06 /* Data version for isdn_net_ioctl_cfg */ +#define TTY_DV 0x06 /* Data version for iprofd etc. */ -#define INF_DV 0x01 /* Data version for /dev/isdninfo */ +#define INF_DV 0x01 /* Data version for /dev/isdninfo */ typedef struct { - char drvid[25]; - unsigned long arg; + char drvid[25]; + unsigned long arg; } isdn_ioctl_struct; typedef struct { - char name[10]; - char phone[ISDN_MSNLEN]; - int outgoing; + char name[10]; + char phone[ISDN_MSNLEN]; + int outgoing; } isdn_net_ioctl_phone; typedef struct { - char name[10]; /* Name of interface */ - char master[10]; /* Name of Master for Bundling */ - char slave[10]; /* Name of Slave for Bundling */ - char eaz[256]; /* EAZ/MSN */ - char drvid[25]; /* DriverId for Bindings */ - int onhtime; /* Hangup-Timeout */ - int charge; /* Charge-Units */ - int l2_proto; /* Layer-2 protocol */ - int l3_proto; /* Layer-3 protocol */ - int p_encap; /* Encapsulation */ - int exclusive; /* Channel, if bound exclusive */ - int dialmax; /* Dial Retry-Counter */ - int slavedelay; /* Delay until slave starts up */ - int cbdelay; /* Delay before Callback */ - int chargehup; /* Flag: Charge-Hangup */ - int ihup; /* Flag: Hangup-Timeout on incoming line */ - int secure; /* Flag: Secure */ - int callback; /* Flag: Callback */ - int cbhup; /* Flag: Reject Call before Callback */ - int pppbind; /* ippp device for bindings */ - int chargeint; /* Use fixed charge interval length */ - int triggercps; /* BogoCPS needed for triggering slave */ - int dialtimeout; /* Dial-Timeout */ - int dialwait; /* Time to wait after failed dial */ - int dialmode; /* Flag: off / on / auto */ + char name[10]; /* Name of interface */ + char master[10]; /* Name of Master for Bundling */ + char slave[10]; /* Name of Slave for Bundling */ + char eaz[256]; /* EAZ/MSN */ + char drvid[25]; /* DriverId for Bindings */ + int onhtime; /* Hangup-Timeout */ + int charge; /* Charge-Units */ + int l2_proto; /* Layer-2 protocol */ + int l3_proto; /* Layer-3 protocol */ + int p_encap; /* Encapsulation */ + int exclusive; /* Channel, if bound exclusive */ + int dialmax; /* Dial Retry-Counter */ + int slavedelay; /* Delay until slave starts up */ + int cbdelay; /* Delay before Callback */ + int chargehup; /* Flag: Charge-Hangup */ + int ihup; /* Flag: Hangup-Timeout on incoming line */ + int secure; /* Flag: Secure */ + int callback; /* Flag: Callback */ + int cbhup; /* Flag: Reject Call before Callback */ + int pppbind; /* ippp device for bindings */ + int chargeint; /* Use fixed charge interval length */ + int triggercps; /* BogoCPS needed for triggering slave */ + int dialtimeout; /* Dial-Timeout */ + int dialwait; /* Time to wait after failed dial */ + int dialmode; /* Flag: off / on / auto */ } isdn_net_ioctl_cfg; #define ISDN_NET_DIALMODE_MASK 0xC0 /* bits for status */ @@ -150,6 +150,7 @@ typedef struct { #include #include #include +#include #include #include #include @@ -178,6 +179,8 @@ typedef struct { * the correspondent code in isdn.c */ +#define ISDN_MINOR_B 0 +#define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1) #define ISDN_MINOR_CTRL 64 #define ISDN_MINOR_CTRLMAX (64 + (ISDN_MAX_CHANNELS-1)) #define ISDN_MINOR_PPP 128 @@ -230,9 +233,177 @@ typedef struct { #define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \ ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) ) +/* Timer-delays and scheduling-flags */ +#define ISDN_TIMER_RES 4 /* Main Timer-Resolution */ +#define ISDN_TIMER_02SEC (HZ/ISDN_TIMER_RES/5) /* Slow-Timer1 .2 sec */ +#define ISDN_TIMER_1SEC (HZ/ISDN_TIMER_RES) /* Slow-Timer2 1 sec */ +#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */ +#define ISDN_TIMER_KEEPINT 10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */ +#define ISDN_TIMER_MODEMREAD 1 +#define ISDN_TIMER_MODEMPLUS 2 +#define ISDN_TIMER_MODEMRING 4 +#define ISDN_TIMER_MODEMXMIT 8 +#define ISDN_TIMER_NETDIAL 16 +#define ISDN_TIMER_NETHANGUP 32 +#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */ +#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \ + ISDN_TIMER_MODEMXMIT) +#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \ + ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER) + +/* Timeout-Values for isdn_net_dial() */ +#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) +#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) +#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) + /* GLOBAL_FLAGS */ #define ISDN_GLOBAL_STOPPED 1 +/*=================== Start of ip-over-ISDN stuff =========================*/ + +/* Feature- and status-flags for a net-interface */ +#define ISDN_NET_CONNECTED 0x01 /* Bound to ISDN-Channel */ +#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */ +#define ISDN_NET_CALLBACK 0x04 /* activate callback */ +#define ISDN_NET_CBHUP 0x08 /* hangup before callback */ +#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */ + +#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */ + +/* Phone-list-element */ +typedef struct { + void *next; + char num[ISDN_MSNLEN]; +} isdn_net_phone; + +/* + Principles when extending structures for generic encapsulation protocol + ("concap") support: + - Stuff which is hardware specific (here i4l-specific) goes in + the netdev -> local structure (here: isdn_net_local) + - Stuff which is encapsulation protocol specific goes in the structure + which holds the linux device structure (here: isdn_net_device) +*/ + +/* Local interface-data */ +typedef struct isdn_net_local_s { + ulong magic; + char name[10]; /* Name of device */ + struct net_device_stats stats; /* Ethernet Statistics */ + int isdn_device; /* Index to isdn-device */ + int isdn_channel; /* Index to isdn-channel */ + int ppp_slot; /* PPPD device slot number */ + int pre_device; /* Preselected isdn-device */ + int pre_channel; /* Preselected isdn-channel */ + int exclusive; /* If non-zero idx to reserved chan.*/ + int flags; /* Connection-flags */ + int dialretry; /* Counter for Dialout-retries */ + int dialmax; /* Max. Number of Dial-retries */ + int cbdelay; /* Delay before Callback starts */ + int dtimer; /* Timeout-counter for dialing */ + char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */ + u_char cbhup; /* Flag: Reject Call before Callback*/ + u_char dialstate; /* State for dialing */ + u_char p_encap; /* Packet encapsulation */ + /* 0 = Ethernet over ISDN */ + /* 1 = RAW-IP */ + /* 2 = IP with type field */ + u_char l2_proto; /* Layer-2-protocol */ + /* See ISDN_PROTO_L2..-constants in */ + /* isdnif.h */ + /* 0 = X75/LAPB with I-Frames */ + /* 1 = X75/LAPB with UI-Frames */ + /* 2 = X75/LAPB with BUI-Frames */ + /* 3 = HDLC */ + u_char l3_proto; /* Layer-3-protocol */ + /* See ISDN_PROTO_L3..-constants in */ + /* isdnif.h */ + /* 0 = Transparent */ + int huptimer; /* Timeout-counter for auto-hangup */ + int charge; /* Counter for charging units */ + ulong chargetime; /* Timer for Charging info */ + int hupflags; /* Flags for charge-unit-hangup: */ + /* bit0: chargeint is invalid */ + /* bit1: Getting charge-interval */ + /* bit2: Do charge-unit-hangup */ + /* bit3: Do hangup even on incoming */ + int outgoing; /* Flag: outgoing call */ + int onhtime; /* Time to keep link up */ + int chargeint; /* Interval between charge-infos */ + int onum; /* Flag: at least 1 outgoing number */ + int cps; /* current speed of this interface */ + int transcount; /* byte-counter for cps-calculation */ + int sqfull; /* Flag: netdev-queue overloaded */ + ulong sqfull_stamp; /* Start-Time of overload */ + ulong slavedelay; /* Dynamic bundling delaytime */ + int triggercps; /* BogoCPS needed for trigger slave */ + isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ + /* phone[0] = Incoming Numbers */ + /* phone[1] = Outgoing Numbers */ + isdn_net_phone *dial; /* Pointer to dialed number */ + struct net_device *master; /* Ptr to Master device for slaves */ + struct net_device *slave; /* Ptr to Slave device for masters */ + struct isdn_net_local_s *next; /* Ptr to next link in bundle */ + struct isdn_net_local_s *last; /* Ptr to last link in bundle */ + struct isdn_net_dev_s *netdev; /* Ptr to netdev */ + struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ + /* be transmitted asap */ + atomic_t frame_cnt; /* number of frames currently */ + /* queued in HL driver */ + /* Ptr to orig. hard_header_cache */ + spinlock_t xmit_lock; /* used to protect the xmit path of */ + /* a particular channel (including */ + /* the frame_cnt */ + + int (*org_hhc)( + struct neighbour *neigh, + struct hh_cache *hh); + /* Ptr to orig. header_cache_update */ + void (*org_hcu)(struct hh_cache *, + struct net_device *, + unsigned char *); + int pppbind; /* ippp device for bindings */ + int dialtimeout; /* How long shall we try on dialing? (jiffies) */ + int dialwait; /* How long shall we wait after failed attempt? (jiffies) */ + ulong dialstarted; /* jiffies of first dialing-attempt */ + ulong dialwait_timer; /* jiffies of earliest next dialing-attempt */ + int huptimeout; /* How long will the connection be up? (seconds) */ +#ifdef CONFIG_ISDN_X25 + struct concap_device_ops *dops; /* callbacks used by encapsulator */ +#endif + /* use an own struct for that in later versions */ + ulong cisco_myseq; /* Local keepalive seq. for Cisco */ + ulong cisco_mineseen; /* returned keepalive seq. from remote */ + ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */ + int cisco_keepalive_period; /* keepalive period */ + ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */ + char cisco_line_state; /* state of line according to keepalive packets */ + char cisco_debserint; /* debugging flag of cisco hdlc with slarp */ + struct timer_list cisco_timer; + struct work_struct tqueue; +} isdn_net_local; + +/* the interface itself */ +typedef struct isdn_net_dev_s { + isdn_net_local *local; + isdn_net_local *queue; /* circular list of all bundled + channels, which are currently + online */ + spinlock_t queue_lock; /* lock to protect queue */ + void *next; /* Pointer to next isdn-interface */ + struct net_device dev; /* interface to upper levels */ +#ifdef CONFIG_ISDN_PPP + ippp_bundle * pb; /* pointer to the common bundle structure + * with the per-bundle data */ +#endif +#ifdef CONFIG_ISDN_X25 + struct concap_proto *cprot; /* connection oriented encapsulation protocol */ +#endif + +} isdn_net_dev; + +/*===================== End of ip-over-ISDN stuff ===========================*/ + /*======================= Start of ISDN-tty stuff ===========================*/ #define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */ @@ -249,21 +420,22 @@ typedef struct { #define ISDN_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */ #define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */ #define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */ +#define ISDN_SERIAL_TYPE_NORMAL 1 +#define ISDN_SERIAL_TYPE_CALLOUT 2 #ifdef CONFIG_ISDN_AUDIO /* For using sk_buffs with audio we need some private variables * within each sk_buff. For this purpose, we declare a struct here, - * and put it always at skb->head. A few macros help accessing the - * variables. Of course, we need to check skb_headroom prior to - * any access. + * and put it always at the private skb->cb data array. A few macros help + * accessing the variables. */ -typedef struct _isdnaudio_header { +typedef struct _isdn_audio_data { unsigned short dle_count; unsigned char lock; -} isdnaudio_header; +} isdn_audio_data_t; -#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdnaudio_header*)skb->head)->dle_count) -#define ISDN_AUDIO_SKB_LOCK(skb) (((isdnaudio_header*)skb->head)->lock) +#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_data_t *)&skb->cb[0])->dle_count) +#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_data_t *)&skb->cb[0])->lock) #endif /* Private data of AT-command-interpreter */ @@ -282,7 +454,8 @@ typedef struct atemu { #endif int mdmcmdl; /* Length of Modem-Commandbuffer */ int pluscount; /* Counter for +++ sequence */ - unsigned long lastplus; /* Timestamp of last + */ + u_long lastplus; /* Timestamp of last + */ + int carrierwait; /* Seconds of carrier waiting */ char mdmcmd[255]; /* Modem-Commandbuffer */ unsigned int charge; /* Charge units of current connection */ } atemu; @@ -299,13 +472,15 @@ typedef struct modem_info { int line; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ int online; /* 1 = B-Channel is up, drop data */ /* 2 = B-Channel is up, deliver d.*/ int dialing; /* Dial in progress or ATA */ int rcvsched; /* Receive needs schedule */ - struct isdn_slot *isdn_slot; /* Ptr to isdn-driver/channel */ - struct sk_buff_head rpqueue; /* Queue of recv'd packets */ - int rcvcount; /* Byte-counters for B rx */ + int isdn_driver; /* Index to isdn-driver */ + int isdn_channel; /* Index to isdn-channel */ + int drv_index; /* Index to dev->usage */ int ncarrier; /* Flag: schedule NO CARRIER */ unsigned char last_cause[8]; /* Last cause message */ unsigned char last_num[ISDN_MSNLEN]; @@ -322,7 +497,6 @@ typedef struct modem_info { struct sk_buff_head xmit_queue; /* transmit queue */ atomic_t xmit_lock; /* Semaphore for isdn_tty_write */ #ifdef CONFIG_ISDN_AUDIO - unsigned long DLEflag; /* Insert DLE at next read */ int vonline; /* Voice-channel status */ /* Bit 0 = recording */ /* Bit 1 = playback */ @@ -339,16 +513,25 @@ typedef struct modem_info { #endif struct tty_struct *tty; /* Pointer to corresponding tty */ atemu emu; /* AT-emulator data */ - struct timer_list escape_timer; /* to recognize +++ escape */ - struct timer_list ring_timer; /* for writing 'RING' responses */ - struct timer_list connect_timer; /* waiting for CONNECT */ - struct timer_list read_timer; /* read incoming data */ + struct termios normal_termios; /* For saving termios structs */ + struct termios callout_termios; wait_queue_head_t open_wait, close_wait; struct semaphore write_sem; + spinlock_t readlock; } modem_info; #define ISDN_MODEM_WINSIZE 8 +/* Description of one ISDN-tty */ +typedef struct _isdn_modem { + int refcount; /* Number of opens */ + struct tty_driver *tty_modem; /* tty-device */ + struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */ + struct termios *modem_termios[ISDN_MAX_CHANNELS]; + struct termios *modem_termios_locked[ISDN_MAX_CHANNELS]; + modem_info info[ISDN_MAX_CHANNELS]; /* Private data */ +} isdn_modem_t; + /*======================= End of ISDN-tty stuff ============================*/ /*======================== Start of V.110 stuff ============================*/ @@ -383,23 +566,72 @@ typedef struct { char *private; } infostruct; +#define DRV_FLAG_RUNNING 1 +#define DRV_FLAG_REJBUS 2 +#define DRV_FLAG_LOADED 4 + +/* Description of hardware-level-driver */ +typedef struct _isdn_driver { + ulong online; /* Channel-Online flags */ + ulong flags; /* Misc driver Flags */ + int locks; /* Number of locks for this driver */ + int channels; /* Number of channels */ + wait_queue_head_t st_waitq; /* Wait-Queue for status-read's */ + int maxbufsize; /* Maximum Buffersize supported */ + unsigned long pktcount; /* Until now: unused */ + int stavail; /* Chars avail on Status-device */ + isdn_if *interface; /* Interface to driver */ + int *rcverr; /* Error-counters for B-Ch.-receive */ + int *rcvcount; /* Byte-counters for B-Ch.-receive */ +#ifdef CONFIG_ISDN_AUDIO + unsigned long DLEflag; /* Flags: Insert DLE at next read */ +#endif + struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */ + wait_queue_head_t *rcv_waitq; /* Wait-Queues for B-Channel-Reads */ + wait_queue_head_t *snd_waitq; /* Wait-Queue for B-Channel-Send's */ + char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */ +} isdn_driver_t; + /* Main driver-data */ -typedef struct _isdn_dev_t { - unsigned short flags; /* Bitmapped Flags: */ - int channels; /* Current number of channels */ - int net_verbose; /* Verbose-Flag */ - int modempoll; /* Flag: tty-read active */ - int tflags; /* Timer-Flags: */ - /* see ISDN_TIMER_..defines */ - int global_flags; - infostruct *infochain; /* List of open info-devs. */ - wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */ - struct task_struct *profd; /* For iprofd */ - struct semaphore sem; /* serialize list access*/ - unsigned long global_features; -} isdn_dev_t; +typedef struct isdn_devt { + struct module *owner; + spinlock_t lock; + unsigned short flags; /* Bitmapped Flags: */ + int drivers; /* Current number of drivers */ + int channels; /* Current number of channels */ + int net_verbose; /* Verbose-Flag */ + int modempoll; /* Flag: tty-read active */ + spinlock_t timerlock; + int tflags; /* Timer-Flags: */ + /* see ISDN_TIMER_..defines */ + int global_flags; + infostruct *infochain; /* List of open info-devs. */ + wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */ + struct timer_list timer; /* Misc.-function Timer */ + int chanmap[ISDN_MAX_CHANNELS]; /* Map minor->device-channel */ + int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */ + int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */ + char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN]; + /* Remote number of active ch.*/ + int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */ + isdn_driver_t *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */ + isdn_net_dev *netdev; /* Linked list of net-if's */ + char drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID */ + struct task_struct *profd; /* For iprofd */ + isdn_modem_t mdm; /* tty-driver-data */ + isdn_net_dev *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers */ + isdn_net_dev *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers */ + ulong ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes */ + ulong obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes */ + int v110emu[ISDN_MAX_CHANNELS]; /* V.110 emulator-mode 0=none */ + atomic_t v110use[ISDN_MAX_CHANNELS]; /* Usage-Semaphore for stream */ + isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */ + struct semaphore sem; /* serialize list access*/ + unsigned long global_features; +} isdn_dev; + +extern isdn_dev *dev; -extern isdn_dev_t *get_isdn_dev(void); #endif /* __KERNEL__ */ diff -puN include/linux/isdnif.h~i4l include/linux/isdnif.h --- 25/include/linux/isdnif.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/include/linux/isdnif.h 2004-02-09 22:19:20.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.37.6.6 2001/09/23 22:25:05 kai Exp $ +/* $Id: isdnif.h,v 1.43.2.2 2004/01/12 23:08:35 keil Exp $ * * Linux ISDN subsystem * Definition of the interface between the subsystem and its low-level drivers. @@ -166,8 +166,17 @@ typedef struct #define ISDN_CMD_HANGUP 4 /* Hangup */ #define ISDN_CMD_CLREAZ 5 /* Clear EAZ(s) of channel */ #define ISDN_CMD_SETEAZ 6 /* Set EAZ(s) of channel */ +#define ISDN_CMD_GETEAZ 7 /* Get EAZ(s) of channel */ +#define ISDN_CMD_SETSIL 8 /* Set Service-Indicator-List of channel */ +#define ISDN_CMD_GETSIL 9 /* Get Service-Indicator-List of channel */ #define ISDN_CMD_SETL2 10 /* Set B-Chan. Layer2-Parameter */ +#define ISDN_CMD_GETL2 11 /* Get B-Chan. Layer2-Parameter */ #define ISDN_CMD_SETL3 12 /* Set B-Chan. Layer3-Parameter */ +#define ISDN_CMD_GETL3 13 /* Get B-Chan. Layer3-Parameter */ +// #define ISDN_CMD_LOCK 14 /* Signal usage by upper levels */ +// #define ISDN_CMD_UNLOCK 15 /* Release usage-lock */ +#define ISDN_CMD_SUSPEND 16 /* Suspend connection */ +#define ISDN_CMD_RESUME 17 /* Resume connection */ #define ISDN_CMD_PROCEED 18 /* Proceed with call establishment */ #define ISDN_CMD_ALERT 19 /* Alert after Proceeding */ #define ISDN_CMD_REDIR 20 /* Redir a incoming call */ @@ -193,12 +202,14 @@ typedef struct #define ISDN_STAT_LOAD 265 /* Signal new lowlevel-driver is loaded */ #define ISDN_STAT_UNLOAD 266 /* Signal unload of lowlevel-driver */ #define ISDN_STAT_BSENT 267 /* Signal packet sent */ +#define ISDN_STAT_NODCH 268 /* Signal no D-Channel */ #define ISDN_STAT_ADDCH 269 /* Add more Channels */ #define ISDN_STAT_CAUSE 270 /* Cause-Message */ #define ISDN_STAT_ICALLW 271 /* Incoming call without B-chan waiting */ #define ISDN_STAT_REDIR 272 /* Redir result */ #define ISDN_STAT_PROT 273 /* protocol IO specific callback */ #define ISDN_STAT_DISPLAY 274 /* deliver a received display message */ +#define ISDN_STAT_L1ERR 275 /* Signal Layer-1 Error */ #define ISDN_STAT_FAXIND 276 /* FAX indications from HL-driver */ #define ISDN_STAT_AUDIO 277 /* DTMF, DSP indications */ #define ISDN_STAT_DISCH 278 /* Disable/Enable channel usage */ @@ -210,6 +221,12 @@ typedef struct #define ISDN_AUDIO_DTMF 1 /* Rx/Tx DTMF */ /* + * Values for errcode field + */ +#define ISDN_STAT_L1ERR_SEND 1 +#define ISDN_STAT_L1ERR_RECV 2 + +/* * Values for feature-field of interface-struct. */ /* Layer 2 */ @@ -258,6 +275,7 @@ typedef struct setup_parm { } setup_parm; +#ifdef CONFIG_ISDN_TTY_FAX /* T.30 Fax G3 */ #define FAXIDLEN 21 @@ -332,6 +350,8 @@ typedef struct T30_s { #define ISDN_FAX_PHASE_D 4 #define ISDN_FAX_PHASE_E 5 +#endif /* TTY_FAX */ + #define ISDN_FAX_CLASS1_FAE 0 #define ISDN_FAX_CLASS1_FTS 1 #define ISDN_FAX_CLASS1_FRS 2 @@ -398,7 +418,9 @@ typedef struct { char display[85];/* display message data */ isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */ aux_s aux; /* for modem commands/indications */ +#ifdef CONFIG_ISDN_TTY_FAX T30_s *fax; /* Pointer to ttys fax struct */ +#endif ulong userdata; /* User Data */ } parm; } isdn_ctrl; diff -puN include/linux/isdn_ppp.h~i4l include/linux/isdn_ppp.h --- 25/include/linux/isdn_ppp.h~i4l 2004-02-09 22:19:20.000000000 -0800 +++ 25-akpm/include/linux/isdn_ppp.h 2004-02-09 22:19:20.000000000 -0800 @@ -21,46 +21,65 @@ struct pppcallinfo { - int calltype; - unsigned char local_num[64]; - unsigned char remote_num[64]; - int charge_units; + int calltype; + unsigned char local_num[64]; + unsigned char remote_num[64]; + int charge_units; }; -#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo) -#define PPPIOCBUNDLE _IOW('t',129,int) -#define PPPIOCGMPFLAGS _IOR('t',130,int) -#define PPPIOCSMPFLAGS _IOW('t',131,int) -#define PPPIOCSMPMTU _IOW('t',132,int) -#define PPPIOCSMPMRU _IOW('t',133,int) -#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long[8]) -#define PPPIOCSCOMPRESSOR _IOW('t',135,int) -#define PPPIOCGIFNAME _IOR('t',136,char[IFNAMSIZ]) +#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo) +#define PPPIOCBUNDLE _IOW('t',129,int) +#define PPPIOCGMPFLAGS _IOR('t',130,int) +#define PPPIOCSMPFLAGS _IOW('t',131,int) +#define PPPIOCSMPMTU _IOW('t',132,int) +#define PPPIOCSMPMRU _IOW('t',133,int) +#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8]) +#define PPPIOCSCOMPRESSOR _IOW('t',135,int) +#define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] ) + #define SC_MP_PROT 0x00000200 #define SC_REJ_MP_PROT 0x00000400 #define SC_OUT_SHORT_SEQ 0x00000800 #define SC_IN_SHORT_SEQ 0x00004000 +#define SC_DECOMP_ON 0x01 +#define SC_COMP_ON 0x02 +#define SC_DECOMP_DISCARD 0x04 +#define SC_COMP_DISCARD 0x08 +#define SC_LINK_DECOMP_ON 0x10 +#define SC_LINK_COMP_ON 0x20 +#define SC_LINK_DECOMP_DISCARD 0x40 +#define SC_LINK_COMP_DISCARD 0x80 + #define ISDN_PPP_COMP_MAX_OPTIONS 16 #define IPPP_COMP_FLAG_XMIT 0x1 #define IPPP_COMP_FLAG_LINK 0x2 struct isdn_ppp_comp_data { - int num; - unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS]; - int optlen; - int flags; + int num; + unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS]; + int optlen; + int flags; }; #ifdef __KERNEL__ -#include -#include + +#include + +#ifdef CONFIG_IPPP_FILTER +#include +#endif #define DECOMP_ERR_NOMEM (-10) +#define MP_END_FRAG 0x40 +#define MP_BEGIN_FRAG 0x80 + +#define MP_MAX_QUEUE_LEN 16 + /* * We need a way for the decompressor to influence the generation of CCP * Reset-Requests in a variety of ways. The decompressor is already returning @@ -79,15 +98,15 @@ struct isdn_ppp_comp_data { #define IPPP_RESET_MAXDATABYTES 32 struct isdn_ppp_resetparams { - unsigned char valid:1; /* rw Is this structure filled at all ? */ - unsigned char rsend:1; /* rw Should we send one at all ? */ - unsigned char idval:1; /* rw Is the id field valid ? */ - unsigned char dtval:1; /* rw Is the data field valid ? */ - unsigned char expra:1; /* rw Is an Ack expected for this Req ? */ - unsigned char id; /* wo Send CCP ResetReq with this id */ - unsigned short maxdlen; /* ro Max bytes to be stored in data field */ - unsigned short dlen; /* rw Bytes stored in data field */ - unsigned char *data; /* wo Data for ResetReq info field */ + unsigned char valid:1; /* rw Is this structure filled at all ? */ + unsigned char rsend:1; /* rw Should we send one at all ? */ + unsigned char idval:1; /* rw Is the id field valid ? */ + unsigned char dtval:1; /* rw Is the data field valid ? */ + unsigned char expra:1; /* rw Is an Ack expected for this Req ? */ + unsigned char id; /* wo Send CCP ResetReq with this id */ + unsigned short maxdlen; /* ro Max bytes to be stored in data field */ + unsigned short dlen; /* rw Bytes stored in data field */ + unsigned char *data; /* wo Data for ResetReq info field */ }; /* @@ -95,38 +114,135 @@ struct isdn_ppp_resetparams { * check the original include for more information */ struct isdn_ppp_compressor { - struct module *owner; - struct list_head list; - int num; /* CCP compression protocol number */ - - void *(*alloc) (struct isdn_ppp_comp_data *); - void (*free) (void *state); - int (*init) (void *state, struct isdn_ppp_comp_data *, - int unit,int debug); - - /* The reset entry needs to get more exact information about the - ResetReq or ResetAck it was called with. The parameters are - obvious. If reset is called without a Req or Ack frame which - could be handed into it, code MUST be set to 0. Using rsparm, - the reset entry can control if and how a ResetAck is returned. */ - - void (*reset) (void *state, unsigned char code, unsigned char id, - unsigned char *data, unsigned len, - struct isdn_ppp_resetparams *rsparm); + struct isdn_ppp_compressor *next, *prev; + struct module *owner; + int num; /* CCP compression protocol number */ + + void *(*alloc) (struct isdn_ppp_comp_data *); + void (*free) (void *state); + int (*init) (void *state, struct isdn_ppp_comp_data *, + int unit,int debug); + + /* The reset entry needs to get more exact information about the + ResetReq or ResetAck it was called with. The parameters are + obvious. If reset is called without a Req or Ack frame which + could be handed into it, code MUST be set to 0. Using rsparm, + the reset entry can control if and how a ResetAck is returned. */ + + void (*reset) (void *state, unsigned char code, unsigned char id, + unsigned char *data, unsigned len, + struct isdn_ppp_resetparams *rsparm); - int (*compress) (void *state, struct sk_buff *in, - struct sk_buff *skb_out, int proto); + int (*compress) (void *state, struct sk_buff *in, + struct sk_buff *skb_out, int proto); int (*decompress) (void *state,struct sk_buff *in, struct sk_buff *skb_out, struct isdn_ppp_resetparams *rsparm); - void (*incomp) (void *state, struct sk_buff *in,int proto); - void (*stat) (void *state, struct compstat *stats); + void (*incomp) (void *state, struct sk_buff *in,int proto); + void (*stat) (void *state, struct compstat *stats); }; extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *); extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *); +extern int isdn_ppp_dial_slave(char *); +extern int isdn_ppp_hangup_slave(char *); + +typedef struct { + unsigned long seqerrs; + unsigned long frame_drops; + unsigned long overflows; + unsigned long max_queue_len; +} isdn_mppp_stats; + +typedef struct { + int mp_mrru; /* unused */ + struct sk_buff * frags; /* fragments sl list -- use skb->next */ + long frames; /* number of frames in the frame list */ + unsigned int seq; /* last processed packet seq #: any packets + * with smaller seq # will be dropped + * unconditionally */ + spinlock_t lock; + int ref_ct; + /* statistics */ + isdn_mppp_stats stats; +} ippp_bundle; + +#define NUM_RCV_BUFFS 64 + +struct ippp_buf_queue { + struct ippp_buf_queue *next; + struct ippp_buf_queue *last; + char *buf; /* NULL here indicates end of queue */ + int len; +}; + +/* The data structure for one CCP reset transaction */ +enum ippp_ccp_reset_states { + CCPResetIdle, + CCPResetSentReq, + CCPResetRcvdReq, + CCPResetSentAck, + CCPResetRcvdAck +}; + +struct ippp_ccp_reset_state { + enum ippp_ccp_reset_states state; /* State of this transaction */ + struct ippp_struct *is; /* Backlink to device stuff */ + unsigned char id; /* Backlink id index */ + unsigned char ta:1; /* The timer is active (flag) */ + unsigned char expra:1; /* We expect a ResetAck at all */ + int dlen; /* Databytes stored in data */ + struct timer_list timer; /* For timeouts/retries */ + /* This is a hack but seems sufficient for the moment. We do not want + to have this be yet another allocation for some bytes, it is more + memory management overhead than the whole mess is worth. */ + unsigned char data[IPPP_RESET_MAXDATABYTES]; +}; + +/* The data structure keeping track of the currently outstanding CCP Reset + transactions. */ +struct ippp_ccp_reset { + struct ippp_ccp_reset_state *rs[256]; /* One per possible id */ + unsigned char lastid; /* Last id allocated by the engine */ +}; + +struct ippp_struct { + struct ippp_struct *next_link; + int state; + spinlock_t buflock; + struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */ + struct ippp_buf_queue *first; /* pointer to (current) first packet */ + struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */ + wait_queue_head_t wq; + struct task_struct *tk; + unsigned int mpppcfg; + unsigned int pppcfg; + unsigned int mru; + unsigned int mpmru; + unsigned int mpmtu; + unsigned int maxcid; + struct isdn_net_local_s *lp; + int unit; + int minor; + unsigned int last_link_seqno; + long mp_seqno; +#ifdef CONFIG_ISDN_PPP_VJ + unsigned char *cbuf; + struct slcompress *slcomp; +#endif +#ifdef CONFIG_IPPP_FILTER + struct sock_fprog pass_filter; /* filter for packets to pass */ + struct sock_fprog active_filter; /* filter for pkts to reset idle */ +#endif + unsigned long debug; + struct isdn_ppp_compressor *compressor,*decompressor; + struct isdn_ppp_compressor *link_compressor,*link_decompressor; + void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat; + struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */ + unsigned long compflags; +}; #endif /* __KERNEL__ */ #endif /* _LINUX_ISDN_PPP_H */ _