File: /usr/src/linux/drivers/isdn/hysdn/hysdn_proclog.c

1     /* $Id: hysdn_proclog.c,v 1.9.6.2 2001/08/13 07:46:15 kai Exp $
2     
3      * Linux driver for HYSDN cards, /proc/net filesystem log functions.
4      * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
5      *
6      * Copyright 1999  by Werner Cornelius (werner@titro.de)
7      *
8      * This program is free software; you can redistribute it and/or modify
9      * it under the terms of the GNU General Public License as published by
10      * the Free Software Foundation; either version 2, or (at your option)
11      * any later version.
12      *
13      * This program is distributed in the hope that it will be useful,
14      * but WITHOUT ANY WARRANTY; without even the implied warranty of
15      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16      * GNU General Public License for more details.
17      *
18      * You should have received a copy of the GNU General Public License
19      * along with this program; if not, write to the Free Software
20      * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21      *
22      */
23     
24     #define __NO_VERSION__
25     #include <linux/module.h>
26     #include <linux/version.h>
27     #include <linux/poll.h>
28     #include <linux/proc_fs.h>
29     #include <linux/pci.h>
30     #include <linux/smp_lock.h>
31     
32     #include "hysdn_defs.h"
33     
34     /* the proc subdir for the interface is defined in the procconf module */
35     extern struct proc_dir_entry *hysdn_proc_entry;
36     
37     /*************************************************/
38     /* structure keeping ascii log for device output */
39     /*************************************************/
40     struct log_data {
41     	struct log_data *next;
42     	ulong usage_cnt;	/* number of files still to work */
43     	void *proc_ctrl;	/* pointer to own control procdata structure */
44     	char log_start[2];	/* log string start (final len aligned by size) */
45     };
46     
47     /**********************************************/
48     /* structure holding proc entrys for one card */
49     /**********************************************/
50     struct procdata {
51     	struct proc_dir_entry *log;	/* log entry */
52     	char log_name[15];	/* log filename */
53     	struct log_data *log_head, *log_tail;	/* head and tail for queue */
54     	int if_used;		/* open count for interface */
55     	int volatile del_lock;	/* lock for delete operations */
56     	uchar logtmp[LOG_MAX_LINELEN];
57     	wait_queue_head_t rd_queue;
58     };
59     
60     
61     /**********************************************/
62     /* log function for cards error log interface */
63     /**********************************************/
64     void
65     hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
66     {
67     	char buf[ERRLOG_TEXT_SIZE + 40];
68     
69     	sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
70     	put_log_buffer(card, buf);	/* output the string */
71     }				/* hysdn_card_errlog */
72     
73     /***************************************************/
74     /* Log function using format specifiers for output */
75     /***************************************************/
76     void
77     hysdn_addlog(hysdn_card * card, char *fmt,...)
78     {
79     	struct procdata *pd = card->proclog;
80     	char *cp;
81     	va_list args;
82     
83     	if (!pd)
84     		return;		/* log structure non existent */
85     
86     	cp = pd->logtmp;
87     	cp += sprintf(cp, "HYSDN: card %d ", card->myid);
88     
89     	va_start(args, fmt);
90     	cp += vsprintf(cp, fmt, args);
91     	va_end(args);
92     	*cp++ = '\n';
93     	*cp = 0;
94     
95     	if (card->debug_flags & DEB_OUT_SYSLOG)
96     		printk(KERN_INFO "%s", pd->logtmp);
97     	else
98     		put_log_buffer(card, pd->logtmp);
99     
100     }				/* hysdn_addlog */
101     
102     /********************************************/
103     /* put an log buffer into the log queue.    */
104     /* This buffer will be kept until all files */
105     /* opened for read got the contents.        */
106     /* Flushes buffers not longer in use.       */
107     /********************************************/
108     void
109     put_log_buffer(hysdn_card * card, char *cp)
110     {
111     	struct log_data *ib;
112     	struct procdata *pd = card->proclog;
113     	int i, flags;
114     
115     	if (!pd)
116     		return;
117     	if (!cp)
118     		return;
119     	if (!*cp)
120     		return;
121     	if (pd->if_used <= 0)
122     		return;		/* no open file for read */
123     
124     	if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
125     		 return;	/* no memory */
126     	strcpy(ib->log_start, cp);	/* set output string */
127     	ib->next = NULL;
128     	ib->proc_ctrl = pd;	/* point to own control structure */
129     	save_flags(flags);
130     	cli();
131     	ib->usage_cnt = pd->if_used;
132     	if (!pd->log_head)
133     		pd->log_head = ib;	/* new head */
134     	else
135     		pd->log_tail->next = ib;	/* follows existing messages */
136     	pd->log_tail = ib;	/* new tail */
137     	i = pd->del_lock++;	/* get lock state */
138     	restore_flags(flags);
139     
140     	/* delete old entrys */
141     	if (!i)
142     		while (pd->log_head->next) {
143     			if ((pd->log_head->usage_cnt <= 0) &&
144     			    (pd->log_head->next->usage_cnt <= 0)) {
145     				ib = pd->log_head;
146     				pd->log_head = pd->log_head->next;
147     				kfree(ib);
148     			} else
149     				break;
150     		}		/* pd->log_head->next */
151     	pd->del_lock--;		/* release lock level */
152     	wake_up_interruptible(&(pd->rd_queue));		/* announce new entry */
153     }				/* put_log_buffer */
154     
155     
156     /******************************/
157     /* file operations and tables */
158     /******************************/
159     
160     /****************************************/
161     /* write log file -> set log level bits */
162     /****************************************/
163     static ssize_t
164     hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
165     {
166     	ulong u = 0;
167     	int found = 0;
168     	uchar *cp, valbuf[128];
169     	long base = 10;
170     	hysdn_card *card = (hysdn_card *) file->private_data;
171     
172     	if (&file->f_pos != off)	/* fs error check */
173     		return (-ESPIPE);
174     
175     	if (count > (sizeof(valbuf) - 1))
176     		count = sizeof(valbuf) - 1;	/* limit length */
177     	if (copy_from_user(valbuf, buf, count))
178     		return (-EFAULT);	/* copy failed */
179     
180     	valbuf[count] = 0;	/* terminating 0 */
181     	cp = valbuf;
182     	if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
183     		cp += 2;	/* pointer after hex modifier */
184     		base = 16;
185     	}
186     	/* scan the input for debug flags */
187     	while (*cp) {
188     		if ((*cp >= '0') && (*cp <= '9')) {
189     			found = 1;
190     			u *= base;	/* adjust to next digit */
191     			u += *cp++ - '0';
192     			continue;
193     		}
194     		if (base != 16)
195     			break;	/* end of number */
196     
197     		if ((*cp >= 'a') && (*cp <= 'f')) {
198     			found = 1;
199     			u *= base;	/* adjust to next digit */
200     			u += *cp++ - 'a' + 10;
201     			continue;
202     		}
203     		break;		/* terminated */
204     	}
205     
206     	if (found) {
207     		card->debug_flags = u;	/* remember debug flags */
208     		hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
209     	}
210     	return (count);
211     }				/* hysdn_log_write */
212     
213     /******************/
214     /* read log file */
215     /******************/
216     static ssize_t
217     hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
218     {
219     	struct log_data *inf;
220     	int len;
221     	word ino;
222     	struct procdata *pd = NULL;
223     	hysdn_card *card;
224     
225     	if (!*((struct log_data **) file->private_data)) {
226     		if (file->f_flags & O_NONBLOCK)
227     			return (-EAGAIN);
228     
229     		/* sorry, but we need to search the card */
230     		ino = file->f_dentry->d_inode->i_ino & 0xFFFF;	/* low-ino */
231     		card = card_root;
232     		while (card) {
233     			pd = card->proclog;
234     			if (pd->log->low_ino == ino)
235     				break;
236     			card = card->next;	/* search next entry */
237     		}
238     		if (card)
239     			interruptible_sleep_on(&(pd->rd_queue));
240     		else
241     			return (-EAGAIN);
242     
243     	}
244     	if (!(inf = *((struct log_data **) file->private_data)))
245     		return (0);
246     
247     	inf->usage_cnt--;	/* new usage count */
248     	(struct log_data **) file->private_data = &inf->next;	/* next structure */
249     	if ((len = strlen(inf->log_start)) <= count) {
250     		if (copy_to_user(buf, inf->log_start, len))
251     			return -EFAULT;
252     		file->f_pos += len;
253     		return (len);
254     	}
255     	return (0);
256     }				/* hysdn_log_read */
257     
258     /******************/
259     /* open log file */
260     /******************/
261     static int
262     hysdn_log_open(struct inode *ino, struct file *filep)
263     {
264     	hysdn_card *card;
265     	struct procdata *pd = NULL;
266     	ulong flags;
267     
268     	lock_kernel();
269     	card = card_root;
270     	while (card) {
271     		pd = card->proclog;
272     		if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
273     			break;
274     		card = card->next;	/* search next entry */
275     	}
276     	if (!card) {
277     		unlock_kernel();
278     		return (-ENODEV);	/* device is unknown/invalid */
279     	}
280     	filep->private_data = card;	/* remember our own card */
281     
282     	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
283     		/* write only access -> write log level only */
284     	} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
285     
286     		/* read access -> log/debug read */
287     		save_flags(flags);
288     		cli();
289     		pd->if_used++;
290     		if (pd->log_head)
291     			(struct log_data **) filep->private_data = &(pd->log_tail->next);
292     		else
293     			(struct log_data **) filep->private_data = &(pd->log_head);
294     		restore_flags(flags);
295     	} else {		/* simultaneous read/write access forbidden ! */
296     		unlock_kernel();
297     		return (-EPERM);	/* no permission this time */
298     	}
299     	unlock_kernel();
300     	return (0);
301     }				/* hysdn_log_open */
302     
303     /*******************************************************************************/
304     /* close a cardlog file. If the file has been opened for exclusive write it is */
305     /* assumed as pof data input and the pof loader is noticed about.              */
306     /* Otherwise file is handled as log output. In this case the interface usage   */
307     /* count is decremented and all buffers are noticed of closing. If this file   */
308     /* was the last one to be closed, all buffers are freed.                       */
309     /*******************************************************************************/
310     static int
311     hysdn_log_close(struct inode *ino, struct file *filep)
312     {
313     	struct log_data *inf;
314     	struct procdata *pd;
315     	hysdn_card *card;
316     	int flags, retval = 0;
317     
318     
319     	lock_kernel();
320     	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
321     		/* write only access -> write debug level written */
322     		retval = 0;	/* success */
323     	} else {
324     		/* read access -> log/debug read, mark one further file as closed */
325     
326     		pd = NULL;
327     		save_flags(flags);
328     		cli();
329     		inf = *((struct log_data **) filep->private_data);	/* get first log entry */
330     		if (inf)
331     			pd = (struct procdata *) inf->proc_ctrl;	/* still entries there */
332     		else {
333     			/* no info available -> search card */
334     			card = card_root;
335     			while (card) {
336     				pd = card->proclog;
337     				if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
338     					break;
339     				card = card->next;	/* search next entry */
340     			}
341     			if (card)
342     				pd = card->proclog;	/* pointer to procfs log */
343     		}
344     		if (pd)
345     			pd->if_used--;	/* decrement interface usage count by one */
346     
347     		while (inf) {
348     			inf->usage_cnt--;	/* decrement usage count for buffers */
349     			inf = inf->next;
350     		}
351     		restore_flags(flags);
352     
353     		if (pd)
354     			if (pd->if_used <= 0)	/* delete buffers if last file closed */
355     				while (pd->log_head) {
356     					inf = pd->log_head;
357     					pd->log_head = pd->log_head->next;
358     					kfree(inf);
359     				}
360     	}			/* read access */
361     	unlock_kernel();
362     
363     	return (retval);
364     }				/* hysdn_log_close */
365     
366     /*************************************************/
367     /* select/poll routine to be able using select() */
368     /*************************************************/
369     static unsigned int
370     hysdn_log_poll(struct file *file, poll_table * wait)
371     {
372     	unsigned int mask = 0;
373     	word ino;
374     	hysdn_card *card;
375     	struct procdata *pd = NULL;
376     
377     	if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
378     		return (mask);	/* no polling for write supported */
379     
380     	/* we need to search the card */
381     	ino = file->f_dentry->d_inode->i_ino & 0xFFFF;	/* low-ino */
382     	card = card_root;
383     	while (card) {
384     		pd = card->proclog;
385     		if (pd->log->low_ino == ino)
386     			break;
387     		card = card->next;	/* search next entry */
388     	}
389     	if (!card)
390     		return (mask);	/* card not found */
391     
392     	poll_wait(file, &(pd->rd_queue), wait);
393     
394     	if (*((struct log_data **) file->private_data))
395     		mask |= POLLIN | POLLRDNORM;
396     
397     	return mask;
398     }				/* hysdn_log_poll */
399     
400     /**************************************************/
401     /* table for log filesystem functions defined above. */
402     /**************************************************/
403     static struct file_operations log_fops =
404     {
405     	llseek:         no_llseek,
406     	read:           hysdn_log_read,
407     	write:          hysdn_log_write,
408     	poll:           hysdn_log_poll,
409     	open:           hysdn_log_open,
410     	release:        hysdn_log_close,                                        
411     };
412     
413     
414     /***********************************************************************************/
415     /* hysdn_proclog_init is called when the module is loaded after creating the cards */
416     /* conf files.                                                                     */
417     /***********************************************************************************/
418     int
419     hysdn_proclog_init(hysdn_card * card)
420     {
421     	struct procdata *pd;
422     
423     	/* create a cardlog proc entry */
424     
425     	if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
426     		memset(pd, 0, sizeof(struct procdata));
427     		sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
428     		if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
429     		        pd->log->proc_fops = &log_fops; 
430     		        pd->log->owner = THIS_MODULE;
431     		}
432     
433     		init_waitqueue_head(&(pd->rd_queue));
434     
435     		card->proclog = (void *) pd;	/* remember procfs structure */
436     	}
437     	return (0);
438     }				/* hysdn_proclog_init */
439     
440     /************************************************************************************/
441     /* hysdn_proclog_release is called when the module is unloaded and before the cards */
442     /* conf file is released                                                            */
443     /* The module counter is assumed to be 0 !                                          */
444     /************************************************************************************/
445     void
446     hysdn_proclog_release(hysdn_card * card)
447     {
448     	struct procdata *pd;
449     
450     	if ((pd = (struct procdata *) card->proclog) != NULL) {
451     		if (pd->log)
452     			remove_proc_entry(pd->log_name, hysdn_proc_entry);
453     		kfree(pd);	/* release memory */
454     		card->proclog = NULL;
455     	}
456     }				/* hysdn_proclog_release */
457