linux-old/drivers/isdn/divert/divert_procfs.c
<<
>>
Prefs
   1/* $Id: divert_procfs.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
   2 *
   3 * Filesystem handling for the diversion supplementary services.
   4 *
   5 * Copyright 1998       by Werner Cornelius (werner@isdn4linux.de)
   6 *
   7 * This software may be used and distributed according to the terms
   8 * of the GNU General Public License, incorporated herein by reference.
   9 *
  10 */
  11
  12#include <linux/config.h>
  13#define __NO_VERSION__
  14#include <linux/module.h>
  15#include <linux/version.h>
  16#include <linux/poll.h>
  17#include <linux/smp_lock.h>
  18#ifdef CONFIG_PROC_FS
  19#include <linux/proc_fs.h>
  20#else
  21#include <linux/fs.h>
  22#endif
  23#include <linux/isdnif.h>
  24#include "isdn_divert.h"
  25
  26/*********************************/
  27/* Variables for interface queue */
  28/*********************************/
  29ulong if_used = 0;              /* number of interface users */
  30static struct divert_info *divert_info_head = NULL;     /* head of queue */
  31static struct divert_info *divert_info_tail = NULL;     /* pointer to last entry */
  32static wait_queue_head_t rd_queue;
  33
  34/*********************************/
  35/* put an info buffer into queue */
  36/*********************************/
  37void
  38put_info_buffer(char *cp)
  39{
  40        struct divert_info *ib;
  41        unsigned long flags;
  42
  43        if (if_used <= 0)
  44                return;
  45        if (!cp)
  46                return;
  47        if (!*cp)
  48                return;
  49        if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
  50                 return;        /* no memory */
  51        strcpy(ib->info_start, cp);     /* set output string */
  52        ib->next = NULL;
  53        save_flags(flags);
  54        cli();
  55        ib->usage_cnt = if_used;
  56        if (!divert_info_head)
  57                divert_info_head = ib;  /* new head */
  58        else
  59                divert_info_tail->next = ib;    /* follows existing messages */
  60        divert_info_tail = ib;  /* new tail */
  61        restore_flags(flags);
  62
  63        /* delete old entrys */
  64        while (divert_info_head->next) {
  65                if ((divert_info_head->usage_cnt <= 0) &&
  66                    (divert_info_head->next->usage_cnt <= 0)) {
  67                        ib = divert_info_head;
  68                        divert_info_head = divert_info_head->next;
  69                        kfree(ib);
  70                } else
  71                        break;
  72        }                       /* divert_info_head->next */
  73        wake_up_interruptible(&(rd_queue));
  74}                               /* put_info_buffer */
  75
  76/**********************************/
  77/* deflection device read routine */
  78/**********************************/
  79static ssize_t
  80isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
  81{
  82        struct divert_info *inf;
  83        loff_t pos = *off;
  84        int len;
  85
  86        if (!*((struct divert_info **) file->private_data)) {
  87                if (file->f_flags & O_NONBLOCK)
  88                        return -EAGAIN;
  89                interruptible_sleep_on(&(rd_queue));
  90        }
  91        if (!(inf = *((struct divert_info **) file->private_data)))
  92                return (0);
  93
  94        inf->usage_cnt--;       /* new usage count */
  95        file->private_data = &inf->next;        /* next structure */
  96        if ((len = strlen(inf->info_start)) <= count) {
  97                if (copy_to_user(buf, inf->info_start, len))
  98                        return -EFAULT;
  99                *off = pos + len;
 100                return (len);
 101        }
 102        return (0);
 103}                               /* isdn_divert_read */
 104
 105/**********************************/
 106/* deflection device write routine */
 107/**********************************/
 108static ssize_t
 109isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t * off)
 110{
 111        return (-ENODEV);
 112}                               /* isdn_divert_write */
 113
 114
 115/***************************************/
 116/* select routines for various kernels */
 117/***************************************/
 118static unsigned int
 119isdn_divert_poll(struct file *file, poll_table * wait)
 120{
 121        unsigned int mask = 0;
 122
 123        poll_wait(file, &(rd_queue), wait);
 124        /* mask = POLLOUT | POLLWRNORM; */
 125        if (*((struct divert_info **) file->private_data)) {
 126                mask |= POLLIN | POLLRDNORM;
 127        }
 128        return mask;
 129}                               /* isdn_divert_poll */
 130
 131/****************/
 132/* Open routine */
 133/****************/
 134static int
 135isdn_divert_open(struct inode *ino, struct file *filep)
 136{
 137        unsigned long flags;
 138
 139        lock_kernel();
 140        save_flags(flags);
 141        cli();
 142        if_used++;
 143        if (divert_info_head)
 144                filep->private_data = &(divert_info_tail->next);
 145        else
 146                filep->private_data = &divert_info_head;
 147        restore_flags(flags);
 148        /*  start_divert(); */
 149        unlock_kernel();
 150        return (0);
 151}                               /* isdn_divert_open */
 152
 153/*******************/
 154/* close routine   */
 155/*******************/
 156static int
 157isdn_divert_close(struct inode *ino, struct file *filep)
 158{
 159        struct divert_info *inf;
 160        unsigned long flags;
 161
 162        lock_kernel();
 163        save_flags(flags);
 164        cli();
 165        if_used--;
 166        inf = *((struct divert_info **) filep->private_data);
 167        while (inf) {
 168                inf->usage_cnt--;
 169                inf = inf->next;
 170        }
 171        restore_flags(flags);
 172        if (if_used <= 0)
 173                while (divert_info_head) {
 174                        inf = divert_info_head;
 175                        divert_info_head = divert_info_head->next;
 176                        kfree(inf);
 177                }
 178        unlock_kernel();
 179        return (0);
 180}                               /* isdn_divert_close */
 181
 182/*********/
 183/* IOCTL */
 184/*********/
 185static int
 186isdn_divert_ioctl(struct inode *inode, struct file *file,
 187                  uint cmd, ulong arg)
 188{
 189        divert_ioctl dioctl;
 190        int i;
 191        unsigned long flags;
 192        divert_rule *rulep;
 193        char *cp;
 194
 195        if ((i = copy_from_user(&dioctl, (char *) arg, sizeof(dioctl))))
 196                return (i);
 197
 198        switch (cmd) {
 199                case IIOCGETVER:
 200                        dioctl.drv_version = DIVERT_IIOC_VERSION;       /* set version */
 201                        break;
 202
 203                case IIOCGETDRV:
 204                        if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
 205                                return (-EINVAL);
 206                        break;
 207
 208                case IIOCGETNAM:
 209                        cp = divert_if.drv_to_name(dioctl.getid.drvid);
 210                        if (!cp)
 211                                return (-EINVAL);
 212                        if (!*cp)
 213                                return (-EINVAL);
 214                        strcpy(dioctl.getid.drvnam, cp);
 215                        break;
 216
 217                case IIOCGETRULE:
 218                        if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
 219                                return (-EINVAL);
 220                        dioctl.getsetrule.rule = *rulep;        /* copy data */
 221                        break;
 222
 223                case IIOCMODRULE:
 224                        if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
 225                                return (-EINVAL);
 226                        save_flags(flags);
 227                        cli();
 228                        *rulep = dioctl.getsetrule.rule;        /* copy data */
 229                        restore_flags(flags);
 230                        return (0);     /* no copy required */
 231                        break;
 232
 233                case IIOCINSRULE:
 234                        return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
 235                        break;
 236
 237                case IIOCDELRULE:
 238                        return (deleterule(dioctl.getsetrule.ruleidx));
 239                        break;
 240
 241                case IIOCDODFACT:
 242                        return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
 243                                                  dioctl.fwd_ctrl.callid,
 244                                                 dioctl.fwd_ctrl.to_nr));
 245
 246                case IIOCDOCFACT:
 247                case IIOCDOCFDIS:
 248                case IIOCDOCFINT:
 249                        if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
 250                                return (-EINVAL);       /* invalid driver */
 251                        if ((i = cf_command(dioctl.cf_ctrl.drvid,
 252                                            (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
 253                                            dioctl.cf_ctrl.cfproc,
 254                                            dioctl.cf_ctrl.msn,
 255                                            dioctl.cf_ctrl.service,
 256                                            dioctl.cf_ctrl.fwd_nr,
 257                                            &dioctl.cf_ctrl.procid)))
 258                                return (i);
 259                        break;
 260
 261                default:
 262                        return (-EINVAL);
 263        }                       /* switch cmd */
 264        return (copy_to_user((char *) arg, &dioctl, sizeof(dioctl)));   /* success */
 265}                               /* isdn_divert_ioctl */
 266
 267
 268#ifdef CONFIG_PROC_FS
 269static struct file_operations isdn_fops =
 270{
 271        llseek:         no_llseek,
 272        read:           isdn_divert_read,
 273        write:          isdn_divert_write,
 274        poll:           isdn_divert_poll,
 275        ioctl:          isdn_divert_ioctl,
 276        open:           isdn_divert_open,
 277        release:        isdn_divert_close,                                      
 278};
 279
 280/****************************/
 281/* isdn subdir in /proc/net */
 282/****************************/
 283static struct proc_dir_entry *isdn_proc_entry = NULL;
 284static struct proc_dir_entry *isdn_divert_entry = NULL;
 285#endif  /* CONFIG_PROC_FS */
 286
 287/***************************************************************************/
 288/* divert_dev_init must be called before the proc filesystem may be used   */
 289/***************************************************************************/
 290int
 291divert_dev_init(void)
 292{
 293
 294        init_waitqueue_head(&rd_queue);
 295
 296#ifdef CONFIG_PROC_FS
 297        isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
 298        if (!isdn_proc_entry)
 299                return (-1);
 300        isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
 301        if (!isdn_divert_entry) {
 302                remove_proc_entry("isdn", proc_net);
 303                return (-1);
 304        }
 305        isdn_divert_entry->proc_fops = &isdn_fops; 
 306        isdn_divert_entry->owner = THIS_MODULE; 
 307#endif  /* CONFIG_PROC_FS */
 308
 309        return (0);
 310}                               /* divert_dev_init */
 311
 312/***************************************************************************/
 313/* divert_dev_deinit must be called before leaving isdn when included as   */
 314/* a module.                                                               */
 315/***************************************************************************/
 316int
 317divert_dev_deinit(void)
 318{
 319
 320#ifdef CONFIG_PROC_FS
 321        remove_proc_entry("divert", isdn_proc_entry);
 322        remove_proc_entry("isdn", proc_net);
 323#endif  /* CONFIG_PROC_FS */
 324
 325        return (0);
 326}                               /* divert_dev_deinit */
 327
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.