isdn_common.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 2,372 行 · 第 1/4 页
C
2,372 行
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: if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) return -1; isdn_info_update(); break; case ISDN_STAT_DISCH: save_flags(flags); cli(); 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; } restore_flags(flags); isdn_info_update(); break; case ISDN_STAT_UNLOAD: while (dev->drv[di]->locks > 0) { isdn_ctrl cmd; cmd.driver = di; cmd.arg = 0; cmd.command = ISDN_CMD_UNLOCK; isdn_command(&cmd); dev->drv[di]->locks--; } save_flags(flags); cli(); 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; isdn_unregister_devfs(i); } 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(); restore_flags(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;}/* * /dev/isdninfo */voidisdn_info_update(void){ infostruct *p = dev->infochain; while (p) { *(p->private) = 1; p = (infostruct *) p->next; } wake_up_interruptible(&(dev->info_waitq));}static intisdn_status_open(struct inode *ino, struct file *filep){ infostruct *p; p = kmalloc(sizeof(infostruct), GFP_KERNEL); if (!p) return -ENOMEM; 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; return 0;}static intisdn_status_release(struct inode *ino, struct file *filep){ infostruct *p = dev->infochain; infostruct *q = NULL; lock_kernel(); 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"); out: unlock_kernel(); return 0;}static ssize_tisdn_status_read(struct file *file, char *buf, size_t count, loff_t * off){ int retval; int len = 0; char *p; if (off != &file->f_pos) return -ESPIPE; lock_kernel(); 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 = 0; 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; out: unlock_kernel(); return retval;}static ssize_tisdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off){ return -EPERM;}static unsigned intisdn_status_poll(struct file *file, poll_table *wait){ unsigned int mask = 0; lock_kernel(); poll_wait(file, &(dev->info_waitq), wait); if (file->private_data) mask |= POLLIN | POLLRDNORM; unlock_kernel(); return mask;}static intisdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){ int ret; union iocpar { char name[10]; char bname[22]; isdn_ioctl_struct iocts; isdn_net_ioctl_phone phone; isdn_net_ioctl_cfg cfg; } iocpar;#define name iocpar.name#define bname iocpar.bname#define iocts iocpar.iocts#define phone iocpar.phone#define cfg iocpar.cfg switch (cmd) { case IIOCGETDVR: return (TTY_DV + (NET_DV << 8) + (INF_DV << 16)); 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; }#undef name#undef bname#undef iocts#undef phone#undef cfg}static struct file_operations isdn_status_fops ={ owner: THIS_MODULE, llseek: no_llseek, read: isdn_status_read, write: isdn_status_write, poll: isdn_status_poll, ioctl: isdn_status_ioctl, open: isdn_status_open, release: isdn_status_release,};/* * /dev/isdnctrlX */static intisdn_ctrl_open(struct inode *ino, struct file *filep){ uint minor = minor(ino->i_rdev); int drvidx; drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) return -ENODEV; isdn_lock_drivers(); return 0;}static intisdn_ctrl_release(struct inode *ino, struct file *filep){ lock_kernel(); if (dev->profd == current) dev->profd = NULL; isdn_unlock_drivers(); unlock_kernel(); return 0;}static ssize_tisdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off){ uint minor = minor(file->f_dentry->d_inode->i_rdev); ulong flags; int len = 0; int drvidx; int retval; if (off != &file->f_pos) return -ESPIPE; lock_kernel(); drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?