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

📄 isdn_common.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
			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_CTRL) {		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 * service routines access user space and are not atomic. Therefor, ioctl's * manipulating the lists and ioctl's sleeping while accessing the lists * are serialized by means of a semaphore. */		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;				return isdn_ppp_dial_slave(name);			case IIOCNETDLN:				if (!arg)					return -EINVAL;				if (copy_from_user(name, (char *) arg, sizeof(name)))					return -EFAULT;				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;				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 (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_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.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;					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;		}	}#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}/* * Open the device code. */static intisdn_open(struct inode *ino, struct file *filep){	uint minor = MINOR(ino->i_rdev);	int drvidx;	int chidx;	int retval = -ENODEV;	if (minor == ISDN_MINOR_STATUS) {		infostruct *p;		if ((p = (infostruct *) 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_CTRL) {		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	if (minor <= ISDN_MINOR_PPPMAX) {		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);		if (retval == 0)			isdn_lock_drivers();		goto out;	}#endif out:	return retval;}static intisdn_close(struct inode *ino, struct file *filep){	uint minor = MINOR(ino->i_rdev);	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_CTRL)		goto out;	if (minor <= ISDN_MINOR_CTRLMAX) {		if (dev->profd == current)			dev->profd = NULL;		goto out;	}#ifdef CONFIG_ISDN_PPP	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:		isdn_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){	driver *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))intisdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev		      ,int pre_chan, char *msn){	int i;	ulong flags;	ulong features;	ulong vfeatures;	save_flags(flags);	cli();	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();						restore_flags(flags);						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();							restore_flags(flags);							return i;						}					}				}			}		}	restore_flags(flags);	return -1;}/* * Set state of ISDN-channel to 'unused' */voidisdn_free_channel(int di, int ch, int usage){	int i;	ulong flags;	save_flags(flags);	cli();	for (i = 0; i < ISDN_MAX_CHANNELS; i++)

⌨️ 快捷键说明

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