]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/drivers/net/can/old/sja1000/proc.c
merged branches/netlink in rev. 1037 back to trunk.
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / old / sja1000 / proc.c
1 /*
2  * proc.c -  proc file system functions for SJA1000 CAN driver.
3  *
4  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of Volkswagen nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * Alternatively, provided that this notice is retained in full, this
20  * software may be distributed under the terms of the GNU General
21  * Public License ("GPL") version 2, in which case the provisions of the
22  * GPL apply INSTEAD OF those given above.
23  *
24  * The provided data structures and external interfaces from this code
25  * are not restricted to be used by modules with a GPL compatible license.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  *
40  * Send feedback to <socketcan-users@lists.berlios.de>
41  *
42  */
43
44 #include <linux/module.h>
45 #include <linux/version.h>
46 #include <linux/slab.h>
47 #include <linux/proc_fs.h>
48 #include <linux/netdevice.h>
49
50 #include <socketcan/can.h>
51 #include <socketcan/can/ioctl.h>
52 #include "sja1000.h"
53 #include "hal.h"
54
55 #include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
56 RCSID("$Id$");
57
58 extern struct net_device *can_dev[];
59
60 static struct proc_dir_entry *pde       = NULL;
61 static struct proc_dir_entry *pde_regs  = NULL;
62 static struct proc_dir_entry *pde_reset = NULL;
63
64 static int can_proc_read_stats(char *page, char **start, off_t off,
65                                int count, int *eof, void *data)
66 {
67         int len = 0;
68         int i;
69
70         len += snprintf(page + len, PAGE_SIZE - len,
71                         "CAN bus device statistics:\n");
72         len += snprintf(page + len, PAGE_SIZE - len,
73                         "       errwarn  overrun   wakeup   buserr   "
74                         "errpass  arbitr   restarts clock        baud\n");
75         for (i = 0; (i < MAXDEV) && (len < PAGE_SIZE - 200); i++) {
76                 if (can_dev[i]) {
77                         struct net_device *dev = can_dev[i];
78                         struct can_priv *priv  = netdev_priv(dev);
79 #ifdef SJA1000_H
80                         u8 stat = hw_readreg(dev->base_addr, REG_SR);
81
82                         if (stat & 0x80) {
83                                 len += snprintf(page + len, PAGE_SIZE - len,
84                                                 "%s: bus status: "
85                                                 "BUS OFF, ", dev->name);
86                         } else if (stat & 0x40) {
87                                 len += snprintf(page + len, PAGE_SIZE - len,
88                                                 "%s: bus status: ERROR "
89                                                 "PASSIVE, ", dev->name);
90                         } else {
91                                 len += snprintf(page + len, PAGE_SIZE - len,
92                                                 "%s: bus status: OK, ",
93                                                 dev->name);
94                         }
95                         len += snprintf(page + len, PAGE_SIZE - len,
96                                         "RXERR: %d, TXERR: %d\n",
97                                         hw_readreg(dev->base_addr, REG_RXERR),
98                                         hw_readreg(dev->base_addr, REG_TXERR));
99 #endif
100                         len += snprintf(page + len, PAGE_SIZE - len,
101                                         "%s: %8d %8d %8d %8d %8d "
102                                         "%8d %8d %10d %8d\n", dev->name,
103                                         priv->can_stats.error_warning,
104                                         priv->can_stats.data_overrun,
105                                         priv->can_stats.wakeup,
106                                         priv->can_stats.bus_error,
107                                         priv->can_stats.error_passive,
108                                         priv->can_stats.arbitration_lost,
109                                         priv->can_stats.restarts,
110                                         priv->clock,
111                                         priv->speed
112                                 );
113
114                 }
115         }
116
117         *eof = 1;
118         return len;
119 }
120
121
122 static int can_proc_dump_regs(char *page, int len, struct net_device *dev)
123 {
124         int r,s;
125         struct can_priv *priv = netdev_priv(dev);
126         int regs = priv->hw_regs;
127
128         len += snprintf(page + len, PAGE_SIZE - len,
129                         "%s registers:\n", dev->name);
130
131         for (r = 0; r < regs; r += 0x10) {
132                 len += snprintf(page + len, PAGE_SIZE - len, "%02X: ", r);
133                 for (s = 0; s < 0x10; s++) {
134                         if (r+s < regs)
135                                 len += snprintf(page + len, PAGE_SIZE-len,
136                                                 "%02X ",
137                                                 hw_readreg(dev->base_addr,
138                                                            r+s));
139                 }
140                 len += snprintf(page + len, PAGE_SIZE - len, "\n");
141         }
142
143         return len;
144 }
145
146 static int can_proc_read_regs(char *page, char **start, off_t off,
147                                   int count, int *eof, void *data)
148 {
149         int len = 0;
150         int i;
151
152         for (i = 0; (i < MAXDEV) && (len < PAGE_SIZE - 200); i++) {
153                 if (can_dev[i])
154                         len = can_proc_dump_regs(page, len, can_dev[i]);
155         }
156
157         *eof = 1;
158         return len;
159 }
160
161 static int can_proc_read_reset(char *page, char **start, off_t off,
162                                    int count, int *eof, void *data)
163 {
164         int len = 0;
165         struct net_device *dev;
166         int i;
167         struct can_priv   *priv;
168
169         len += snprintf(page + len, PAGE_SIZE - len, "resetting ");
170         for (i = 0; (i < MAXDEV) && (len < PAGE_SIZE - 200); i++) {
171                 if (can_dev[i]) {
172                         dev = can_dev[i];
173                         priv = netdev_priv(can_dev[i]);
174                         if ((priv->state != STATE_UNINITIALIZED)
175                             && (priv->state != STATE_RESET_MODE)) {
176                                 len += snprintf(page + len, PAGE_SIZE - len,
177                                                 "%s ", dev->name);
178 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
179                                 dev->netdev_ops->ndo_stop(dev);
180                                 dev->netdev_ops->ndo_open(dev);
181 #else
182                                 dev->stop(dev);
183                                 dev->open(dev);
184 #endif
185                                 /* count number of restarts */
186                                 priv->can_stats.restarts++;
187
188                         } else {
189                                 len += snprintf(page + len, PAGE_SIZE - len,
190                                                 "(%s|%d) ", dev->name,
191                                                 priv->state);
192                         }
193                 }
194         }
195
196         len += snprintf(page + len, PAGE_SIZE - len, "done\n");
197
198         *eof = 1;
199         return len;
200 }
201
202 void can_proc_create(const char *drv_name)
203 {
204         char fname[256];
205
206         if (pde == NULL) {
207                 sprintf(fname, PROCBASE "/%s_stats", drv_name);
208                 pde = create_proc_read_entry(fname, 0644, NULL,
209                                              can_proc_read_stats, NULL);
210         }
211         if (pde_regs == NULL) {
212                 sprintf(fname, PROCBASE "/%s_regs", drv_name);
213                 pde_regs = create_proc_read_entry(fname, 0644, NULL,
214                                                   can_proc_read_regs, NULL);
215         }
216         if (pde_reset == NULL) {
217                 sprintf(fname, PROCBASE "/%s_reset", drv_name);
218                 pde_reset = create_proc_read_entry(fname, 0644, NULL,
219                                                    can_proc_read_reset, NULL);
220         }
221 }
222
223 void can_proc_remove(const char *drv_name)
224 {
225         char fname[256];
226
227         if (pde) {
228                 sprintf(fname, PROCBASE "/%s_stats", drv_name);
229                 remove_proc_entry(fname, NULL);
230         }
231         if (pde_regs) {
232                 sprintf(fname, PROCBASE "/%s_regs", drv_name);
233                 remove_proc_entry(fname, NULL);
234         }
235         if (pde_reset) {
236                 sprintf(fname, PROCBASE "/%s_reset", drv_name);
237                 remove_proc_entry(fname, NULL);
238         }
239 }