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