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

📄 isdn_common.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
			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); #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:			spin_lock_irqsave(&dev->lock, flags);			for (i = 0; i < ISDN_MAX_CHANNELS; i++)				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;				}			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 /* CONFIG_ISDN_DIVERSION */		default:			return -1;	}	return 0;}/* * Get integer from char-pointer, set pointer to end of number */intisdn_getnum(char **p){	int v = -1;	while (*p[0] >= '0' && *p[0] <= '9')		v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');	return v;}#define DLE 0x10/* * isdn_readbchan() tries to get data from the read-queue. * It MUST be called with interrupts off. * * 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  */intisdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep){	int count;	int count_pull;	int count_put;	int dflag;	struct sk_buff *skb;	u_char *cp;	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++;					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		}#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(&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;}static __inline intisdn_minor2drv(int minor){	return (dev->drvmap[minor]);}static __inline intisdn_minor2chan(int minor){	return (dev->chanmap[minor]);}static char *isdn_statstr(void){	static char istatbuf[2048];	char *p;	int i;	sprintf(istatbuf, "idmap:\t");	p = istatbuf + strlen(istatbuf);	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {		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++) {		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++) {		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++) {		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++) {		if (dev->drv[i]) {			sprintf(p, "%ld ", dev->drv[i]->online);			p = istatbuf + strlen(istatbuf);		} else {			sprintf(p, "? ");			p = istatbuf + strlen(istatbuf);		}	}	sprintf(p, "\nphone:\t");	p = istatbuf + strlen(istatbuf);	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {		sprintf(p, "%s ", dev->num[i]);		p = istatbuf + strlen(istatbuf);	}	sprintf(p, "\n");	return istatbuf;}/* Module interface-code */voidisdn_info_update(void){	infostruct *p = dev->infochain;	while (p) {		*(p->private) = 1;		p = (infostruct *) p->next;	}	wake_up_interruptible(&(dev->info_waitq));}static ssize_tisdn_read(struct file *file, char __user *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;	char *p;	lock_kernel();	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 = NULL;		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, NULL, count,				     &dev->drv[drvidx]->rcv_waitq[chidx]);		*off += len;		if (copy_to_user(buf,p,len)) 			len = -EFAULT;		kfree(p);		retval = len;		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, 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_tisdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off){	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);	int drvidx;	int chidx;	int retval;	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 (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {			retval = -ENODEV;			goto out;		}		chidx = isdn_minor2chan(minor);		while (isdn_writebuf_stub(drvidx, chidx, buf, count) != count)			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);		retval = count;		goto out;	}	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, drvidx, isdn_minor2chan(minor));		else			retval = count;		goto out;	}#ifdef CONFIG_ISDN_PPP	if (minor <= ISDN_MINOR_PPPMAX) {		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);		goto out;	}#endif	retval = -ENODEV; out:	unlock_kernel();	return retval;}static unsigned intisdn_poll(struct file *file, poll_table * wait){	unsigned int mask = 0;	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);	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) {

⌨️ 快捷键说明

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