1 /* $Id: hysdn_procfs.c,v 1.1 2000/02/10 19:45:18 werner Exp $
3 * Linux driver for HYSDN cards, /proc/net filesystem log functions.
4 * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
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)
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.
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.
22 * $Log: hysdn_procfs.c,v $
23 * Revision 1.1 2000/02/10 19:45:18 werner
30 #define __NO_VERSION__
31 #include <linux/module.h>
32 #include <linux/version.h>
33 #include <linux/poll.h>
34 #include <linux/proc_fs.h>
35 #include <linux/pci.h>
37 #include "hysdn_defs.h"
39 static char *hysdn_procfs_revision
= "$Revision: 1.1 $";
41 #define INFO_OUT_LEN 80 /* length of info line including lf */
43 /*************************************************/
44 /* structure keeping ascii log for device output */
45 /*************************************************/
47 struct log_data
*next
;
48 ulong usage_cnt
; /* number of files still to work */
49 void *proc_ctrl
; /* pointer to own control procdata structure */
50 char log_start
[2]; /* log string start (final len aligned by size) */
53 /**********************************************/
54 /* structure holding proc entrys for one card */
55 /**********************************************/
57 struct proc_dir_entry
*log
; /* log entry */
58 char log_name
[15]; /* log filename */
59 struct log_data
*log_head
, *log_tail
; /* head and tail for queue */
60 int if_used
; /* open count for interface */
61 wait_queue_head_t rd_queue
;
64 /********************************************/
65 /* put an log buffer into the log queue. */
66 /* This buffer will be kept until all files */
67 /* opened for read got the contents. */
68 /* Flushes buffers not longer in use. */
69 /********************************************/
71 put_log_buffer(hysdn_card
* card
, char *cp
)
74 struct procdata
*pd
= card
->procfs
;
84 return; /* no open file for read */
86 if (!(ib
= (struct log_data
*) kmalloc(sizeof(struct log_data
) + strlen(cp
), GFP_ATOMIC
)))
87 return; /* no memory */
88 strcpy(ib
->log_start
, cp
); /* set output string */
90 ib
->proc_ctrl
= pd
; /* point to own control structure */
93 ib
->usage_cnt
= pd
->if_used
;
95 pd
->log_head
= ib
; /* new head */
97 pd
->log_tail
->next
= ib
; /* follows existing messages */
98 pd
->log_tail
= ib
; /* new tail */
101 /* delete old entrys */
102 while (pd
->log_head
->next
) {
103 if ((pd
->log_head
->usage_cnt
<= 0) &&
104 (pd
->log_head
->next
->usage_cnt
<= 0)) {
106 pd
->log_head
= pd
->log_head
->next
;
110 } /* pd->log_head->next */
111 wake_up_interruptible(&(pd
->rd_queue
)); /* announce new entry */
112 } /* put_log_buffer */
115 /*************************/
116 /* dummy file operations */
117 /*************************/
119 hysdn_dummy_lseek(struct file
*file
, loff_t offset
, int orig
)
122 } /* hysdn_dummy_lseek */
124 /**********************************/
125 /* log file operations and tables */
126 /**********************************/
128 /****************************************/
129 /* write log file -> set log level bits */
130 /****************************************/
132 hysdn_log_write(struct file
*file
, const char *buf
, size_t count
, loff_t
* off
)
135 hysdn_card
*card
= (hysdn_card
*) file
->private_data
;
137 if (&file
->f_pos
!= off
) /* fs error check */
140 if ((retval
= pof_boot_write(card
, buf
, count
)) < 0)
141 retval
= -EFAULT
; /* an error occured */
144 } /* hysdn_log_write */
150 hysdn_log_read(struct file
*file
, char *buf
, size_t count
, loff_t
* off
)
152 struct log_data
*inf
;
158 if (!*((struct log_data
**) file
->private_data
)) {
159 if (file
->f_flags
& O_NONBLOCK
)
162 /* sorry, but we need to search the card */
163 ino
= file
->f_dentry
->d_inode
->i_ino
& 0xFFFF; /* low-ino */
167 if (pd
->log
->low_ino
== ino
)
169 card
= card
->next
; /* search next entry */
172 interruptible_sleep_on(&(pd
->rd_queue
));
177 if (!(inf
= *((struct log_data
**) file
->private_data
)))
180 inf
->usage_cnt
--; /* new usage count */
181 (struct log_data
**) file
->private_data
= &inf
->next
; /* next structure */
182 if ((len
= strlen(inf
->log_start
)) <= count
) {
183 if (copy_to_user(buf
, inf
->log_start
, len
))
189 } /* hysdn_log_read */
195 hysdn_log_open(struct inode
*ino
, struct file
*filep
)
201 MOD_INC_USE_COUNT
; /* lock module */
205 if (pd
->log
->low_ino
== (ino
->i_ino
& 0xFFFF))
207 card
= card
->next
; /* search next entry */
210 MOD_DEC_USE_COUNT
; /* unlock module */
211 return (-ENODEV
); /* device is unknown/invalid */
213 filep
->private_data
= card
; /* remember our own card */
215 if ((filep
->f_mode
& (FMODE_READ
| FMODE_WRITE
)) == FMODE_WRITE
) {
216 /* write only access -> boot pof data */
217 if (pof_boot_open(card
)) {
218 MOD_DEC_USE_COUNT
; /* unlock module */
219 return (-EPERM
); /* no permission this time */
221 } else if ((filep
->f_mode
& (FMODE_READ
| FMODE_WRITE
)) == FMODE_READ
) {
223 /* read access -> log/debug read */
228 (struct log_data
**) filep
->private_data
= &(pd
->log_tail
->next
);
230 (struct log_data
**) filep
->private_data
= &(pd
->log_head
);
231 restore_flags(flags
);
233 } else { /* simultaneous read/write access forbidden ! */
234 MOD_DEC_USE_COUNT
; /* unlock module */
235 return (-EPERM
); /* no permission this time */
238 } /* hysdn_log_open */
240 /*******************************************************************************/
241 /* close a cardlog file. If the file has been opened for exclusive write it is */
242 /* assumed as pof data input and the pof loader is noticed about. */
243 /* Otherwise file is handled as log output. In this case the interface usage */
244 /* count is decremented and all buffers are noticed of closing. If this file */
245 /* was the last one to be closed, all buffers are freed. */
246 /*******************************************************************************/
248 hysdn_log_close(struct inode
*ino
, struct file
*filep
)
250 struct log_data
*inf
;
253 int flags
, retval
= 0;
256 if ((filep
->f_mode
& (FMODE_READ
| FMODE_WRITE
)) == FMODE_WRITE
) {
257 /* write only access -> write debug completely written */
258 retval
= 0; /* success */
260 /* read access -> log/debug read, mark one further file as closed */
265 inf
= *((struct log_data
**) filep
->private_data
); /* get first log entry */
267 pd
= (struct procdata
*) inf
->proc_ctrl
; /* still entries there */
269 /* no info available -> search card */
273 if (pd
->log
->low_ino
== (ino
->i_ino
& 0xFFFF))
275 card
= card
->next
; /* search next entry */
278 pd
= card
->procfs
; /* pointer to procfs ctrl */
281 pd
->if_used
--; /* decrement interface usage count by one */
284 inf
->usage_cnt
--; /* decrement usage count for buffers */
287 restore_flags(flags
);
290 if (pd
->if_used
<= 0) /* delete buffers if last file closed */
291 while (pd
->log_head
) {
293 pd
->log_head
= pd
->log_head
->next
;
300 } /* hysdn_log_close */
302 /*************************************************/
303 /* select/poll routine to be able using select() */
304 /*************************************************/
306 hysdn_log_poll(struct file
*file
, poll_table
* wait
)
308 unsigned int mask
= 0;
313 if ((file
->f_mode
& (FMODE_READ
| FMODE_WRITE
)) == FMODE_WRITE
)
314 return (mask
); /* no polling for write supported */
316 /* we need to search the card */
317 ino
= file
->f_dentry
->d_inode
->i_ino
& 0xFFFF; /* low-ino */
321 if (pd
->log
->low_ino
== ino
)
323 card
= card
->next
; /* search next entry */
326 return (mask
); /* card not found */
328 poll_wait(file
, &(pd
->rd_queue
), wait
);
330 if (*((struct log_data
**) file
->private_data
))
331 mask
|= POLLIN
| POLLRDNORM
;
334 } /* hysdn_log_poll */
336 /**************************************************/
337 /* table for log filesystem functions defined above. */
338 /**************************************************/
339 static struct file_operations log_fops
=
345 hysdn_log_poll
, /* poll */
346 NULL
, /*hysdn_log_ioctl, *//* ioctl */
354 struct inode_operations log_inode_operations
=
356 &log_fops
, /* log proc file-ops */
367 NULL
, /* follow_link */
369 NULL
, /* writepage */
372 NULL
/* permission */
375 /*****************************************/
376 /* Output info data to the cardinfo file */
377 /*****************************************/
379 info_read(char *buffer
, char **start
, off_t offset
, int length
, int *eof
, void *data
)
381 char tmp
[INFO_OUT_LEN
* 11 + 2];
386 sprintf(tmp
, "id bus slot type irq iobase plx-mem dp-mem boot device");
387 cp
= tmp
; /* start of string */
390 while (((cp
- tmp
) % (INFO_OUT_LEN
+ 1)) != INFO_OUT_LEN
)
394 card
= card_root
; /* start of list */
396 sprintf(cp
, "%d %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x",
399 PCI_SLOT(card
->devfn
),
408 while (((cp
- tmp
) % (INFO_OUT_LEN
+ 1)) != INFO_OUT_LEN
)
415 if (offset
+ length
> i
) {
418 } else if (offset
> i
) {
425 /* start_bh_atomic(); */
426 memcpy(buffer
, cp
, length
);
427 /* end_bh_atomic(); */
433 /*****************************/
434 /* hysdn subdir in /proc/net */
435 /*****************************/
436 static struct proc_dir_entry
*hysdn_proc_entry
= NULL
;
437 static struct proc_dir_entry
*hysdn_info_entry
= NULL
;
439 /***************************************************************************************/
440 /* hysdn_procfs_init is called when the module is loaded and after the cards have been */
441 /* detected. The needed proc dir and card entries are created. */
442 /***************************************************************************************/
444 hysdn_procfs_init(void)
449 hysdn_proc_entry
= create_proc_entry(PROC_SUBDIR_NAME
, S_IFDIR
| S_IRUGO
| S_IXUGO
, proc_net
);
450 if (!hysdn_proc_entry
) {
451 printk(KERN_ERR
"HYSDN: unable to create hysdn subdir\n");
454 hysdn_info_entry
= create_proc_entry("cardinfo", 0, hysdn_proc_entry
);
455 if (hysdn_info_entry
)
456 hysdn_info_entry
->read_proc
= info_read
; /* read info function */
458 /* create all cardlog proc entries */
460 card
= card_root
; /* start with first card */
462 if ((pd
= (struct procdata
*) kmalloc(sizeof(struct procdata
), GFP_KERNEL
)) != NULL
) {
463 memset(pd
, 0, sizeof(struct procdata
));
465 sprintf(pd
->log_name
, "%s%d", PROC_LOG_BASENAME
, card
->myid
);
466 if ((pd
->log
= create_proc_entry(pd
->log_name
, S_IFREG
| S_IRUGO
| S_IWUSR
, hysdn_proc_entry
)) != NULL
)
467 pd
->log
->ops
= &log_inode_operations
; /* set new operations table */
469 init_waitqueue_head(&(pd
->rd_queue
));
471 card
->procfs
= (void *) pd
; /* remember procfs structure */
473 card
= card
->next
; /* point to next card */
476 printk(KERN_NOTICE
"HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision
));
478 } /* hysdn_procfs_init */
480 /***************************************************************************************/
481 /* hysdn_procfs_release is called when the module is unloaded and before the cards */
482 /* resources are released. The module counter is assumed to be 0 ! */
483 /***************************************************************************************/
485 hysdn_procfs_release(void)
490 card
= card_root
; /* start with first card */
492 if ((pd
= (struct procdata
*) card
->procfs
) != NULL
) {
494 remove_proc_entry(pd
->log_name
, hysdn_proc_entry
);
495 kfree(pd
); /* release memory */
497 card
= card
->next
; /* point to next card */
500 remove_proc_entry("cardinfo", hysdn_proc_entry
);
501 remove_proc_entry(PROC_SUBDIR_NAME
, proc_net
);
502 } /* hysdn_procfs_release */