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