⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isdn_common.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (minor <= ISDN_MINOR_PPPMAX)		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);#endif out:	unlock_kernel();	return 0;}static struct file_operations isdn_fops ={	.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){	isdn_driver_t *this = dev->drv[di];	int i;	if (strlen(msn) == 1) {		i = msn[0] - '0';		if ((i >= 0) && (i <= 9))			if (strlen(this->msn2eaz[i]))				return (this->msn2eaz[i]);	}	return (msn);}/* * Find an unused ISDN-channel, whose feature-flags match the * given L2- and L3-protocols. */#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))/* * This function must be called with holding the dev->lock. */intisdn_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;	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 (!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;}/* * Set state of ISDN-channel to 'unused' */voidisdn_free_channel(int di, int ch, int usage){	int i;	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]);		}}/* * Cancel Exclusive-Flag for ISDN-channel */voidisdn_unexclusive_channel(int di, int ch){	int i;	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;		}}/* *  writebuf replacement for SKB_ABLE drivers */static intisdn_writebuf_stub(int drvidx, int chan, const u_char __user * buf, int len){	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);	copy_from_user(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;}static intisdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding){	int j, k, m;	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 = 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; 	}	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;}/* * 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 */        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 /* CONFIG_ISDN_DIVERSION */EXPORT_SYMBOL(register_isdn);#ifdef CONFIG_ISDN_PPPEXPORT_SYMBOL(isdn_ppp_register_compressor);EXPORT_SYMBOL(isdn_ppp_unregister_compressor);#endifintregister_isdn(isdn_if * i){	isdn_driver_t *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 = 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));	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;	}	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;}/* ***************************************************************************** * And now the modules code. ***************************************************************************** */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;}/* * Allocate and initialize all data, register modem-devices */static int __init isdn_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;	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");		vfree(dev);		return -EIO;	}	if ((isdn_tty_modem_init()) < 0) {		printk(KERN_WARNING "isdn: Could not register tty devices\n");		vfree(dev);		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");		isdn_tty_exit();		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");#endif	isdn_info_update();	return 0;}/* * Unload module */static void __exit isdn_exit(void){#ifdef CONFIG_ISDN_PPP	isdn_ppp_cleanup();#endif	if (isdn_net_rmall() < 0) {		printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");		return;	}	isdn_tty_exit();	unregister_chrdev(ISDN_MAJOR, "isdn");	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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -