root/drivers/staging/isdn/hysdn/hysdn_proclog.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hysdn_card_errlog
  2. hysdn_addlog
  3. put_log_buffer
  4. hysdn_log_write
  5. hysdn_log_read
  6. hysdn_log_open
  7. hysdn_log_close
  8. hysdn_log_poll
  9. hysdn_proclog_init
  10. hysdn_proclog_release

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

/* [<][>][^][v][top][bottom][index][help] */