Commit | Line | Data |
---|---|---|
50ee11fe BB |
1 | /* Copyright (C) 2004-2005 SBE, Inc. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License as published by | |
5 | * the Free Software Foundation; either version 2 of the License, or | |
6 | * (at your option) any later version. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | */ | |
13 | ||
e6e4d05d JP |
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
15 | ||
50ee11fe BB |
16 | #include <linux/types.h> |
17 | #include <linux/module.h> | |
18 | #include <linux/errno.h> | |
19 | #include <linux/kernel.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/proc_fs.h> | |
22 | #include <linux/sched.h> | |
23 | #include <asm/uaccess.h> | |
24 | #include "pmcc4_sysdep.h" | |
25 | #include "sbecom_inline_linux.h" | |
26 | #include "pmcc4_private.h" | |
27 | #include "sbeproc.h" | |
28 | ||
29 | /* forwards */ | |
30 | void sbecom_get_brdinfo (ci_t *, struct sbe_brd_info *, u_int8_t *); | |
31 | extern struct s_hdw_info hdw_info[MAX_BOARDS]; | |
32 | ||
33 | #ifdef CONFIG_PROC_FS | |
34 | ||
35 | /********************************************************************/ | |
36 | /* procfs stuff */ | |
37 | /********************************************************************/ | |
38 | ||
39 | ||
40 | void | |
41 | sbecom_proc_brd_cleanup (ci_t * ci) | |
42 | { | |
43 | if (ci->dir_dev) | |
44 | { | |
45 | char dir[7 + SBE_IFACETMPL_SIZE + 1]; | |
46 | snprintf(dir, sizeof(dir), "driver/%s", ci->devname); | |
47 | remove_proc_entry("info", ci->dir_dev); | |
48 | remove_proc_entry(dir, NULL); | |
49 | ci->dir_dev = NULL; | |
50 | } | |
51 | } | |
52 | ||
53 | ||
54 | static int | |
55 | sbecom_proc_get_sbe_info (char *buffer, char **start, off_t offset, | |
56 | int length, int *eof, void *priv) | |
57 | { | |
58 | ci_t *ci = (ci_t *) priv; | |
59 | int len = 0; | |
60 | char *spd; | |
61 | struct sbe_brd_info *bip; | |
62 | ||
63 | if (!(bip = OS_kmalloc (sizeof (struct sbe_brd_info)))) | |
64 | { | |
65 | return -ENOMEM; | |
66 | } | |
67 | #if 0 | |
68 | /** RLD DEBUG **/ | |
694a9807 | 69 | pr_info(">> sbecom_proc_get_sbe_info: entered, offset %d. length %d.\n", |
50ee11fe BB |
70 | (int) offset, (int) length); |
71 | #endif | |
72 | ||
73 | { | |
74 | hdw_info_t *hi = &hdw_info[ci->brdno]; | |
75 | ||
76 | u_int8_t *bsn = 0; | |
77 | ||
78 | switch (hi->promfmt) | |
79 | { | |
80 | case PROM_FORMAT_TYPE1: | |
81 | bsn = (u_int8_t *) hi->mfg_info.pft1.Serial; | |
82 | break; | |
83 | case PROM_FORMAT_TYPE2: | |
84 | bsn = (u_int8_t *) hi->mfg_info.pft2.Serial; | |
85 | break; | |
86 | } | |
87 | ||
88 | sbecom_get_brdinfo (ci, bip, bsn); | |
89 | } | |
90 | ||
91 | #if 0 | |
92 | /** RLD DEBUG **/ | |
694a9807 | 93 | pr_info(">> sbecom_get_brdinfo: returned, first_if %p <%s> last_if %p <%s>\n", |
50ee11fe BB |
94 | (char *) &bip->first_iname, (char *) &bip->first_iname, |
95 | (char *) &bip->last_iname, (char *) &bip->last_iname); | |
96 | #endif | |
97 | len += sprintf (buffer + len, "Board Type: "); | |
98 | switch (bip->brd_id) | |
99 | { | |
100 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T3): | |
101 | len += sprintf (buffer + len, "wanPMC-C1T3"); | |
102 | break; | |
103 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_E1): | |
104 | len += sprintf (buffer + len, "wanPTMC-256T3 <E1>"); | |
105 | break; | |
106 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_T1): | |
107 | len += sprintf (buffer + len, "wanPTMC-256T3 <T1>"); | |
108 | break; | |
109 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_C24TE1): | |
110 | len += sprintf (buffer + len, "wanPTMC-C24TE1"); | |
111 | break; | |
112 | ||
113 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1): | |
114 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1_L): | |
115 | len += sprintf (buffer + len, "wanPMC-C4T1E1"); | |
116 | break; | |
117 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1): | |
118 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1_L): | |
119 | len += sprintf (buffer + len, "wanPMC-C2T1E1"); | |
120 | break; | |
121 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1): | |
122 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1_L): | |
123 | len += sprintf (buffer + len, "wanPMC-C1T1E1"); | |
124 | break; | |
125 | ||
126 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1): | |
127 | len += sprintf (buffer + len, "wanPCI-C4T1E1"); | |
128 | break; | |
129 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1): | |
130 | len += sprintf (buffer + len, "wanPCI-C2T1E1"); | |
131 | break; | |
132 | case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1): | |
133 | len += sprintf (buffer + len, "wanPCI-C1T1E1"); | |
134 | break; | |
135 | ||
136 | default: | |
137 | len += sprintf (buffer + len, "unknown"); | |
138 | break; | |
139 | } | |
140 | len += sprintf (buffer + len, " [%08X]\n", bip->brd_id); | |
141 | ||
142 | len += sprintf (buffer + len, "Board Number: %d\n", bip->brdno); | |
143 | len += sprintf (buffer + len, "Hardware ID: 0x%02X\n", ci->hdw_bid); | |
144 | len += sprintf (buffer + len, "Board SN: %06X\n", bip->brd_sn); | |
ff5cb20b | 145 | len += sprintf(buffer + len, "Board MAC: %pMF\n", |
b01d467d | 146 | bip->brd_mac_addr); |
50ee11fe BB |
147 | len += sprintf (buffer + len, "Ports: %d\n", ci->max_port); |
148 | len += sprintf (buffer + len, "Channels: %d\n", bip->brd_chan_cnt); | |
149 | #if 1 | |
150 | len += sprintf (buffer + len, "Interface: %s -> %s\n", | |
151 | (char *) &bip->first_iname, (char *) &bip->last_iname); | |
152 | #else | |
153 | len += sprintf (buffer + len, "Interface: <not available> 1st %p lst %p\n", | |
154 | (char *) &bip->first_iname, (char *) &bip->last_iname); | |
155 | #endif | |
156 | ||
157 | switch (bip->brd_pci_speed) | |
158 | { | |
159 | case BINFO_PCI_SPEED_33: | |
160 | spd = "33Mhz"; | |
161 | break; | |
162 | case BINFO_PCI_SPEED_66: | |
163 | spd = "66Mhz"; | |
164 | break; | |
165 | default: | |
166 | spd = "<not available>"; | |
167 | break; | |
168 | } | |
169 | len += sprintf (buffer + len, "PCI Bus Speed: %s\n", spd); | |
170 | len += sprintf (buffer + len, "Release: %s\n", ci->release); | |
171 | ||
172 | #ifdef SBE_PMCC4_ENABLE | |
173 | { | |
c694ed85 | 174 | extern int cxt1e1_max_mru; |
50ee11fe BB |
175 | #if 0 |
176 | extern int max_chans_used; | |
c694ed85 | 177 | extern int cxt1e1_max_mtu; |
50ee11fe BB |
178 | #endif |
179 | extern int max_rxdesc_used, max_txdesc_used; | |
180 | ||
c694ed85 | 181 | len += sprintf (buffer + len, "\ncxt1e1_max_mru: %d\n", cxt1e1_max_mru); |
50ee11fe BB |
182 | #if 0 |
183 | len += sprintf (buffer + len, "\nmax_chans_used: %d\n", max_chans_used); | |
c694ed85 | 184 | len += sprintf (buffer + len, "cxt1e1_max_mtu: %d\n", cxt1e1_max_mtu); |
50ee11fe BB |
185 | #endif |
186 | len += sprintf (buffer + len, "max_rxdesc_used: %d\n", max_rxdesc_used); | |
187 | len += sprintf (buffer + len, "max_txdesc_used: %d\n", max_txdesc_used); | |
188 | } | |
189 | #endif | |
190 | ||
191 | OS_kfree (bip); /* cleanup */ | |
192 | ||
193 | /*** | |
194 | * How to be a proc read function | |
195 | * ------------------------------ | |
196 | * Prototype: | |
197 | * int f(char *buffer, char **start, off_t offset, | |
198 | * int count, int *peof, void *dat) | |
199 | * | |
200 | * Assume that the buffer is "count" bytes in size. | |
201 | * | |
202 | * If you know you have supplied all the data you | |
203 | * have, set *peof. | |
204 | * | |
205 | * You have three ways to return data: | |
206 | * 0) Leave *start = NULL. (This is the default.) | |
207 | * Put the data of the requested offset at that | |
208 | * offset within the buffer. Return the number (n) | |
209 | * of bytes there are from the beginning of the | |
210 | * buffer up to the last byte of data. If the | |
211 | * number of supplied bytes (= n - offset) is | |
212 | * greater than zero and you didn't signal eof | |
213 | * and the reader is prepared to take more data | |
214 | * you will be called again with the requested | |
215 | * offset advanced by the number of bytes | |
216 | * absorbed. This interface is useful for files | |
217 | * no larger than the buffer. | |
218 | * 1) Set *start = an unsigned long value less than | |
219 | * the buffer address but greater than zero. | |
220 | * Put the data of the requested offset at the | |
221 | * beginning of the buffer. Return the number of | |
222 | * bytes of data placed there. If this number is | |
223 | * greater than zero and you didn't signal eof | |
224 | * and the reader is prepared to take more data | |
225 | * you will be called again with the requested | |
226 | * offset advanced by *start. This interface is | |
227 | * useful when you have a large file consisting | |
228 | * of a series of blocks which you want to count | |
229 | * and return as wholes. | |
230 | * (Hack by Paul.Russell@rustcorp.com.au) | |
231 | * 2) Set *start = an address within the buffer. | |
232 | * Put the data of the requested offset at *start. | |
233 | * Return the number of bytes of data placed there. | |
234 | * If this number is greater than zero and you | |
235 | * didn't signal eof and the reader is prepared to | |
236 | * take more data you will be called again with the | |
237 | * requested offset advanced by the number of bytes | |
238 | * absorbed. | |
239 | */ | |
240 | ||
241 | #if 1 | |
25985edc | 242 | /* #4 - interpretation of above = set EOF, return len */ |
50ee11fe BB |
243 | *eof = 1; |
244 | #endif | |
245 | ||
246 | #if 0 | |
247 | /* | |
248 | * #1 - from net/wireless/atmel.c RLD NOTE -there's something wrong with | |
249 | * this plagarized code which results in this routine being called TWICE. | |
250 | * The second call returns ZERO, resulting in hidden failure, but at | |
251 | * least only a single message set is being displayed. | |
252 | */ | |
253 | if (len <= offset + length) | |
254 | *eof = 1; | |
255 | *start = buffer + offset; | |
256 | len -= offset; | |
257 | if (len > length) | |
258 | len = length; | |
259 | if (len < 0) | |
260 | len = 0; | |
261 | #endif | |
262 | ||
263 | #if 0 /* #2 from net/tokenring/olympic.c + | |
264 | * lanstreamer.c */ | |
265 | { | |
266 | off_t begin = 0; | |
267 | int size = 0; | |
268 | off_t pos = 0; | |
269 | ||
270 | size = len; | |
271 | pos = begin + size; | |
272 | if (pos < offset) | |
273 | { | |
274 | len = 0; | |
275 | begin = pos; | |
276 | } | |
277 | *start = buffer + (offset - begin); /* Start of wanted data */ | |
278 | len -= (offset - begin); /* Start slop */ | |
279 | if (len > length) | |
280 | len = length; /* Ending slop */ | |
281 | } | |
282 | #endif | |
283 | ||
284 | #if 0 /* #3 from | |
285 | * char/ftape/lowlevel/ftape-proc.c */ | |
286 | len = strlen (buffer); | |
287 | *start = NULL; | |
288 | if (offset + length >= len) | |
289 | *eof = 1; | |
290 | else | |
291 | *eof = 0; | |
292 | #endif | |
293 | ||
294 | #if 0 | |
694a9807 | 295 | pr_info(">> proc_fs: returned len = %d., start %p\n", len, start); /* RLD DEBUG */ |
50ee11fe BB |
296 | #endif |
297 | ||
298 | /*** | |
299 | using NONE: returns = 314.314.314. | |
300 | using #1 : returns = 314, 0. | |
301 | using #2 : returns = 314, 0, 0. | |
302 | using #3 : returns = 314, 314. | |
303 | using #4 : returns = 314, 314. | |
304 | ***/ | |
305 | ||
306 | return len; | |
307 | } | |
308 | ||
309 | /* initialize the /proc subsystem for the specific SBE driver */ | |
310 | ||
311 | int __init | |
312 | sbecom_proc_brd_init (ci_t * ci) | |
313 | { | |
314 | struct proc_dir_entry *e; | |
315 | char dir[7 + SBE_IFACETMPL_SIZE + 1]; | |
316 | ||
317 | /* create a directory in the root procfs */ | |
318 | snprintf(dir, sizeof(dir), "driver/%s", ci->devname); | |
319 | ci->dir_dev = proc_mkdir(dir, NULL); | |
320 | if (!ci->dir_dev) | |
321 | { | |
e6e4d05d | 322 | pr_err("Unable to create directory /proc/driver/%s\n", ci->devname); |
50ee11fe BB |
323 | goto fail; |
324 | } | |
325 | e = create_proc_read_entry ("info", S_IFREG | S_IRUGO, | |
326 | ci->dir_dev, sbecom_proc_get_sbe_info, ci); | |
327 | if (!e) | |
328 | { | |
e6e4d05d | 329 | pr_err("Unable to create entry /proc/driver/%s/info\n", ci->devname); |
50ee11fe BB |
330 | goto fail; |
331 | } | |
332 | return 0; | |
333 | ||
334 | fail: | |
335 | sbecom_proc_brd_cleanup (ci); | |
336 | return 1; | |
337 | } | |
338 | ||
339 | #else /*** ! CONFIG_PROC_FS ***/ | |
340 | ||
341 | /* stubbed off dummy routines */ | |
342 | ||
343 | void | |
344 | sbecom_proc_brd_cleanup (ci_t * ci) | |
345 | { | |
346 | } | |
347 | ||
348 | int __init | |
349 | sbecom_proc_brd_init (ci_t * ci) | |
350 | { | |
351 | return 0; | |
352 | } | |
353 | ||
354 | #endif /*** CONFIG_PROC_FS ***/ | |
355 | ||
356 | ||
357 | /*** End-of-File ***/ |