📄 isdn_common.c
字号:
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(); isdn_free_queue(&dev->drv[di]->rpqueue[ch]); } restore_flags(flags);}/* * Cancel Exclusive-Flag for ISDN-channel */voidisdn_unexclusive_channel(int di, int ch){ int i; ulong flags; save_flags(flags); cli(); 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(); restore_flags(flags); return; } restore_flags(flags);}/* * writebuf replacement for SKB_ABLE drivers */static intisdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len, int user){ 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. */intisdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *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;}intregister_isdn_module(isdn_module *m) { return 0;}intunregister_isdn_module(isdn_module *m) { return 0;}intisdn_add_channels(driver *d, int drvidx, int n, int adding){ int j, k, m; ulong flags; init_waitqueue_head(&d->st_waitq); if (d->flags & DRV_FLAG_RUNNING) return -1; if (n < 1) return 0; 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 -1; } if ((adding) && (d->rcverr)) kfree(d->rcverr); if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { 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 = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { 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++) isdn_free_queue(&d->rpqueue[j]); kfree(d->rpqueue); } if (!(d->rpqueue = (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); if (!adding) { kfree(d->rcvcount); kfree(d->rcverr); } return -1; } 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 = (wait_queue_head_t *) kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); 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; save_flags(flags); cli(); 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; isdn_register_devfs(k); break; } restore_flags(flags); d->channels = m; return 0;}/* * Low-level-driver registration */static voidset_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_DIVERSIONstatic char *map_drvname(int di){ if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) return(NULL); return(dev->drvid[di]); /* driver name */} /* map_drvname */static int map_namedrv(char *id){ int i; for (i = 0; i < ISDN_MAX_DRIVERS; i++) { if (!strcmp(dev->drvid[i],id)) return(i); } return(-1);} /* map_namedrv */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); }} /* DIVERT_REG_NAME */EXPORT_SYMBOL(DIVERT_REG_NAME);#endif CONFIG_ISDN_DIVERSIONEXPORT_SYMBOL(register_isdn);EXPORT_SYMBOL(register_isdn_module);EXPORT_SYMBOL(unregister_isdn_module);#ifdef CONFIG_ISDN_PPPEXPORT_SYMBOL(isdn_ppp_register_compressor);EXPORT_SYMBOL(isdn_ppp_unregister_compressor);#endifintregister_isdn(isdn_if * i){ driver *d; int j; ulong flags; int drvidx; if (dev->drivers >= ISDN_MAX_DRIVERS) { printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", ISDN_MAX_DRIVERS); return 0; } if (!i->writebuf_skb) { printk(KERN_WARNING "register_isdn: No write routine given.\n"); return 0; } if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); return 0; } memset((char *) d, 0, sizeof(driver)); d->maxbufsize = i->maxbufsize; d->pktcount = 0; d->stavail = 0; d->flags = DRV_FLAG_LOADED; d->online = 0; d->interface = i; d->channels = 0; for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) if (!dev->drv[drvidx]) break; if (isdn_add_channels(d, drvidx, i->channels, 0)) { kfree(d); return 0; } 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); save_flags(flags); cli(); 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(); restore_flags(flags); return 1;}/* ***************************************************************************** * And now the modules code. ***************************************************************************** */extern int printk(const char *fmt,...);#ifdef MODULE#define isdn_init init_module#endifstatic 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;}#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_handle;static void isdn_register_devfs(int k){ char buf[11]; sprintf (buf, "isdn%d", k); dev->devfs_handle_isdnX[k] = devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR, &isdn_fops, NULL); sprintf (buf, "isdnctrl%d", k); dev->devfs_handle_isdnctrlX[k] = devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR, &isdn_fops, NULL);}static void isdn_unregister_devfs(int k){ devfs_unregister (dev->devfs_handle_isdnX[k]); devfs_unregister (dev->devfs_handle_isdnctrlX[k]);}static void isdn_init_devfs(void){# ifdef CONFIG_ISDN_PPP int i;# endif devfs_handle = devfs_mk_dir (NULL, "isdn", NULL);# ifdef CONFIG_ISDN_PPP for (i = 0; i < ISDN_MAX_CHANNELS; i++) { char buf[8]; sprintf (buf, "ippp%d", i); dev->devfs_handle_ipppX[i] = devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_PPP + i, 0600 | S_IFCHR, &isdn_fops, NULL); }# endif dev->devfs_handle_isdninfo = devfs_register (devfs_handle, "isdninfo", DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR, &isdn_fops, NULL); dev->devfs_handle_isdnctrl = devfs_register (devfs_handle, "isdnctrl", DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, &isdn_fops, NULL);}static void isdn_cleanup_devfs(void){# ifdef CONFIG_ISDN_PPP int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) devfs_unregister (dev->devfs_handle_ipppX[i]);# endif devfs_unregister (dev->devfs_handle_isdninfo); devfs_unregister (dev->devfs_handle_isdnctrl); devfs_unregister (devfs_handle);}#else /* CONFIG_DEVFS_FS */static void isdn_register_devfs(int dummy){ return;}static void isdn_unregister_devfs(int dummy){ return;}static void isdn_init_devfs(void){ return;}static void isdn_cleanup_devfs(void){ return;}#endif /* CONFIG_DEVFS_FS *//* * Allocate and initialize all data, register modem-devices */intisdn_init(void){ int i; char tmprev[50]; 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; 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 (devfs_register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { printk(KERN_WARNING "isdn: Could not register control devices\n"); vfree(dev); return -EIO; } isdn_init_devfs(); if ((i = isdn_tty_modem_init()) < 0) { printk(KERN_WARNING "isdn: Could not register tty devices\n"); if (i == -3) tty_unregister_driver(&dev->mdm.cua_modem); if (i <= -2) tty_unregister_driver(&dev->mdm.tty_modem); vfree(dev); isdn_cleanup_devfs(); devfs_unregister_chrdev(ISDN_MAJOR, "isdn"); return -EIO; }#ifdef CONFIG_ISDN_PPP if (isdn_ppp_init() < 0) { printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n"); tty_unregister_driver(&dev->mdm.tty_modem); tty_unregister_driver(&dev->mdm.cua_modem); for (i = 0; i < ISDN_MAX_CHANNELS; i++) kfree(dev->mdm.info[i].xmit_buf - 4); isdn_cleanup_devfs(); devfs_unregister_chrdev(ISDN_MAJOR, "isdn"); vfree(dev); return -EIO; }#endif /* CONFIG_ISDN_PPP */ 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 MODULE printk(" loaded\n");#else printk("\n"); isdn_cards_init();#endif isdn_info_update(); return 0;}#ifdef MODULE/* * Unload module */voidcleanup_module(void){ int flags; int i;#ifdef CONFIG_ISDN_PPP isdn_ppp_cleanup();#endif save_flags(flags); cli(); if (isdn_net_rmall() < 0) { printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n"); restore_flags(flags); return; } if (tty_unregister_driver(&dev->mdm.tty_modem)) { printk(KERN_WARNING "isdn: ttyI-device busy, remove cancelled\n"); restore_flags(flags); return; } if (tty_unregister_driver(&dev->mdm.cua_modem)) { printk(KERN_WARNING "isdn: cui-device busy, remove cancelled\n"); restore_flags(flags); return; } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { isdn_tty_cleanup_xmit(&dev->mdm.info[i]); kfree(dev->mdm.info[i].xmit_buf - 4);#ifdef CONFIG_ISDN_TTY_FAX kfree(dev->mdm.info[i].fax);#endif } if (devfs_unregister_chrdev(ISDN_MAJOR, "isdn") != 0) { printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n"); restore_flags(flags); } else { isdn_cleanup_devfs(); del_timer(&dev->timer); restore_flags(flags); /* call vfree with interrupts enabled, else it will hang */ vfree(dev); printk(KERN_NOTICE "ISDN-subsystem unloaded\n"); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -