📄 isdn_common.c
字号:
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 + -