1/* $Id: hysdn_proclog.c,v 1.1.1.1 2008/10/15 03:26:34 james26_jang 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 */ 24extern struct proc_dir_entry *hysdn_proc_entry; 25 26/*************************************************/ 27/* structure keeping ascii log for device output */ 28/*************************************************/ 29struct 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/**********************************************/ 39struct 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/**********************************************/ 53void 54hysdn_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/***************************************************/ 65void 66hysdn_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/********************************************/ 97void 98put_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/****************************************/ 152static ssize_t 153hysdn_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/******************/ 205static ssize_t 206hysdn_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 214 if (!*((struct log_data **) file->private_data)) { 215 if (file->f_flags & O_NONBLOCK) 216 return (-EAGAIN); 217 218 /* sorry, but we need to search the card */ 219 ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ 220 card = card_root; 221 while (card) { 222 pd = card->proclog; 223 if (pd->log->low_ino == ino) 224 break; 225 card = card->next; /* search next entry */ 226 } 227 if (card) 228 interruptible_sleep_on(&(pd->rd_queue)); 229 else 230 return (-EAGAIN); 231 232 } 233 if (!(inf = *((struct log_data **) file->private_data))) 234 return (0); 235 236 inf->usage_cnt--; /* new usage count */ 237 (struct log_data **) file->private_data = &inf->next; /* next structure */ 238 if ((len = strlen(inf->log_start)) <= count) { 239 if (copy_to_user(buf, inf->log_start, len)) 240 return -EFAULT; 241 file->f_pos += len; 242 return (len); 243 } 244 return (0); 245} /* hysdn_log_read */ 246 247/******************/ 248/* open log file */ 249/******************/ 250static int 251hysdn_log_open(struct inode *ino, struct file *filep) 252{ 253 hysdn_card *card; 254 struct procdata *pd = NULL; 255 ulong flags; 256 257 lock_kernel(); 258 card = card_root; 259 while (card) { 260 pd = card->proclog; 261 if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) 262 break; 263 card = card->next; /* search next entry */ 264 } 265 if (!card) { 266 unlock_kernel(); 267 return (-ENODEV); /* device is unknown/invalid */ 268 } 269 filep->private_data = card; /* remember our own card */ 270 271 if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { 272 /* write only access -> write log level only */ 273 } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { 274 275 /* read access -> log/debug read */ 276 save_flags(flags); 277 cli(); 278 pd->if_used++; 279 if (pd->log_head) 280 (struct log_data **) filep->private_data = &(pd->log_tail->next); 281 else 282 (struct log_data **) filep->private_data = &(pd->log_head); 283 restore_flags(flags); 284 } else { /* simultaneous read/write access forbidden ! */ 285 unlock_kernel(); 286 return (-EPERM); /* no permission this time */ 287 } 288 unlock_kernel(); 289 return (0); 290} /* hysdn_log_open */ 291 292/*******************************************************************************/ 293/* close a cardlog file. If the file has been opened for exclusive write it is */ 294/* assumed as pof data input and the pof loader is noticed about. */ 295/* Otherwise file is handled as log output. In this case the interface usage */ 296/* count is decremented and all buffers are noticed of closing. If this file */ 297/* was the last one to be closed, all buffers are freed. */ 298/*******************************************************************************/ 299static int 300hysdn_log_close(struct inode *ino, struct file *filep) 301{ 302 struct log_data *inf; 303 struct procdata *pd; 304 hysdn_card *card; 305 int flags, retval = 0; 306 307 308 lock_kernel(); 309 if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { 310 /* write only access -> write debug level written */ 311 retval = 0; /* success */ 312 } else { 313 /* read access -> log/debug read, mark one further file as closed */ 314 315 pd = NULL; 316 save_flags(flags); 317 cli(); 318 inf = *((struct log_data **) filep->private_data); /* get first log entry */ 319 if (inf) 320 pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ 321 else { 322 /* no info available -> search card */ 323 card = card_root; 324 while (card) { 325 pd = card->proclog; 326 if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) 327 break; 328 card = card->next; /* search next entry */ 329 } 330 if (card) 331 pd = card->proclog; /* pointer to procfs log */ 332 } 333 if (pd) 334 pd->if_used--; /* decrement interface usage count by one */ 335 336 while (inf) { 337 inf->usage_cnt--; /* decrement usage count for buffers */ 338 inf = inf->next; 339 } 340 restore_flags(flags); 341 342 if (pd) 343 if (pd->if_used <= 0) /* delete buffers if last file closed */ 344 while (pd->log_head) { 345 inf = pd->log_head; 346 pd->log_head = pd->log_head->next; 347 kfree(inf); 348 } 349 } /* read access */ 350 unlock_kernel(); 351 352 return (retval); 353} /* hysdn_log_close */ 354 355/*************************************************/ 356/* select/poll routine to be able using select() */ 357/*************************************************/ 358static unsigned int 359hysdn_log_poll(struct file *file, poll_table * wait) 360{ 361 unsigned int mask = 0; 362 word ino; 363 hysdn_card *card; 364 struct procdata *pd = NULL; 365 366 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) 367 return (mask); /* no polling for write supported */ 368 369 /* we need to search the card */ 370 ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ 371 card = card_root; 372 while (card) { 373 pd = card->proclog; 374 if (pd->log->low_ino == ino) 375 break; 376 card = card->next; /* search next entry */ 377 } 378 if (!card) 379 return (mask); /* card not found */ 380 381 poll_wait(file, &(pd->rd_queue), wait); 382 383 if (*((struct log_data **) file->private_data)) 384 mask |= POLLIN | POLLRDNORM; 385 386 return mask; 387} /* hysdn_log_poll */ 388 389/**************************************************/ 390/* table for log filesystem functions defined above. */ 391/**************************************************/ 392static struct file_operations log_fops = 393{ 394 llseek: no_llseek, 395 read: hysdn_log_read, 396 write: hysdn_log_write, 397 poll: hysdn_log_poll, 398 open: hysdn_log_open, 399 release: hysdn_log_close, 400}; 401 402 403/***********************************************************************************/ 404/* hysdn_proclog_init is called when the module is loaded after creating the cards */ 405/* conf files. */ 406/***********************************************************************************/ 407int 408hysdn_proclog_init(hysdn_card * card) 409{ 410 struct procdata *pd; 411 412 /* create a cardlog proc entry */ 413 414 if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { 415 memset(pd, 0, sizeof(struct procdata)); 416 sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); 417 if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { 418 pd->log->proc_fops = &log_fops; 419 pd->log->owner = THIS_MODULE; 420 } 421 422 init_waitqueue_head(&(pd->rd_queue)); 423 424 card->proclog = (void *) pd; /* remember procfs structure */ 425 } 426 return (0); 427} /* hysdn_proclog_init */ 428 429/************************************************************************************/ 430/* hysdn_proclog_release is called when the module is unloaded and before the cards */ 431/* conf file is released */ 432/* The module counter is assumed to be 0 ! */ 433/************************************************************************************/ 434void 435hysdn_proclog_release(hysdn_card * card) 436{ 437 struct procdata *pd; 438 439 if ((pd = (struct procdata *) card->proclog) != NULL) { 440 if (pd->log) 441 remove_proc_entry(pd->log_name, hysdn_proc_entry); 442 kfree(pd); /* release memory */ 443 card->proclog = NULL; 444 } 445} /* hysdn_proclog_release */ 446