1/* $Id: divasproc.c,v 1.19.4.3 2005/01/31 12:22:20 armin Exp $ 2 * 3 * Low level driver for Eicon DIVA Server ISDN cards. 4 * /proc functions 5 * 6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de) 8 * 9 * This software may be used and distributed according to the terms 10 * of the GNU General Public License, incorporated herein by reference. 11 */ 12 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/poll.h> 16#include <linux/proc_fs.h> 17#include <linux/seq_file.h> 18#include <linux/list.h> 19#include <asm/uaccess.h> 20 21#include "platform.h" 22#include "debuglib.h" 23#undef ID_MASK 24#undef N_DATA 25#include "pc.h" 26#include "di_defs.h" 27#include "divasync.h" 28#include "di.h" 29#include "io.h" 30#include "xdi_msg.h" 31#include "xdi_adapter.h" 32#include "diva.h" 33#include "diva_pci.h" 34 35 36extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; 37extern void divas_get_version(char *); 38extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf); 39 40/********************************************************* 41 ** Functions for /proc interface / File operations 42 *********************************************************/ 43 44static char *divas_proc_name = "divas"; 45static char *adapter_dir_name = "adapter"; 46static char *info_proc_name = "info"; 47static char *grp_opt_proc_name = "group_optimization"; 48static char *d_l1_down_proc_name = "dynamic_l1_down"; 49 50/* 51** "divas" entry 52*/ 53 54extern struct proc_dir_entry *proc_net_eicon; 55static struct proc_dir_entry *divas_proc_entry = NULL; 56 57static ssize_t 58divas_read(struct file *file, char __user *buf, size_t count, loff_t *off) 59{ 60 int len = 0; 61 int cadapter; 62 char tmpbuf[80]; 63 char tmpser[16]; 64 65 if (*off) 66 return 0; 67 68 divas_get_version(tmpbuf); 69 if (copy_to_user(buf + len, &tmpbuf, strlen(tmpbuf))) 70 return -EFAULT; 71 len += strlen(tmpbuf); 72 73 for (cadapter = 0; cadapter < MAX_ADAPTER; cadapter++) { 74 if (IoAdapters[cadapter]) { 75 diva_get_vserial_number(IoAdapters[cadapter], 76 tmpser); 77 sprintf(tmpbuf, 78 "%2d: %-30s Serial:%-10s IRQ:%2d\n", 79 cadapter + 1, 80 IoAdapters[cadapter]->Properties.Name, 81 tmpser, 82 IoAdapters[cadapter]->irq_info.irq_nr); 83 if ((strlen(tmpbuf) + len) > count) 84 break; 85 if (copy_to_user 86 (buf + len, &tmpbuf, 87 strlen(tmpbuf))) return -EFAULT; 88 len += strlen(tmpbuf); 89 } 90 } 91 92 *off += len; 93 return (len); 94} 95 96static ssize_t 97divas_write(struct file *file, const char __user *buf, size_t count, loff_t *off) 98{ 99 return (-ENODEV); 100} 101 102static unsigned int divas_poll(struct file *file, poll_table *wait) 103{ 104 return (POLLERR); 105} 106 107static int divas_open(struct inode *inode, struct file *file) 108{ 109 return nonseekable_open(inode, file); 110} 111 112static int divas_close(struct inode *inode, struct file *file) 113{ 114 return (0); 115} 116 117static const struct file_operations divas_fops = { 118 .owner = THIS_MODULE, 119 .llseek = no_llseek, 120 .read = divas_read, 121 .write = divas_write, 122 .poll = divas_poll, 123 .open = divas_open, 124 .release = divas_close 125}; 126 127int create_divas_proc(void) 128{ 129 divas_proc_entry = proc_create(divas_proc_name, S_IFREG | S_IRUGO, 130 proc_net_eicon, &divas_fops); 131 if (!divas_proc_entry) 132 return (0); 133 134 return (1); 135} 136 137void remove_divas_proc(void) 138{ 139 if (divas_proc_entry) { 140 remove_proc_entry(divas_proc_name, proc_net_eicon); 141 divas_proc_entry = NULL; 142 } 143} 144 145static ssize_t grp_opt_proc_write(struct file *file, const char __user *buffer, 146 size_t count, loff_t *pos) 147{ 148 diva_os_xdi_adapter_t *a = PDE_DATA(file_inode(file)); 149 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; 150 151 if ((count == 1) || (count == 2)) { 152 char c; 153 if (get_user(c, buffer)) 154 return -EFAULT; 155 switch (c) { 156 case '0': 157 IoAdapter->capi_cfg.cfg_1 &= 158 ~DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON; 159 break; 160 case '1': 161 IoAdapter->capi_cfg.cfg_1 |= 162 DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON; 163 break; 164 default: 165 return (-EINVAL); 166 } 167 return (count); 168 } 169 return (-EINVAL); 170} 171 172static ssize_t d_l1_down_proc_write(struct file *file, const char __user *buffer, 173 size_t count, loff_t *pos) 174{ 175 diva_os_xdi_adapter_t *a = PDE_DATA(file_inode(file)); 176 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; 177 178 if ((count == 1) || (count == 2)) { 179 char c; 180 if (get_user(c, buffer)) 181 return -EFAULT; 182 switch (c) { 183 case '0': 184 IoAdapter->capi_cfg.cfg_1 &= 185 ~DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON; 186 break; 187 case '1': 188 IoAdapter->capi_cfg.cfg_1 |= 189 DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON; 190 break; 191 default: 192 return (-EINVAL); 193 } 194 return (count); 195 } 196 return (-EINVAL); 197} 198 199static int d_l1_down_proc_show(struct seq_file *m, void *v) 200{ 201 diva_os_xdi_adapter_t *a = m->private; 202 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; 203 204 seq_printf(m, "%s\n", 205 (IoAdapter->capi_cfg. 206 cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" : 207 "0"); 208 return 0; 209} 210 211static int d_l1_down_proc_open(struct inode *inode, struct file *file) 212{ 213 return single_open(file, d_l1_down_proc_show, PDE_DATA(inode)); 214} 215 216static const struct file_operations d_l1_down_proc_fops = { 217 .owner = THIS_MODULE, 218 .open = d_l1_down_proc_open, 219 .read = seq_read, 220 .llseek = seq_lseek, 221 .release = single_release, 222 .write = d_l1_down_proc_write, 223}; 224 225static int grp_opt_proc_show(struct seq_file *m, void *v) 226{ 227 diva_os_xdi_adapter_t *a = m->private; 228 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; 229 230 seq_printf(m, "%s\n", 231 (IoAdapter->capi_cfg. 232 cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) 233 ? "1" : "0"); 234 return 0; 235} 236 237static int grp_opt_proc_open(struct inode *inode, struct file *file) 238{ 239 return single_open(file, grp_opt_proc_show, PDE_DATA(inode)); 240} 241 242static const struct file_operations grp_opt_proc_fops = { 243 .owner = THIS_MODULE, 244 .open = grp_opt_proc_open, 245 .read = seq_read, 246 .llseek = seq_lseek, 247 .release = single_release, 248 .write = grp_opt_proc_write, 249}; 250 251static ssize_t info_proc_write(struct file *file, const char __user *buffer, 252 size_t count, loff_t *pos) 253{ 254 diva_os_xdi_adapter_t *a = PDE_DATA(file_inode(file)); 255 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; 256 char c[4]; 257 258 if (count <= 4) 259 return -EINVAL; 260 261 if (copy_from_user(c, buffer, 4)) 262 return -EFAULT; 263 264 /* this is for test purposes only */ 265 if (!memcmp(c, "trap", 4)) { 266 (*(IoAdapter->os_trap_nfy_Fnc)) (IoAdapter, IoAdapter->ANum); 267 return (count); 268 } 269 return (-EINVAL); 270} 271 272static int info_proc_show(struct seq_file *m, void *v) 273{ 274 int i = 0; 275 char *p; 276 char tmpser[16]; 277 diva_os_xdi_adapter_t *a = m->private; 278 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; 279 280 seq_printf(m, "Name : %s\n", IoAdapter->Properties.Name); 281 seq_printf(m, "DSP state : %08x\n", a->dsp_mask); 282 seq_printf(m, "Channels : %02d\n", IoAdapter->Properties.Channels); 283 seq_printf(m, "E. max/used : %03d/%03d\n", 284 IoAdapter->e_max, IoAdapter->e_count); 285 diva_get_vserial_number(IoAdapter, tmpser); 286 seq_printf(m, "Serial : %s\n", tmpser); 287 seq_printf(m, "IRQ : %d\n", IoAdapter->irq_info.irq_nr); 288 seq_printf(m, "CardIndex : %d\n", a->CardIndex); 289 seq_printf(m, "CardOrdinal : %d\n", a->CardOrdinal); 290 seq_printf(m, "Controller : %d\n", a->controller); 291 seq_printf(m, "Bus-Type : %s\n", 292 (a->Bus == 293 DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI"); 294 seq_printf(m, "Port-Name : %s\n", a->port_name); 295 if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) { 296 seq_printf(m, "PCI-bus : %d\n", a->resources.pci.bus); 297 seq_printf(m, "PCI-func : %d\n", a->resources.pci.func); 298 for (i = 0; i < 8; i++) { 299 if (a->resources.pci.bar[i]) { 300 seq_printf(m, 301 "Mem / I/O %d : 0x%x / mapped : 0x%lx", 302 i, a->resources.pci.bar[i], 303 (unsigned long) a->resources. 304 pci.addr[i]); 305 if (a->resources.pci.length[i]) { 306 seq_printf(m, 307 " / length : %d", 308 a->resources.pci. 309 length[i]); 310 } 311 seq_putc(m, '\n'); 312 } 313 } 314 } 315 if ((!a->xdi_adapter.port) && 316 ((!a->xdi_adapter.ram) || 317 (!a->xdi_adapter.reset) 318 || (!a->xdi_adapter.cfg))) { 319 if (!IoAdapter->irq_info.irq_nr) { 320 p = "slave"; 321 } else { 322 p = "out of service"; 323 } 324 } else if (a->xdi_adapter.trapped) { 325 p = "trapped"; 326 } else if (a->xdi_adapter.Initialized) { 327 p = "active"; 328 } else { 329 p = "ready"; 330 } 331 seq_printf(m, "State : %s\n", p); 332 333 return 0; 334} 335 336static int info_proc_open(struct inode *inode, struct file *file) 337{ 338 return single_open(file, info_proc_show, PDE_DATA(inode)); 339} 340 341static const struct file_operations info_proc_fops = { 342 .owner = THIS_MODULE, 343 .open = info_proc_open, 344 .read = seq_read, 345 .llseek = seq_lseek, 346 .release = single_release, 347 .write = info_proc_write, 348}; 349 350/* 351** adapter proc init/de-init 352*/ 353 354/* -------------------------------------------------------------------------- 355 Create adapter directory and files in proc file system 356 -------------------------------------------------------------------------- */ 357int create_adapter_proc(diva_os_xdi_adapter_t *a) 358{ 359 struct proc_dir_entry *de, *pe; 360 char tmp[16]; 361 362 sprintf(tmp, "%s%d", adapter_dir_name, a->controller); 363 if (!(de = proc_mkdir(tmp, proc_net_eicon))) 364 return (0); 365 a->proc_adapter_dir = (void *) de; 366 367 pe = proc_create_data(info_proc_name, S_IRUGO | S_IWUSR, de, 368 &info_proc_fops, a); 369 if (!pe) 370 return (0); 371 a->proc_info = (void *) pe; 372 373 pe = proc_create_data(grp_opt_proc_name, S_IRUGO | S_IWUSR, de, 374 &grp_opt_proc_fops, a); 375 if (pe) 376 a->proc_grp_opt = (void *) pe; 377 pe = proc_create_data(d_l1_down_proc_name, S_IRUGO | S_IWUSR, de, 378 &d_l1_down_proc_fops, a); 379 if (pe) 380 a->proc_d_l1_down = (void *) pe; 381 382 DBG_TRC(("proc entry %s created", tmp)); 383 384 return (1); 385} 386 387/* -------------------------------------------------------------------------- 388 Remove adapter directory and files in proc file system 389 -------------------------------------------------------------------------- */ 390void remove_adapter_proc(diva_os_xdi_adapter_t *a) 391{ 392 char tmp[16]; 393 394 if (a->proc_adapter_dir) { 395 if (a->proc_d_l1_down) { 396 remove_proc_entry(d_l1_down_proc_name, 397 (struct proc_dir_entry *) a->proc_adapter_dir); 398 } 399 if (a->proc_grp_opt) { 400 remove_proc_entry(grp_opt_proc_name, 401 (struct proc_dir_entry *) a->proc_adapter_dir); 402 } 403 if (a->proc_info) { 404 remove_proc_entry(info_proc_name, 405 (struct proc_dir_entry *) a->proc_adapter_dir); 406 } 407 sprintf(tmp, "%s%d", adapter_dir_name, a->controller); 408 remove_proc_entry(tmp, proc_net_eicon); 409 DBG_TRC(("proc entry %s%d removed", adapter_dir_name, 410 a->controller)); 411 } 412} 413