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