OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [isdn/] [hysdn/] [hysdn_proclog.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.