Merge branch 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/adobriyan...
[linux-2.6] / drivers / staging / epl / proc_fs.c
1 /****************************************************************************
2
3   (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4       www.systec-electronic.com
5
6   Project:      openPOWERLINK
7
8   Description:  proc fs entry with diagnostic information under Linux
9
10   License:
11
12     Redistribution and use in source and binary forms, with or without
13     modification, are permitted provided that the following conditions
14     are met:
15
16     1. Redistributions of source code must retain the above copyright
17        notice, this list of conditions and the following disclaimer.
18
19     2. Redistributions in binary form must reproduce the above copyright
20        notice, this list of conditions and the following disclaimer in the
21        documentation and/or other materials provided with the distribution.
22
23     3. Neither the name of SYSTEC electronic GmbH nor the names of its
24        contributors may be used to endorse or promote products derived
25        from this software without prior written permission. For written
26        permission, please contact info@systec-electronic.com.
27
28     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32     COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39     POSSIBILITY OF SUCH DAMAGE.
40
41     Severability Clause:
42
43         If a provision of this License is or becomes illegal, invalid or
44         unenforceable in any jurisdiction, that shall not affect:
45         1. the validity or enforceability in that jurisdiction of any other
46            provision of this License; or
47         2. the validity or enforceability in other jurisdictions of that or
48            any other provision of this License.
49
50   -------------------------------------------------------------------------
51
52                 $RCSfile: proc_fs.c,v $
53
54                 $Author: D.Krueger $
55
56                 $Revision: 1.13 $  $Date: 2008/11/07 13:55:56 $
57
58                 $State: Exp $
59
60                 Build Environment:
61                     GNU
62
63   -------------------------------------------------------------------------
64
65   Revision History:
66
67   2006/07/31 d.k.:   start of implementation
68
69 ****************************************************************************/
70
71 #include "kernel/EplNmtk.h"
72 #include "user/EplNmtu.h"
73
74 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
75 #include "user/EplNmtMnu.h"
76 #endif
77
78 #include "kernel/EplDllkCal.h"
79
80 //#include <linux/config.h>
81 #include <linux/module.h>
82 #include <linux/kernel.h>
83 #include <linux/init.h>
84 #include <linux/errno.h>
85 #include <linux/major.h>
86 #include <linux/version.h>
87 #include <asm/io.h>
88 #include <asm/uaccess.h>
89 #include <asm/atomic.h>
90 #include <linux/proc_fs.h>
91 #include <linux/spinlock.h>
92
93 #ifdef CONFIG_COLDFIRE
94 #include <asm/coldfire.h>
95 #include "fec.h"
96 #endif
97
98 /***************************************************************************/
99 /*                                                                         */
100 /*                                                                         */
101 /*          G L O B A L   D E F I N I T I O N S                            */
102 /*                                                                         */
103 /*                                                                         */
104 /***************************************************************************/
105
106 //---------------------------------------------------------------------------
107 // const defines
108 //---------------------------------------------------------------------------
109
110 #ifndef EPL_PROC_DEV_NAME
111 #define EPL_PROC_DEV_NAME    "epl"
112 #endif
113
114 #ifndef DBG_TRACE_POINTS
115 #define DBG_TRACE_POINTS    23  // # of supported debug trace points
116 #endif
117
118 #ifndef DBG_TRACE_VALUES
119 #define DBG_TRACE_VALUES    24  // # of supported debug trace values (size of circular buffer)
120 #endif
121
122 //---------------------------------------------------------------------------
123 // modul global types
124 //---------------------------------------------------------------------------
125
126 //---------------------------------------------------------------------------
127 // local vars
128 //---------------------------------------------------------------------------
129
130 #ifdef _DBG_TRACE_POINTS_
131 atomic_t aatmDbgTracePoint_l[DBG_TRACE_POINTS];
132 DWORD adwDbgTraceValue_l[DBG_TRACE_VALUES];
133 DWORD dwDbgTraceValueOld_l;
134 unsigned int uiDbgTraceValuePos_l;
135 spinlock_t spinlockDbgTraceValue_l;
136 unsigned long ulDbTraceValueFlags_l;
137 #endif
138
139 //---------------------------------------------------------------------------
140 // local function prototypes
141 //---------------------------------------------------------------------------
142
143 static int EplLinProcRead(char *pcBuffer_p, char **ppcStart_p, off_t Offset_p,
144                           int nBufferSize_p, int *pEof_p, void *pData_p);
145 static int EplLinProcWrite(struct file *file, const char __user * buffer,
146                            unsigned long count, void *data);
147
148 void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p);
149 void PUBLIC TgtDbgPostTraceValue(DWORD dwTraceValue_p);
150
151 EPLDLLEXPORT DWORD PUBLIC EplIdentuGetRunningRequests(void);
152
153 //=========================================================================//
154 //                                                                         //
155 //          P U B L I C   F U N C T I O N S                                //
156 //                                                                         //
157 //=========================================================================//
158
159 tEplKernel EplLinProcInit(void)
160 {
161         struct proc_dir_entry *pProcDirEntry;
162         pProcDirEntry = create_proc_entry(EPL_PROC_DEV_NAME, S_IRUGO, NULL);
163         if (pProcDirEntry != NULL) {
164                 pProcDirEntry->read_proc = EplLinProcRead;
165                 pProcDirEntry->write_proc = EplLinProcWrite;
166                 pProcDirEntry->data = NULL;     // device number or something else
167
168         } else {
169                 return kEplNoResource;
170         }
171
172 #ifdef _DBG_TRACE_POINTS_
173         // initialize spinlock and circular buffer position
174         spin_lock_init(&spinlockDbgTraceValue_l);
175         uiDbgTraceValuePos_l = 0;
176         dwDbgTraceValueOld_l = 0;
177 #endif
178
179         return kEplSuccessful;
180 }
181
182 tEplKernel EplLinProcFree(void)
183 {
184         remove_proc_entry(EPL_PROC_DEV_NAME, NULL);
185
186         return kEplSuccessful;
187 }
188
189 //---------------------------------------------------------------------------
190 //  Target specific event signaling (FEC Tx-/Rx-Interrupt, used by Edrv)
191 //---------------------------------------------------------------------------
192
193 #ifdef _DBG_TRACE_POINTS_
194 void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p)
195 {
196
197         if (bTracePointNumber_p >=
198             (sizeof(aatmDbgTracePoint_l) / sizeof(aatmDbgTracePoint_l[0]))) {
199                 goto Exit;
200         }
201
202         atomic_inc(&aatmDbgTracePoint_l[bTracePointNumber_p]);
203
204       Exit:
205
206         return;
207
208 }
209
210 void PUBLIC TgtDbgPostTraceValue(DWORD dwTraceValue_p)
211 {
212
213         spin_lock_irqsave(&spinlockDbgTraceValue_l, ulDbTraceValueFlags_l);
214         if (dwDbgTraceValueOld_l != dwTraceValue_p) {
215                 adwDbgTraceValue_l[uiDbgTraceValuePos_l] = dwTraceValue_p;
216                 uiDbgTraceValuePos_l =
217                     (uiDbgTraceValuePos_l + 1) % DBG_TRACE_VALUES;
218                 dwDbgTraceValueOld_l = dwTraceValue_p;
219         }
220         spin_unlock_irqrestore(&spinlockDbgTraceValue_l, ulDbTraceValueFlags_l);
221
222         return;
223
224 }
225 #endif
226
227 //---------------------------------------------------------------------------
228 //  Read function for PROC-FS read access
229 //---------------------------------------------------------------------------
230
231 static int EplLinProcRead(char *pcBuffer_p,
232                           char **ppcStart_p,
233                           off_t Offset_p,
234                           int nBufferSize_p, int *pEof_p, void *pData_p)
235 {
236
237         int nSize;
238         int Eof;
239         tEplDllkCalStatistics *pDllkCalStats;
240
241         nSize = 0;
242         Eof = 0;
243
244         // count calls of this function
245 #ifdef _DBG_TRACE_POINTS_
246         TgtDbgSignalTracePoint(0);
247 #endif
248
249         //---------------------------------------------------------------
250         // generate static information
251         //---------------------------------------------------------------
252
253         // ---- Driver information ----
254         nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
255                           "%s    %s    (c) 2006 %s\n",
256                           EPL_PRODUCT_NAME, EPL_PRODUCT_VERSION,
257                           EPL_PRODUCT_MANUFACTURER);
258
259         //---------------------------------------------------------------
260         // generate process information
261         //---------------------------------------------------------------
262
263         // ---- EPL state ----
264         nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
265                           "NMT state:                  0x%04X\n",
266                           (WORD) EplNmtkGetNmtState());
267
268         EplDllkCalGetStatistics(&pDllkCalStats);
269
270         nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
271                           "CurAsyncTxGen=%lu CurAsyncTxNmt=%lu CurAsyncRx=%lu\nMaxAsyncTxGen=%lu MaxAsyncTxNmt=%lu MaxAsyncRx=%lu\n",
272                           pDllkCalStats->m_ulCurTxFrameCountGen,
273                           pDllkCalStats->m_ulCurTxFrameCountNmt,
274                           pDllkCalStats->m_ulCurRxFrameCount,
275                           pDllkCalStats->m_ulMaxTxFrameCountGen,
276                           pDllkCalStats->m_ulMaxTxFrameCountNmt,
277                           pDllkCalStats->m_ulMaxRxFrameCount);
278
279 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
280         // fetch running IdentRequests
281         nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
282                           "running IdentRequests:      0x%08lX\n",
283                           EplIdentuGetRunningRequests());
284
285         // fetch state of NmtMnu module
286         {
287                 unsigned int uiMandatorySlaveCount;
288                 unsigned int uiSignalSlaveCount;
289                 WORD wFlags;
290
291                 EplNmtMnuGetDiagnosticInfo(&uiMandatorySlaveCount,
292                                            &uiSignalSlaveCount, &wFlags);
293
294                 nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
295                                   "MN  MandSlaveCount: %u  SigSlaveCount: %u  Flags: 0x%X\n",
296                                   uiMandatorySlaveCount, uiSignalSlaveCount,
297                                   wFlags);
298
299         }
300 #endif
301
302         // ---- FEC state ----
303 #ifdef CONFIG_COLDFIRE
304         {
305                 // Receive the base address
306                 unsigned long base_addr;
307 #if (EDRV_USED_ETH_CTRL == 0)
308                 // Set the base address of FEC0
309                 base_addr = FEC_BASE_ADDR_FEC0;
310 #else
311                 // Set the base address of FEC1
312                 base_addr = FEC_BASE_ADDR_FEC1;
313 #endif
314
315                 nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
316                                   "FEC_ECR = 0x%08X FEC_EIR = 0x%08X FEC_EIMR = 0x%08X\nFEC_TCR = 0x%08X FECTFSR = 0x%08X FECRFSR = 0x%08X\n",
317                                   FEC_ECR(base_addr), FEC_EIR(base_addr),
318                                   FEC_EIMR(base_addr), FEC_TCR(base_addr),
319                                   FEC_FECTFSR(base_addr),
320                                   FEC_FECRFSR(base_addr));
321         }
322 #endif
323
324         // ---- DBG: TracePoints ----
325 #ifdef _DBG_TRACE_POINTS_
326         {
327                 int nNum;
328
329                 nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
330                                   "DbgTracePoints:\n");
331                 for (nNum = 0;
332                      nNum < (sizeof(aatmDbgTracePoint_l) / sizeof(atomic_t));
333                      nNum++) {
334                         nSize +=
335                             snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
336                                      " TracePoint[%2d]: %d\n", (int)nNum,
337                                      atomic_read(&aatmDbgTracePoint_l[nNum]));
338                 }
339
340                 nSize += snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
341                                   "DbgTraceValues:\n");
342                 for (nNum = 0; nNum < DBG_TRACE_VALUES; nNum++) {
343                         if (nNum == uiDbgTraceValuePos_l) {     // next value will be stored at that position
344                                 nSize +=
345                                     snprintf(pcBuffer_p + nSize,
346                                              nBufferSize_p - nSize, "*%08lX",
347                                              adwDbgTraceValue_l[nNum]);
348                         } else {
349                                 nSize +=
350                                     snprintf(pcBuffer_p + nSize,
351                                              nBufferSize_p - nSize, " %08lX",
352                                              adwDbgTraceValue_l[nNum]);
353                         }
354                         if ((nNum & 0x00000007) == 0x00000007) {        // 8 values printed -> end of line reached
355                                 nSize +=
356                                     snprintf(pcBuffer_p + nSize,
357                                              nBufferSize_p - nSize, "\n");
358                         }
359                 }
360                 if ((nNum & 0x00000007) != 0x00000007) {        // number of values printed is not a multiple of 8 -> print new line
361                         nSize +=
362                             snprintf(pcBuffer_p + nSize, nBufferSize_p - nSize,
363                                      "\n");
364                 }
365         }
366 #endif
367
368         Eof = 1;
369         goto Exit;
370
371       Exit:
372
373         *pEof_p = Eof;
374
375         return (nSize);
376
377 }
378
379 //---------------------------------------------------------------------------
380 //  Write function for PROC-FS write access
381 //---------------------------------------------------------------------------
382
383 static int EplLinProcWrite(struct file *file, const char __user * buffer,
384                            unsigned long count, void *data)
385 {
386         char abBuffer[count + 1];
387         int iErr;
388         int iVal = 0;
389         tEplNmtEvent NmtEvent;
390
391         if (count > 0) {
392                 iErr = copy_from_user(abBuffer, buffer, count);
393                 if (iErr != 0) {
394                         return count;
395                 }
396                 abBuffer[count] = '\0';
397
398                 iErr = sscanf(abBuffer, "%i", &iVal);
399         }
400         if ((iVal <= 0) || (iVal > 0x2F)) {
401                 NmtEvent = kEplNmtEventSwReset;
402         } else {
403                 NmtEvent = (tEplNmtEvent) iVal;
404         }
405         // execute specified NMT command on write access of /proc/epl
406         EplNmtuNmtEvent(NmtEvent);
407
408         return count;
409 }