linux/drivers/isdn/hardware/eicon/divasproc.c
<<
>>
Prefs
   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