2 * proc.c - proc file system functions for SJA1000 CAN driver.
4 * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
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.
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
40 * Send feedback to <socketcan-users@lists.berlios.de>
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>
50 #include <socketcan/can.h>
51 #include <socketcan/can/ioctl.h>
55 #include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
58 extern struct net_device *can_dev[];
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;
64 static int can_proc_read_stats(char *page, char **start, off_t off,
65 int count, int *eof, void *data)
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++) {
77 struct net_device *dev = can_dev[i];
78 struct can_priv *priv = netdev_priv(dev);
80 u8 stat = hw_readreg(dev->base_addr, REG_SR);
83 len += snprintf(page + len, PAGE_SIZE - len,
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);
91 len += snprintf(page + len, PAGE_SIZE - len,
92 "%s: bus status: OK, ",
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));
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,
122 static int can_proc_dump_regs(char *page, int len, struct net_device *dev)
125 struct can_priv *priv = netdev_priv(dev);
126 int regs = priv->hw_regs;
128 len += snprintf(page + len, PAGE_SIZE - len,
129 "%s registers:\n", dev->name);
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++) {
135 len += snprintf(page + len, PAGE_SIZE-len,
137 hw_readreg(dev->base_addr,
140 len += snprintf(page + len, PAGE_SIZE - len, "\n");
146 static int can_proc_read_regs(char *page, char **start, off_t off,
147 int count, int *eof, void *data)
152 for (i = 0; (i < MAXDEV) && (len < PAGE_SIZE - 200); i++) {
154 len = can_proc_dump_regs(page, len, can_dev[i]);
161 static int can_proc_read_reset(char *page, char **start, off_t off,
162 int count, int *eof, void *data)
165 struct net_device *dev;
167 struct can_priv *priv;
169 len += snprintf(page + len, PAGE_SIZE - len, "resetting ");
170 for (i = 0; (i < MAXDEV) && (len < PAGE_SIZE - 200); 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,
178 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
179 dev->netdev_ops->ndo_stop(dev);
180 dev->netdev_ops->ndo_open(dev);
185 /* count number of restarts */
186 priv->can_stats.restarts++;
189 len += snprintf(page + len, PAGE_SIZE - len,
190 "(%s|%d) ", dev->name,
196 len += snprintf(page + len, PAGE_SIZE - len, "done\n");
202 void can_proc_create(const char *drv_name)
207 sprintf(fname, PROCBASE "/%s_stats", drv_name);
208 pde = create_proc_read_entry(fname, 0644, NULL,
209 can_proc_read_stats, NULL);
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);
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);
223 void can_proc_remove(const char *drv_name)
228 sprintf(fname, PROCBASE "/%s_stats", drv_name);
229 remove_proc_entry(fname, NULL);
232 sprintf(fname, PROCBASE "/%s_regs", drv_name);
233 remove_proc_entry(fname, NULL);
236 sprintf(fname, PROCBASE "/%s_reset", drv_name);
237 remove_proc_entry(fname, NULL);