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