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