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        unsigned long u = 0;
 159        int rc;
 160        unsigned char valbuf[128];
 161        hysdn_card *card = file->private_data;
 162
 163        if (count > (sizeof(valbuf) - 1))
 164                count = sizeof(valbuf) - 1;     /* limit length */
 165        if (copy_from_user(valbuf, buf, count))
 166                return (-EFAULT);       /* copy failed */
 167
 168        valbuf[count] = 0;      /* terminating 0 */
 169
 170        rc = strict_strtoul(valbuf, 0, &u);
 171
 172        if (rc == 0) {
 173                card->debug_flags = u;  /* remember debug flags */
 174                hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
 175        }
 176        return (count);
 177}                               /* hysdn_log_write */
 178
 179/******************/
 180/* read log file */
 181/******************/
 182static ssize_t
 183hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t * off)
 184{
 185        struct log_data *inf;
 186        int len;
 187        struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
 188        struct procdata *pd = NULL;
 189        hysdn_card *card;
 190
 191        if (!*((struct log_data **) file->private_data)) {
 192                if (file->f_flags & O_NONBLOCK)
 193                        return (-EAGAIN);
 194
 195                /* sorry, but we need to search the card */
 196                card = card_root;
 197                while (card) {
 198                        pd = card->proclog;
 199                        if (pd->log == pde)
 200                                break;
 201                        card = card->next;      /* search next entry */
 202                }
 203                if (card)
 204                        interruptible_sleep_on(&(pd->rd_queue));
 205                else
 206                        return (-EAGAIN);
 207
 208        }
 209        if (!(inf = *((struct log_data **) file->private_data)))
 210                return (0);
 211
 212        inf->usage_cnt--;       /* new usage count */
 213        file->private_data = &inf->next;        /* next structure */
 214        if ((len = strlen(inf->log_start)) <= count) {
 215                if (copy_to_user(buf, inf->log_start, len))
 216                        return -EFAULT;
 217                *off += len;
 218                return (len);
 219        }
 220        return (0);
 221}                               /* hysdn_log_read */
 222
 223/******************/
 224/* open log file */
 225/******************/
 226static int
 227hysdn_log_open(struct inode *ino, struct file *filep)
 228{
 229        hysdn_card *card;
 230        struct procdata *pd = NULL;
 231        unsigned long flags;
 232
 233        mutex_lock(&hysdn_log_mutex);
 234        card = card_root;
 235        while (card) {
 236                pd = card->proclog;
 237                if (pd->log == PDE(ino))
 238                        break;
 239                card = card->next;      /* search next entry */
 240        }
 241        if (!card) {
 242                mutex_unlock(&hysdn_log_mutex);
 243                return (-ENODEV);       /* device is unknown/invalid */
 244        }
 245        filep->private_data = card;     /* remember our own card */
 246
 247        if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 248                /* write only access -> write log level only */
 249        } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
 250
 251                /* read access -> log/debug read */
 252                spin_lock_irqsave(&card->hysdn_lock, flags);
 253                pd->if_used++;
 254                if (pd->log_head)
 255                        filep->private_data = &pd->log_tail->next;
 256                else
 257                        filep->private_data = &pd->log_head;
 258                spin_unlock_irqrestore(&card->hysdn_lock, flags);
 259        } else {                /* simultaneous read/write access forbidden ! */
 260                mutex_unlock(&hysdn_log_mutex);
 261                return (-EPERM);        /* no permission this time */
 262        }
 263        mutex_unlock(&hysdn_log_mutex);
 264        return nonseekable_open(ino, filep);
 265}                               /* hysdn_log_open */
 266
 267/*******************************************************************************/
 268/* close a cardlog file. If the file has been opened for exclusive write it is */
 269/* assumed as pof data input and the pof loader is noticed about.              */
 270/* Otherwise file is handled as log output. In this case the interface usage   */
 271/* count is decremented and all buffers are noticed of closing. If this file   */
 272/* was the last one to be closed, all buffers are freed.                       */
 273/*******************************************************************************/
 274static int
 275hysdn_log_close(struct inode *ino, struct file *filep)
 276{
 277        struct log_data *inf;
 278        struct procdata *pd;
 279        hysdn_card *card;
 280        int retval = 0;
 281
 282        mutex_lock(&hysdn_log_mutex);
 283        if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 284                /* write only access -> write debug level written */
 285                retval = 0;     /* success */
 286        } else {
 287                /* read access -> log/debug read, mark one further file as closed */
 288
 289                pd = NULL;
 290                inf = *((struct log_data **) filep->private_data);      /* get first log entry */
 291                if (inf)
 292                        pd = (struct procdata *) inf->proc_ctrl;        /* still entries there */
 293                else {
 294                        /* no info available -> search card */
 295                        card = card_root;
 296                        while (card) {
 297                                pd = card->proclog;
 298                                if (pd->log == PDE(ino))
 299                                        break;
 300                                card = card->next;      /* search next entry */
 301                        }
 302                        if (card)
 303                                pd = card->proclog;     /* pointer to procfs log */
 304                }
 305                if (pd)
 306                        pd->if_used--;  /* decrement interface usage count by one */
 307
 308                while (inf) {
 309                        inf->usage_cnt--;       /* decrement usage count for buffers */
 310                        inf = inf->next;
 311                }
 312
 313                if (pd)
 314                        if (pd->if_used <= 0)   /* delete buffers if last file closed */
 315                                while (pd->log_head) {
 316                                        inf = pd->log_head;
 317                                        pd->log_head = pd->log_head->next;
 318                                        kfree(inf);
 319                                }
 320        }                       /* read access */
 321        mutex_unlock(&hysdn_log_mutex);
 322
 323        return (retval);
 324}                               /* hysdn_log_close */
 325
 326/*************************************************/
 327/* select/poll routine to be able using select() */
 328/*************************************************/
 329static unsigned int
 330hysdn_log_poll(struct file *file, poll_table * wait)
 331{
 332        unsigned int mask = 0;
 333        struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
 334        hysdn_card *card;
 335        struct procdata *pd = NULL;
 336
 337        if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
 338                return (mask);  /* no polling for write supported */
 339
 340        /* we need to search the card */
 341        card = card_root;
 342        while (card) {
 343                pd = card->proclog;
 344                if (pd->log == pde)
 345                        break;
 346                card = card->next;      /* search next entry */
 347        }
 348        if (!card)
 349                return (mask);  /* card not found */
 350
 351        poll_wait(file, &(pd->rd_queue), wait);
 352
 353        if (*((struct log_data **) file->private_data))
 354                mask |= POLLIN | POLLRDNORM;
 355
 356        return mask;
 357}                               /* hysdn_log_poll */
 358
 359/**************************************************/
 360/* table for log filesystem functions defined above. */
 361/**************************************************/
 362static const struct file_operations log_fops =
 363{
 364        .owner          = THIS_MODULE,
 365        .llseek         = no_llseek,
 366        .read           = hysdn_log_read,
 367        .write          = hysdn_log_write,
 368        .poll           = hysdn_log_poll,
 369        .open           = hysdn_log_open,
 370        .release        = hysdn_log_close,                                        
 371};
 372
 373
 374/***********************************************************************************/
 375/* hysdn_proclog_init is called when the module is loaded after creating the cards */
 376/* conf files.                                                                     */
 377/***********************************************************************************/
 378int
 379hysdn_proclog_init(hysdn_card * card)
 380{
 381        struct procdata *pd;
 382
 383        /* create a cardlog proc entry */
 384
 385        if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
 386                sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
 387                pd->log = proc_create(pd->log_name,
 388                                S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry,
 389                                &log_fops);
 390
 391                init_waitqueue_head(&(pd->rd_queue));
 392
 393                card->proclog = (void *) pd;    /* remember procfs structure */
 394        }
 395        return (0);
 396}                               /* hysdn_proclog_init */
 397
 398/************************************************************************************/
 399/* hysdn_proclog_release is called when the module is unloaded and before the cards */
 400/* conf file is released                                                            */
 401/* The module counter is assumed to be 0 !                                          */
 402/************************************************************************************/
 403void
 404hysdn_proclog_release(hysdn_card * card)
 405{
 406        struct procdata *pd;
 407
 408        if ((pd = (struct procdata *) card->proclog) != NULL) {
 409                if (pd->log)
 410                        remove_proc_entry(pd->log_name, hysdn_proc_entry);
 411                kfree(pd);      /* release memory */
 412                card->proclog = NULL;
 413        }
 414}                               /* hysdn_proclog_release */
 415