linux/drivers/isdn/hysdn/hysdn_proclog.c
<<
>>
Prefs
   1/* $Id: hysdn_proclog.c,v 1.9.6.3 2001/09/23 22:24:54 kai Exp $
   2 *
   3 * Linux driver for HYSDN cards, /proc/net filesystem log functions.
   4 *
   5 * Author    Werner Cornelius (werner@titro.de) for Hypercope GmbH
   6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/poll.h>
  15#include <linux/proc_fs.h>
  16#include <linux/sched.h>
  17#include <linux/smp_lock.h>
  18
  19#include "hysdn_defs.h"
  20
  21/* the proc subdir for the interface is defined in the procconf module */
  22extern struct proc_dir_entry *hysdn_proc_entry;
  23
  24static void put_log_buffer(hysdn_card * card, char *cp);
  25
  26/*************************************************/
  27/* structure keeping ascii log for device output */
  28/*************************************************/
  29struct log_data {
  30        struct log_data *next;
  31        unsigned long usage_cnt;/* number of files still to work */
  32        void *proc_ctrl;        /* pointer to own control procdata structure */
  33        char log_start[2];      /* log string start (final len aligned by size) */
  34};
  35
  36/**********************************************/
  37/* structure holding proc entrys for one card */
  38/**********************************************/
  39struct procdata {
  40        struct proc_dir_entry *log;     /* log entry */
  41        char log_name[15];      /* log filename */
  42        struct log_data *log_head, *log_tail;   /* head and tail for queue */
  43        int if_used;            /* open count for interface */
  44        int volatile del_lock;  /* lock for delete operations */
  45        unsigned char logtmp[LOG_MAX_LINELEN];
  46        wait_queue_head_t rd_queue;
  47};
  48
  49
  50/**********************************************/
  51/* log function for cards error log interface */
  52/**********************************************/
  53void
  54hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
  55{
  56        char buf[ERRLOG_TEXT_SIZE + 40];
  57
  58        sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
  59        put_log_buffer(card, buf);      /* output the string */
  60}                               /* hysdn_card_errlog */
  61
  62/***************************************************/
  63/* Log function using format specifiers for output */
  64/***************************************************/
  65void
  66hysdn_addlog(hysdn_card * card, char *fmt,...)
  67{
  68        struct procdata *pd = card->proclog;
  69        char *cp;
  70        va_list args;
  71
  72        if (!pd)
  73                return;         /* log structure non existent */
  74
  75        cp = pd->logtmp;
  76        cp += sprintf(cp, "HYSDN: card %d ", card->myid);
  77
  78        va_start(args, fmt);
  79        cp += vsprintf(cp, fmt, args);
  80        va_end(args);
  81        *cp++ = '\n';
  82        *cp = 0;
  83
  84        if (card->debug_flags & DEB_OUT_SYSLOG)
  85                printk(KERN_INFO "%s", pd->logtmp);
  86        else
  87                put_log_buffer(card, pd->logtmp);
  88
  89}                               /* hysdn_addlog */
  90
  91/********************************************/
  92/* put an log buffer into the log queue.    */
  93/* This buffer will be kept until all files */
  94/* opened for read got the contents.        */
  95/* Flushes buffers not longer in use.       */
  96/********************************************/
  97static void
  98put_log_buffer(hysdn_card * card, char *cp)
  99{
 100        struct log_data *ib;
 101        struct procdata *pd = card->proclog;
 102        int i;
 103        unsigned long flags;
 104
 105        if (!pd)
 106                return;
 107        if (!cp)
 108                return;
 109        if (!*cp)
 110                return;
 111        if (pd->if_used <= 0)
 112                return;         /* no open file for read */
 113
 114        if (!(ib = kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
 115                 return;        /* no memory */
 116        strcpy(ib->log_start, cp);      /* set output string */
 117        ib->next = NULL;
 118        ib->proc_ctrl = pd;     /* point to own control structure */
 119        spin_lock_irqsave(&card->hysdn_lock, flags);
 120        ib->usage_cnt = pd->if_used;
 121        if (!pd->log_head)
 122                pd->log_head = ib;      /* new head */
 123        else
 124                pd->log_tail->next = ib;        /* follows existing messages */
 125        pd->log_tail = ib;      /* new tail */
 126        i = pd->del_lock++;     /* get lock state */
 127        spin_unlock_irqrestore(&card->hysdn_lock, flags);
 128
 129        /* delete old entrys */
 130        if (!i)
 131                while (pd->log_head->next) {
 132                        if ((pd->log_head->usage_cnt <= 0) &&
 133                            (pd->log_head->next->usage_cnt <= 0)) {
 134                                ib = pd->log_head;
 135                                pd->log_head = pd->log_head->next;
 136                                kfree(ib);
 137                        } else
 138                                break;
 139                }               /* pd->log_head->next */
 140        pd->del_lock--;         /* release lock level */
 141        wake_up_interruptible(&(pd->rd_queue));         /* announce new entry */
 142}                               /* put_log_buffer */
 143
 144
 145/******************************/
 146/* file operations and tables */
 147/******************************/
 148
 149/****************************************/
 150/* write log file -> set log level bits */
 151/****************************************/
 152static ssize_t
 153hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
 154{
 155        unsigned long u = 0;
 156        int found = 0;
 157        unsigned char *cp, valbuf[128];
 158        long base = 10;
 159        hysdn_card *card = (hysdn_card *) file->private_data;
 160
 161        if (count > (sizeof(valbuf) - 1))
 162                count = sizeof(valbuf) - 1;     /* limit length */
 163        if (copy_from_user(valbuf, buf, count))
 164                return (-EFAULT);       /* copy failed */
 165
 166        valbuf[count] = 0;      /* terminating 0 */
 167        cp = valbuf;
 168        if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
 169                cp += 2;        /* pointer after hex modifier */
 170                base = 16;
 171        }
 172        /* scan the input for debug flags */
 173        while (*cp) {
 174                if ((*cp >= '0') && (*cp <= '9')) {
 175                        found = 1;
 176                        u *= base;      /* adjust to next digit */
 177                        u += *cp++ - '0';
 178                        continue;
 179                }
 180                if (base != 16)
 181                        break;  /* end of number */
 182
 183                if ((*cp >= 'a') && (*cp <= 'f')) {
 184                        found = 1;
 185                        u *= base;      /* adjust to next digit */
 186                        u += *cp++ - 'a' + 10;
 187                        continue;
 188                }
 189                break;          /* terminated */
 190        }
 191
 192        if (found) {
 193                card->debug_flags = u;  /* remember debug flags */
 194                hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
 195        }
 196        return (count);
 197}                               /* hysdn_log_write */
 198
 199/******************/
 200/* read log file */
 201/******************/
 202static ssize_t
 203hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t * off)
 204{
 205        struct log_data *inf;
 206        int len;
 207        struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
 208        struct procdata *pd = NULL;
 209        hysdn_card *card;
 210
 211        if (!*((struct log_data **) file->private_data)) {
 212                if (file->f_flags & O_NONBLOCK)
 213                        return (-EAGAIN);
 214
 215                /* sorry, but we need to search the card */
 216                card = card_root;
 217                while (card) {
 218                        pd = card->proclog;
 219                        if (pd->log == pde)
 220                                break;
 221                        card = card->next;      /* search next entry */
 222                }
 223                if (card)
 224                        interruptible_sleep_on(&(pd->rd_queue));
 225                else
 226                        return (-EAGAIN);
 227
 228        }
 229        if (!(inf = *((struct log_data **) file->private_data)))
 230                return (0);
 231
 232        inf->usage_cnt--;       /* new usage count */
 233        file->private_data = &inf->next;        /* next structure */
 234        if ((len = strlen(inf->log_start)) <= count) {
 235                if (copy_to_user(buf, inf->log_start, len))
 236                        return -EFAULT;
 237                *off += len;
 238                return (len);
 239        }
 240        return (0);
 241}                               /* hysdn_log_read */
 242
 243/******************/
 244/* open log file */
 245/******************/
 246static int
 247hysdn_log_open(struct inode *ino, struct file *filep)
 248{
 249        hysdn_card *card;
 250        struct procdata *pd = NULL;
 251        unsigned long flags;
 252
 253        lock_kernel();
 254        card = card_root;
 255        while (card) {
 256                pd = card->proclog;
 257                if (pd->log == PDE(ino))
 258                        break;
 259                card = card->next;      /* search next entry */
 260        }
 261        if (!card) {
 262                unlock_kernel();
 263                return (-ENODEV);       /* device is unknown/invalid */
 264        }
 265        filep->private_data = card;     /* remember our own card */
 266
 267        if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 268                /* write only access -> write log level only */
 269        } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
 270
 271                /* read access -> log/debug read */
 272                spin_lock_irqsave(&card->hysdn_lock, flags);
 273                pd->if_used++;
 274                if (pd->log_head)
 275                        filep->private_data = &pd->log_tail->next;
 276                else
 277                        filep->private_data = &pd->log_head;
 278                spin_unlock_irqrestore(&card->hysdn_lock, flags);
 279        } else {                /* simultaneous read/write access forbidden ! */
 280                unlock_kernel();
 281                return (-EPERM);        /* no permission this time */
 282        }
 283        unlock_kernel();
 284        return nonseekable_open(ino, filep);
 285}                               /* hysdn_log_open */
 286
 287/*******************************************************************************/
 288/* close a cardlog file. If the file has been opened for exclusive write it is */
 289/* assumed as pof data input and the pof loader is noticed about.              */
 290/* Otherwise file is handled as log output. In this case the interface usage   */
 291/* count is decremented and all buffers are noticed of closing. If this file   */
 292/* was the last one to be closed, all buffers are freed.                       */
 293/*******************************************************************************/
 294static int
 295hysdn_log_close(struct inode *ino, struct file *filep)
 296{
 297        struct log_data *inf;
 298        struct procdata *pd;
 299        hysdn_card *card;
 300        int retval = 0;
 301
 302        lock_kernel();
 303        if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 304                /* write only access -> write debug level written */
 305                retval = 0;     /* success */
 306        } else {
 307                /* read access -> log/debug read, mark one further file as closed */
 308
 309                pd = NULL;
 310                inf = *((struct log_data **) filep->private_data);      /* get first log entry */
 311                if (inf)
 312                        pd = (struct procdata *) inf->proc_ctrl;        /* still entries there */
 313                else {
 314                        /* no info available -> search card */
 315                        card = card_root;
 316                        while (card) {
 317                                pd = card->proclog;
 318                                if (pd->log == PDE(ino))
 319                                        break;
 320                                card = card->next;      /* search next entry */
 321                        }
 322                        if (card)
 323                                pd = card->proclog;     /* pointer to procfs log */
 324                }
 325                if (pd)
 326                        pd->if_used--;  /* decrement interface usage count by one */
 327
 328                while (inf) {
 329                        inf->usage_cnt--;       /* decrement usage count for buffers */
 330                        inf = inf->next;
 331                }
 332
 333                if (pd)
 334                        if (pd->if_used <= 0)   /* delete buffers if last file closed */
 335                                while (pd->log_head) {
 336                                        inf = pd->log_head;
 337                                        pd->log_head = pd->log_head->next;
 338                                        kfree(inf);
 339                                }
 340        }                       /* read access */
 341        unlock_kernel();
 342
 343        return (retval);
 344}                               /* hysdn_log_close */
 345
 346/*************************************************/
 347/* select/poll routine to be able using select() */
 348/*************************************************/
 349static unsigned int
 350hysdn_log_poll(struct file *file, poll_table * wait)
 351{
 352        unsigned int mask = 0;
 353        struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
 354        hysdn_card *card;
 355        struct procdata *pd = NULL;
 356
 357        if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
 358                return (mask);  /* no polling for write supported */
 359
 360        /* we need to search the card */
 361        card = card_root;
 362        while (card) {
 363                pd = card->proclog;
 364                if (pd->log == pde)
 365                        break;
 366                card = card->next;      /* search next entry */
 367        }
 368        if (!card)
 369                return (mask);  /* card not found */
 370
 371        poll_wait(file, &(pd->rd_queue), wait);
 372
 373        if (*((struct log_data **) file->private_data))
 374                mask |= POLLIN | POLLRDNORM;
 375
 376        return mask;
 377}                               /* hysdn_log_poll */
 378
 379/**************************************************/
 380/* table for log filesystem functions defined above. */
 381/**************************************************/
 382static const struct file_operations log_fops =
 383{
 384        .owner          = THIS_MODULE,
 385        .llseek         = no_llseek,
 386        .read           = hysdn_log_read,
 387        .write          = hysdn_log_write,
 388        .poll           = hysdn_log_poll,
 389        .open           = hysdn_log_open,
 390        .release        = hysdn_log_close,                                        
 391};
 392
 393
 394/***********************************************************************************/
 395/* hysdn_proclog_init is called when the module is loaded after creating the cards */
 396/* conf files.                                                                     */
 397/***********************************************************************************/
 398int
 399hysdn_proclog_init(hysdn_card * card)
 400{
 401        struct procdata *pd;
 402
 403        /* create a cardlog proc entry */
 404
 405        if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
 406                sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
 407                pd->log = proc_create(pd->log_name,
 408                                S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry,
 409                                &log_fops);
 410
 411                init_waitqueue_head(&(pd->rd_queue));
 412
 413                card->proclog = (void *) pd;    /* remember procfs structure */
 414        }
 415        return (0);
 416}                               /* hysdn_proclog_init */
 417
 418/************************************************************************************/
 419/* hysdn_proclog_release is called when the module is unloaded and before the cards */
 420/* conf file is released                                                            */
 421/* The module counter is assumed to be 0 !                                          */
 422/************************************************************************************/
 423void
 424hysdn_proclog_release(hysdn_card * card)
 425{
 426        struct procdata *pd;
 427
 428        if ((pd = (struct procdata *) card->proclog) != NULL) {
 429                if (pd->log)
 430                        remove_proc_entry(pd->log_name, hysdn_proc_entry);
 431                kfree(pd);      /* release memory */
 432                card->proclog = NULL;
 433        }
 434}                               /* hysdn_proclog_release */
 435