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 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 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 */ 30void sbecom_get_brdinfo (ci_t *, struct sbe_brd_info *, u_int8_t *); 31extern struct s_hdw_info hdw_info[MAX_BOARDS]; 32 33#ifdef CONFIG_PROC_FS 34 35/********************************************************************/ 36/* procfs stuff */ 37/********************************************************************/ 38 39 40void 41sbecom_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 54static int 55sbecom_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 68 { 69 hdw_info_t *hi = &hdw_info[ci->brdno]; 70 71 u_int8_t *bsn = 0; 72 73 switch (hi->promfmt) 74 { 75 case PROM_FORMAT_TYPE1: 76 bsn = (u_int8_t *) hi->mfg_info.pft1.Serial; 77 break; 78 case PROM_FORMAT_TYPE2: 79 bsn = (u_int8_t *) hi->mfg_info.pft2.Serial; 80 break; 81 } 82 83 sbecom_get_brdinfo (ci, bip, bsn); 84 } 85 86 len += sprintf (buffer + len, "Board Type: "); 87 switch (bip->brd_id) 88 { 89 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T3): 90 len += sprintf (buffer + len, "wanPMC-C1T3"); 91 break; 92 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_E1): 93 len += sprintf (buffer + len, "wanPTMC-256T3 <E1>"); 94 break; 95 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_T1): 96 len += sprintf (buffer + len, "wanPTMC-256T3 <T1>"); 97 break; 98 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_C24TE1): 99 len += sprintf (buffer + len, "wanPTMC-C24TE1"); 100 break; 101 102 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1): 103 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1_L): 104 len += sprintf (buffer + len, "wanPMC-C4T1E1"); 105 break; 106 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1): 107 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1_L): 108 len += sprintf (buffer + len, "wanPMC-C2T1E1"); 109 break; 110 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1): 111 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1_L): 112 len += sprintf (buffer + len, "wanPMC-C1T1E1"); 113 break; 114 115 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1): 116 len += sprintf (buffer + len, "wanPCI-C4T1E1"); 117 break; 118 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1): 119 len += sprintf (buffer + len, "wanPCI-C2T1E1"); 120 break; 121 case SBE_BOARD_ID (PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1): 122 len += sprintf (buffer + len, "wanPCI-C1T1E1"); 123 break; 124 125 default: 126 len += sprintf (buffer + len, "unknown"); 127 break; 128 } 129 len += sprintf (buffer + len, " [%08X]\n", bip->brd_id); 130 131 len += sprintf (buffer + len, "Board Number: %d\n", bip->brdno); 132 len += sprintf (buffer + len, "Hardware ID: 0x%02X\n", ci->hdw_bid); 133 len += sprintf (buffer + len, "Board SN: %06X\n", bip->brd_sn); 134 len += sprintf (buffer + len, "Board MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", 135 bip->brd_mac_addr[0], bip->brd_mac_addr[1], bip->brd_mac_addr[2], 136 bip->brd_mac_addr[3], bip->brd_mac_addr[4], bip->brd_mac_addr[5]); 137 len += sprintf (buffer + len, "Ports: %d\n", ci->max_port); 138 len += sprintf (buffer + len, "Channels: %d\n", bip->brd_chan_cnt); 139 len += sprintf (buffer + len, "Interface: %s -> %s\n", 140 (char *) &bip->first_iname, (char *) &bip->last_iname); 141 142 switch (bip->brd_pci_speed) 143 { 144 case BINFO_PCI_SPEED_33: 145 spd = "33Mhz"; 146 break; 147 case BINFO_PCI_SPEED_66: 148 spd = "66Mhz"; 149 break; 150 default: 151 spd = "<not available>"; 152 break; 153 } 154 len += sprintf (buffer + len, "PCI Bus Speed: %s\n", spd); 155 len += sprintf (buffer + len, "Release: %s\n", ci->release); 156 157#ifdef SBE_PMCC4_ENABLE 158 { 159 extern int max_mru; 160 extern int max_rxdesc_used, max_txdesc_used; 161 162 len += sprintf (buffer + len, "\nmax_mru: %d\n", max_mru); 163 len += sprintf (buffer + len, "max_rxdesc_used: %d\n", max_rxdesc_used); 164 len += sprintf (buffer + len, "max_txdesc_used: %d\n", max_txdesc_used); 165 } 166#endif 167 168 OS_kfree (bip); /* cleanup */ 169 170 /*** 171 * How to be a proc read function 172 * ------------------------------ 173 * Prototype: 174 * int f(char *buffer, char **start, off_t offset, 175 * int count, int *peof, void *dat) 176 * 177 * Assume that the buffer is "count" bytes in size. 178 * 179 * If you know you have supplied all the data you 180 * have, set *peof. 181 * 182 * You have three ways to return data: 183 * 0) Leave *start = NULL. (This is the default.) 184 * Put the data of the requested offset at that 185 * offset within the buffer. Return the number (n) 186 * of bytes there are from the beginning of the 187 * buffer up to the last byte of data. If the 188 * number of supplied bytes (= n - offset) is 189 * greater than zero and you didn't signal eof 190 * and the reader is prepared to take more data 191 * you will be called again with the requested 192 * offset advanced by the number of bytes 193 * absorbed. This interface is useful for files 194 * no larger than the buffer. 195 * 1) Set *start = an unsigned long value less than 196 * the buffer address but greater than zero. 197 * Put the data of the requested offset at the 198 * beginning of the buffer. Return the number of 199 * bytes of data placed there. If this number is 200 * greater than zero and you didn't signal eof 201 * and the reader is prepared to take more data 202 * you will be called again with the requested 203 * offset advanced by *start. This interface is 204 * useful when you have a large file consisting 205 * of a series of blocks which you want to count 206 * and return as wholes. 207 * (Hack by Paul.Russell@rustcorp.com.au) 208 * 2) Set *start = an address within the buffer. 209 * Put the data of the requested offset at *start. 210 * Return the number of bytes of data placed there. 211 * If this number is greater than zero and you 212 * didn't signal eof and the reader is prepared to 213 * take more data you will be called again with the 214 * requested offset advanced by the number of bytes 215 * absorbed. 216 */ 217 218 /* #4 - intepretation of above = set EOF, return len */ 219 *eof = 1; 220 221 222#if 0 /* #2 from net/tokenring/olympic.c + 223 * lanstreamer.c */ 224 { 225 off_t begin = 0; 226 int size = 0; 227 off_t pos = 0; 228 229 size = len; 230 pos = begin + size; 231 if (pos < offset) 232 { 233 len = 0; 234 begin = pos; 235 } 236 *start = buffer + (offset - begin); /* Start of wanted data */ 237 len -= (offset - begin); /* Start slop */ 238 if (len > length) 239 len = length; /* Ending slop */ 240 } 241#endif 242 243#if 0 /* #3 from 244 * char/ftape/lowlevel/ftape-proc.c */ 245 len = strlen (buffer); 246 *start = NULL; 247 if (offset + length >= len) 248 *eof = 1; 249 else 250 *eof = 0; 251#endif 252 253 254/*** 255 using NONE: returns = 314.314.314. 256 using #1 : returns = 314, 0. 257 using #2 : returns = 314, 0, 0. 258 using #3 : returns = 314, 314. 259 using #4 : returns = 314, 314. 260***/ 261 262 return len; 263} 264 265/* initialize the /proc subsystem for the specific SBE driver */ 266 267int __init 268sbecom_proc_brd_init (ci_t * ci) 269{ 270 struct proc_dir_entry *e; 271 char dir[7 + SBE_IFACETMPL_SIZE + 1]; 272 273 /* create a directory in the root procfs */ 274 snprintf(dir, sizeof(dir), "driver/%s", ci->devname); 275 ci->dir_dev = proc_mkdir(dir, NULL); 276 if (!ci->dir_dev) 277 { 278 pr_err("Unable to create directory /proc/driver/%s\n", ci->devname); 279 goto fail; 280 } 281 e = create_proc_read_entry ("info", S_IFREG | S_IRUGO, 282 ci->dir_dev, sbecom_proc_get_sbe_info, ci); 283 if (!e) 284 { 285 pr_err("Unable to create entry /proc/driver/%s/info\n", ci->devname); 286 goto fail; 287 } 288 return 0; 289 290fail: 291 sbecom_proc_brd_cleanup (ci); 292 return 1; 293} 294 295#else /*** ! CONFIG_PROC_FS ***/ 296 297/* stubbed off dummy routines */ 298 299void 300sbecom_proc_brd_cleanup (ci_t * ci) 301{ 302} 303 304int __init 305sbecom_proc_brd_init (ci_t * ci) 306{ 307 return 0; 308} 309 310#endif /*** CONFIG_PROC_FS ***/ 311 312 313/*** End-of-File ***/ 314