linux-old/drivers/net/wan/comx.c
<<
>>
Prefs
   1/*
   2 * Device driver framework for the COMX line of synchronous serial boards
   3 * 
   4 * for Linux kernel 2.2.X / 2.4.X
   5 *
   6 * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
   7 *                    Peter Bajan <bajan.peter@synergon.hu>,
   8 * Previous maintainer: Tivadar Szemethy <tiv@itc.hu>
   9 * Current maintainer: Gergely Madarasz <gorgo@itc.hu>
  10 *
  11 * Copyright (C) 1995-1999 ITConsult-Pro Co.
  12 *
  13 * Contributors:
  14 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.85)
  15 *
  16 * This program is free software; you can redistribute it and/or
  17 * modify it under the terms of the GNU General Public License
  18 * as published by the Free Software Foundation; either version
  19 * 2 of the License, or (at your option) any later version.
  20 *
  21 * Version 0.80 (99/06/11):
  22 *              - clean up source code (playing a bit of indent)
  23 *              - port back to kernel, add support for non-module versions
  24 *              - add support for board resets when channel protocol is down
  25 *              - reset the device structure after protocol exit
  26 *                the syncppp driver needs it
  27 *              - add support for /proc/comx/protocols and 
  28 *                /proc/comx/boardtypes
  29 *
  30 * Version 0.81 (99/06/21):
  31 *              - comment out the board reset support code, the locomx
  32 *                driver seems not buggy now
  33 *              - printk() levels fixed
  34 *
  35 * Version 0.82 (99/07/08):
  36 *              - Handle stats correctly if the lowlevel driver is
  37 *                is not a comx one (locomx - z85230)
  38 *
  39 * Version 0.83 (99/07/15):
  40 *              - reset line_status when interface is down
  41 *
  42 * Version 0.84 (99/12/01):
  43 *              - comx_status should not check for IFF_UP (to report
  44 *                line status from dev->open())
  45 *
  46 * Version 0.85 (00/08/15):
  47 *              - resource release on failure in comx_mkdir
  48 *              - fix return value on failure at comx_write_proc
  49 *
  50 * Changed      (00/10/29, Henner Eisen):
  51 *              - comx_rx() / comxlapb_data_indication() return status.
  52 */
  53
  54#define VERSION "0.85"
  55
  56#include <linux/config.h>
  57#include <linux/module.h>
  58#include <linux/version.h>
  59
  60#include <linux/types.h>
  61#include <linux/sched.h>
  62#include <linux/netdevice.h>
  63#include <linux/proc_fs.h>
  64#include <asm/uaccess.h>
  65#include <linux/ctype.h>
  66#include <linux/init.h>
  67
  68#ifdef CONFIG_KMOD
  69#include <linux/kmod.h>
  70#endif
  71
  72#ifndef CONFIG_PROC_FS
  73#error For now, COMX really needs the /proc filesystem
  74#endif
  75
  76#include <net/syncppp.h>
  77#include "comx.h"
  78
  79MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
  80MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
  81MODULE_LICENSE("GPL");
  82
  83extern int comx_hw_comx_init(void);
  84extern int comx_hw_locomx_init(void);
  85extern int comx_hw_mixcom_init(void);
  86extern int comx_proto_hdlc_init(void);
  87extern int comx_proto_ppp_init(void);
  88extern int comx_proto_syncppp_init(void);
  89extern int comx_proto_lapb_init(void);
  90extern int comx_proto_fr_init(void);
  91
  92static struct comx_hardware *comx_channels = NULL;
  93static struct comx_protocol *comx_lines = NULL;
  94
  95static int comx_mkdir(struct inode *, struct dentry *, int);
  96static int comx_rmdir(struct inode *, struct dentry *);
  97static struct dentry *comx_lookup(struct inode *, struct dentry *);
  98
  99static struct inode_operations comx_root_inode_ops = {
 100        lookup: comx_lookup,
 101        mkdir: comx_mkdir,
 102        rmdir: comx_rmdir,
 103};
 104
 105static int comx_delete_dentry(struct dentry *dentry);
 106static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
 107        int size, struct proc_dir_entry *dir);
 108
 109static struct dentry_operations comx_dentry_operations = {
 110        d_delete:       comx_delete_dentry,
 111};
 112
 113
 114static struct proc_dir_entry * comx_root_dir;
 115
 116struct comx_debugflags_struct   comx_debugflags[] = {
 117        { "comx_rx",            DEBUG_COMX_RX           },
 118        { "comx_tx",            DEBUG_COMX_TX           },
 119        { "hw_tx",              DEBUG_HW_TX             },
 120        { "hw_rx",              DEBUG_HW_RX             },
 121        { "hdlc_keepalive",     DEBUG_HDLC_KEEPALIVE    },
 122        { "comxppp",            DEBUG_COMX_PPP          },
 123        { "comxlapb",           DEBUG_COMX_LAPB         },
 124        { "dlci",               DEBUG_COMX_DLCI         },
 125        { NULL,                 0                       } 
 126};
 127
 128
 129int comx_debug(struct net_device *dev, char *fmt, ...)
 130{
 131        struct comx_channel *ch = dev->priv;
 132        char *page,*str;
 133        va_list args;
 134        int len;
 135
 136        if (!ch->debug_area) return 0;
 137
 138        if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM;
 139
 140        va_start(args, fmt);
 141        len = vsprintf(str = page, fmt, args);
 142        va_end(args);
 143
 144        if (len >= PAGE_SIZE) {
 145                printk(KERN_ERR "comx_debug: PANIC! len = %d !!!\n", len);
 146                free_page((unsigned long)page);
 147                return -EINVAL;
 148        }
 149
 150        while (len) {
 151                int to_copy;
 152                int free = (ch->debug_start - ch->debug_end + ch->debug_size) 
 153                        % ch->debug_size;
 154
 155                to_copy = min_t(int, free ? free : ch->debug_size, 
 156                              min_t(int, ch->debug_size - ch->debug_end, len));
 157                memcpy(ch->debug_area + ch->debug_end, str, to_copy);
 158                str += to_copy;
 159                len -= to_copy;
 160                ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size;
 161                if (ch->debug_start == ch->debug_end) // Full ? push start away
 162                        ch->debug_start = (ch->debug_start + len + 1) % 
 163                                        ch->debug_size;
 164                ch->debug_file->size = (ch->debug_end - ch->debug_start +
 165                                        ch->debug_size) % ch->debug_size;
 166        } 
 167
 168        free_page((unsigned long)page);
 169        return 0;
 170}
 171
 172int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg)
 173{
 174        struct comx_channel *ch = dev->priv;
 175
 176        if (!ch->debug_area) return 0;
 177        if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg);
 178        if (!skb->len) comx_debug(dev, "%s: %s empty skb\n\n", dev->name, msg);
 179
 180        return comx_debug_bytes(dev, skb->data, skb->len, msg);
 181}
 182
 183int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len, 
 184                char *msg)
 185{
 186        int pos = 0;
 187        struct comx_channel *ch = dev->priv;
 188
 189        if (!ch->debug_area) return 0;
 190
 191        comx_debug(dev, "%s: %s len %d\n", dev->name, msg, len);
 192
 193        while (pos != len) {
 194                char line[80];
 195                int i = 0;
 196
 197                memset(line, 0, 80);
 198                sprintf(line,"%04d ", pos);
 199                do {
 200                        sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]);
 201                        sprintf(line + 60 + (pos % 16), "%c", 
 202                                isprint(bytes[pos]) ? bytes[pos] : '.');
 203                        pos++;
 204                } while (pos != len && pos % 16);
 205
 206                while ( i++ != 78 ) if (line[i] == 0) line[i] = ' ';
 207                line[77] = '\n';
 208                line[78] = 0;
 209        
 210                comx_debug(dev, "%s", line);
 211        }
 212        comx_debug(dev, "\n");
 213        return 0;
 214}
 215
 216static void comx_loadavg_timerfun(unsigned long d)
 217{
 218        struct net_device *dev = (struct net_device *)d;
 219        struct comx_channel *ch = dev->priv;
 220
 221        ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;
 222        ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = 
 223                ch->current_stats->tx_bytes;
 224
 225        ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size;
 226
 227        mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]);
 228}
 229
 230#if 0
 231static void comx_reset_timerfun(unsigned long d)
 232{ 
 233        struct net_device *dev = (struct net_device *)d;
 234        struct comx_channel *ch = dev->priv;
 235
 236        if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {
 237                if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {
 238                        ch->HW_reset(dev);
 239                }
 240        }
 241
 242        mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout);
 243}
 244#endif                                            
 245
 246static int comx_open(struct net_device *dev)
 247{
 248        struct comx_channel *ch = dev->priv;
 249        struct proc_dir_entry *comxdir = ch->procdir->subdir;
 250        int ret=0;
 251
 252        if (!ch->protocol || !ch->hardware) return -ENODEV;
 253
 254        if ((ret = ch->HW_open(dev))) return ret;
 255        if ((ret = ch->LINE_open(dev))) { 
 256                ch->HW_close(dev); 
 257                return ret; 
 258        };
 259
 260        for (; comxdir ; comxdir = comxdir->next) {
 261                if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
 262                   strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
 263                        comxdir->mode = S_IFREG | 0444;
 264        }
 265
 266#if 0
 267        ch->reset_pending = 1;
 268        ch->reset_timeout = 30;
 269        ch->reset_timer.function = comx_reset_timerfun;
 270        ch->reset_timer.data = (unsigned long)dev;
 271        ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout;
 272        add_timer(&ch->reset_timer);
 273#endif
 274
 275        return 0;
 276}
 277
 278static int comx_close(struct net_device *dev)
 279{
 280        struct comx_channel *ch = dev->priv;
 281        struct proc_dir_entry *comxdir = ch->procdir->subdir;
 282        int ret = -ENODEV;
 283
 284        if (test_and_clear_bit(0, &ch->lineup_pending)) {
 285                del_timer(&ch->lineup_timer);
 286        }
 287
 288#if 0   
 289        del_timer(&ch->reset_timer);
 290#endif
 291
 292        if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) {
 293                ret = ch->LINE_close(dev);
 294        }
 295
 296        if (ret) return ret;
 297
 298        if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) {
 299                ret = ch->HW_close(dev);
 300        }
 301        
 302        ch->line_status=0;
 303
 304        for (; comxdir ; comxdir = comxdir->next) {
 305                if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
 306                    strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
 307                        comxdir->mode = S_IFREG | 0644;
 308        }
 309
 310        return ret;
 311}
 312
 313void comx_status(struct net_device *dev, int status)
 314{
 315        struct comx_channel *ch = dev->priv;
 316
 317#if 0
 318        if(status & (PROTO_UP | PROTO_LOOP)) {
 319                clear_bit(0,&ch->reset_pending);
 320        }
 321#endif
 322
 323        printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %s\n",
 324                    dev->name, status & LINE_UP ? "UP" : "DOWN", 
 325                    status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ? 
 326                    "UP" : "DOWN");
 327        
 328        ch->line_status = status;
 329}
 330
 331static int comx_xmit(struct sk_buff *skb, struct net_device *dev)
 332{
 333        struct comx_channel *ch = dev->priv;
 334        int rc;
 335
 336        if (skb->len > dev->mtu + dev->hard_header_len) {
 337                printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %d\n", dev->name,
 338                (int)skb->len, dev->mtu);
 339        }
 340        
 341        if (ch->debug_flags & DEBUG_COMX_TX) {
 342                comx_debug_skb(dev, skb, "comx_xmit skb");
 343        }
 344        
 345        rc=ch->LINE_xmit(skb, dev);
 346//      if (!rc) dev_kfree_skb(skb);
 347
 348        return rc;
 349}
 350
 351static int comx_header(struct sk_buff *skb, struct net_device *dev, 
 352        unsigned short type, void *daddr, void *saddr, unsigned len) 
 353{
 354        struct comx_channel *ch = dev->priv;
 355
 356        if (ch->LINE_header) {
 357                return (ch->LINE_header(skb, dev, type, daddr, saddr, len));
 358        } else {
 359                return 0;
 360        }
 361}
 362
 363static int comx_rebuild_header(struct sk_buff *skb) 
 364{
 365        struct net_device *dev = skb->dev;
 366        struct comx_channel *ch = dev->priv;
 367
 368        if (ch->LINE_rebuild_header) {
 369                return(ch->LINE_rebuild_header(skb));
 370        } else {
 371                return 0;
 372        }
 373}
 374
 375int comx_rx(struct net_device *dev, struct sk_buff *skb)
 376{
 377        struct comx_channel *ch = dev->priv;
 378
 379        if (ch->debug_flags & DEBUG_COMX_RX) {
 380                comx_debug_skb(dev, skb, "comx_rx skb");
 381        }
 382        if (skb) {
 383                netif_rx(skb);
 384                dev->last_rx = jiffies;
 385        }
 386        return 0;
 387}
 388
 389static struct net_device_stats *comx_stats(struct net_device *dev)
 390{
 391        struct comx_channel *ch = (struct comx_channel *)dev->priv;
 392
 393        return ch->current_stats;
 394}
 395
 396void comx_lineup_func(unsigned long d)
 397{
 398        struct net_device *dev = (struct net_device *)d;
 399        struct comx_channel *ch = dev->priv;
 400
 401        del_timer(&ch->lineup_timer);
 402        clear_bit(0, &ch->lineup_pending);
 403
 404        if (ch->LINE_status) {
 405                ch->LINE_status(dev, ch->line_status |= LINE_UP);
 406        }
 407}
 408
 409#define LOADAVG(avg, off) (int) \
 410        ((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) \
 411        % ch->loadavg_size + off] -  ch->avg_bytes[(ch->loadavg_counter - 1 \
 412                - ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) \
 413                % ch->loadavg_size + off]) / ch->loadavg[avg] * 8)
 414
 415static int comx_statistics(struct net_device *dev, char *page)
 416{
 417        struct comx_channel *ch = dev->priv;
 418        int len = 0;
 419        int tmp;
 420        int i = 0;
 421        char tmpstr[20];
 422        int tmpstrlen = 0;
 423
 424        len += sprintf(page + len, "Interface administrative status is %s, "
 425                "modem status is %s, protocol is %s\n", 
 426                dev->flags & IFF_UP ? "UP" : "DOWN",
 427                ch->line_status & LINE_UP ? "UP" : "DOWN",
 428                ch->line_status & PROTO_LOOP ? "LOOP" : 
 429                ch->line_status & PROTO_UP ? "UP" : "DOWN");
 430        len += sprintf(page + len, "Modem status changes: %lu, Transmitter status "
 431                "is %s, tbusy: %d\n", ch->current_stats->tx_carrier_errors, ch->HW_txe ? 
 432                ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", netif_running(dev));
 433        len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (",
 434                LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0));
 435        tmpstr[0] = 0;
 436        for (i=0; i != 3; i++) {
 437                char tf;
 438
 439                tf = ch->loadavg[i] % 60 == 0 && 
 440                        ch->loadavg[i] / 60 > 0 ? 'm' : 's';
 441                tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s", 
 442                        ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf, 
 443                        i == 2 ? ")\n" : "/");
 444        }
 445        len += sprintf(page + len, 
 446                "%s              (output): %d / %d / %d bits/s (%s", tmpstr, 
 447                LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size), 
 448                LOADAVG(2, ch->loadavg_size), tmpstr);
 449
 450        len += sprintf(page + len, "Debug flags: ");
 451        tmp = len; i = 0;
 452        while (comx_debugflags[i].name) {
 453                if (ch->debug_flags & comx_debugflags[i].value) 
 454                        len += sprintf(page + len, "%s ", 
 455                                comx_debugflags[i].name);
 456                i++;
 457        }
 458        len += sprintf(page + len, "%s\n", tmp == len ? "none" : "");
 459
 460        len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, "
 461                "aborts: %lu\n           buffer overrun: %lu, pbuffer overrun: %lu\n"
 462                "TX errors: underrun: %lu\n",
 463                ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors, 
 464                ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors, 
 465                ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors,
 466                ch->current_stats->tx_fifo_errors);
 467
 468        if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) {
 469                len += ch->LINE_statistics(dev, page + len);
 470        } else {
 471                len += sprintf(page+len, "Line status: driver not initialized\n");
 472        }
 473        if (ch->HW_statistics && (ch->init_status & HW_OPEN)) {
 474                len += ch->HW_statistics(dev, page + len);
 475        } else {
 476                len += sprintf(page+len, "Board status: driver not initialized\n");
 477        }
 478
 479        return len;
 480}
 481
 482static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 483{
 484        struct comx_channel *ch = dev->priv;
 485
 486        if (ch->LINE_ioctl) {
 487                return(ch->LINE_ioctl(dev, ifr, cmd));
 488        }
 489        return -EINVAL;
 490}
 491
 492static void comx_reset_dev(struct net_device *dev)
 493{
 494        dev->open = comx_open;
 495        dev->stop = comx_close;
 496        dev->hard_start_xmit = comx_xmit;
 497        dev->hard_header = comx_header;
 498        dev->rebuild_header = comx_rebuild_header;
 499        dev->get_stats = comx_stats;
 500        dev->do_ioctl = comx_ioctl;
 501        dev->change_mtu = NULL;
 502        dev->tx_queue_len = 20;
 503        dev->flags = IFF_NOARP;
 504}
 505
 506static int comx_init_dev(struct net_device *dev)
 507{
 508        struct comx_channel *ch;
 509
 510        if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) {
 511                return -ENOMEM;
 512        }
 513        memset(ch, 0, sizeof(struct comx_channel));
 514
 515        ch->loadavg[0] = 5;
 516        ch->loadavg[1] = 300;
 517        ch->loadavg[2] = 900;
 518        ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1; 
 519        if ((ch->avg_bytes = kmalloc(ch->loadavg_size * 
 520                sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) {
 521                kfree(ch);
 522                return -ENOMEM;
 523        }
 524
 525        memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2);
 526        ch->loadavg_counter = 0;
 527        ch->loadavg_timer.function = comx_loadavg_timerfun;
 528        ch->loadavg_timer.data = (unsigned long)dev;
 529        ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0];
 530        add_timer(&ch->loadavg_timer);
 531
 532        dev->priv = (void *)ch;
 533        ch->dev = dev;
 534        ch->line_status &= ~LINE_UP;
 535
 536        ch->current_stats = &ch->stats;
 537
 538        comx_reset_dev(dev);
 539        return 0;
 540}
 541
 542static int comx_read_proc(char *page, char **start, off_t off, int count, 
 543        int *eof, void *data)
 544{
 545        struct proc_dir_entry *file = (struct proc_dir_entry *)data;
 546        struct net_device *dev = file->parent->data;
 547        struct comx_channel *ch=(struct comx_channel *)dev->priv;
 548        int len = 0;
 549
 550        if (strcmp(file->name, FILENAME_STATUS) == 0) {
 551                len = comx_statistics(dev, page);
 552        } else if (strcmp(file->name, FILENAME_HARDWARE) == 0) {
 553                len = sprintf(page, "%s\n", ch->hardware ? 
 554                        ch->hardware->name : HWNAME_NONE);
 555        } else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) {
 556                len = sprintf(page, "%s\n", ch->protocol ? 
 557                        ch->protocol->name : PROTONAME_NONE);
 558        } else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) {
 559                len = sprintf(page, "%01d\n", ch->lineup_delay);
 560        }
 561
 562        if (off >= len) {
 563                *eof = 1;
 564                return 0;
 565        }
 566
 567        *start = page + off;
 568        if (count >= len - off) {
 569                *eof = 1;
 570        }
 571        return min_t(int, count, len - off);
 572}
 573
 574
 575static int comx_root_read_proc(char *page, char **start, off_t off, int count, 
 576        int *eof, void *data)
 577{
 578        struct proc_dir_entry *file = (struct proc_dir_entry *)data;
 579        struct comx_hardware *hw;
 580        struct comx_protocol *line;
 581
 582        int len = 0;
 583
 584        if (strcmp(file->name, FILENAME_HARDWARELIST) == 0) {
 585                for(hw=comx_channels;hw;hw=hw->next) 
 586                        len+=sprintf(page+len, "%s\n", hw->name);
 587        } else if (strcmp(file->name, FILENAME_PROTOCOLLIST) == 0) {
 588                for(line=comx_lines;line;line=line->next)
 589                        len+=sprintf(page+len, "%s\n", line->name);
 590        }
 591
 592        if (off >= len) {
 593                *eof = 1;
 594                return 0;
 595        }
 596
 597        *start = page + off;
 598        if (count >= len - off) {
 599                *eof = 1;
 600        }
 601        return min_t(int, count, len - off);
 602}
 603
 604
 605
 606static int comx_write_proc(struct file *file, const char *buffer, u_long count,
 607        void *data)
 608{
 609        struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
 610        struct net_device *dev = (struct net_device *)entry->parent->data;
 611        struct comx_channel *ch=(struct comx_channel *)dev->priv;
 612        char *page;
 613        struct comx_hardware *hw = comx_channels;
 614        struct comx_protocol *line = comx_lines;
 615        char str[30];
 616        int ret=0;
 617
 618        if (count > PAGE_SIZE) {
 619                printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
 620                return -ENOSPC;
 621        }
 622
 623        if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
 624
 625        if(copy_from_user(page, buffer, count))
 626        {
 627                count = -EFAULT;
 628                goto out;
 629        }
 630
 631        if (page[count-1] == '\n')
 632                page[count-1] = '\0';
 633        else if (count < PAGE_SIZE)
 634                page[count] = '\0';
 635        else if (page[count]) {
 636                count = -EINVAL;
 637                goto out;
 638        }
 639
 640        if (strcmp(entry->name, FILENAME_DEBUG) == 0) {
 641                int i;
 642                int ret = 0;
 643
 644                if ((i = simple_strtoul(page, NULL, 10)) != 0) {
 645                        unsigned long flags;
 646
 647                        save_flags(flags); cli();
 648                        if (ch->debug_area) kfree(ch->debug_area);
 649                        if ((ch->debug_area = kmalloc(ch->debug_size = i, 
 650                                GFP_KERNEL)) == NULL) {
 651                                ret = -ENOMEM;
 652                        }
 653                        ch->debug_start = ch->debug_end = 0;
 654                        restore_flags(flags);
 655                        free_page((unsigned long)page);
 656                        return ret ? ret : count;
 657                }
 658                
 659                if (*page != '+' && *page != '-') {
 660                        free_page((unsigned long)page);
 661                        return -EINVAL;
 662                }
 663                while (comx_debugflags[i].value && 
 664                        strncmp(comx_debugflags[i].name, page + 1, 
 665                        strlen(comx_debugflags[i].name))) {
 666                        i++;
 667                }
 668        
 669                if (comx_debugflags[i].value == 0) {
 670                        printk(KERN_ERR "Invalid debug option\n");
 671                        free_page((unsigned long)page);
 672                        return -EINVAL;
 673                }
 674                if (*page == '+') {
 675                        ch->debug_flags |= comx_debugflags[i].value;
 676                } else {
 677                        ch->debug_flags &= ~comx_debugflags[i].value;
 678                }
 679        } else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) {
 680                if(strlen(page)>10) {
 681                        free_page((unsigned long)page);
 682                        return -EINVAL;
 683                }
 684                while (hw) { 
 685                        if (strcmp(hw->name, page) == 0) {
 686                                break;
 687                        } else {
 688                                hw = hw->next;
 689                        }
 690                }
 691#ifdef CONFIG_KMOD
 692                if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){
 693                        sprintf(str,"comx-hw-%s",page);
 694                        request_module(str);
 695                }               
 696                hw=comx_channels;
 697                while (hw) {
 698                        if (comx_strcasecmp(hw->name, page) == 0) {
 699                                break;
 700                        } else {
 701                                hw = hw->next;
 702                        }
 703                }
 704#endif
 705
 706                if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw)  {
 707                        free_page((unsigned long)page);
 708                        return -ENODEV;
 709                }
 710                if (ch->init_status & HW_OPEN) {
 711                        free_page((unsigned long)page);
 712                        return -EBUSY;
 713                }
 714                if (ch->hardware && ch->hardware->hw_exit && 
 715                   (ret=ch->hardware->hw_exit(dev))) {
 716                        free_page((unsigned long)page);
 717                        return ret;
 718                }
 719                ch->hardware = hw;
 720                entry->size = strlen(page) + 1;
 721                if (hw && hw->hw_init) hw->hw_init(dev);
 722        } else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) {
 723                if(strlen(page)>10) {
 724                        free_page((unsigned long)page);
 725                        return -EINVAL;
 726                }
 727                while (line) {
 728                        if (comx_strcasecmp(line->name, page) == 0) {
 729                                break;
 730                        } else {
 731                                line = line->next;
 732                        }
 733                }
 734#ifdef CONFIG_KMOD
 735                if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
 736                        sprintf(str,"comx-proto-%s",page);
 737                        request_module(str);
 738                }               
 739                line=comx_lines;
 740                while (line) {
 741                        if (comx_strcasecmp(line->name, page) == 0) {
 742                                break;
 743                        } else {
 744                                line = line->next;
 745                        }
 746                }
 747#endif
 748                
 749                if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) {
 750                        free_page((unsigned long)page);
 751                        return -ENODEV;
 752                }
 753                
 754                if (ch->init_status & LINE_OPEN) {
 755                        free_page((unsigned long)page);
 756                        return -EBUSY;
 757                }
 758                
 759                if (ch->protocol && ch->protocol->line_exit && 
 760                    (ret=ch->protocol->line_exit(dev))) {
 761                        free_page((unsigned long)page);
 762                        return ret;
 763                }
 764                ch->protocol = line;
 765                entry->size = strlen(page) + 1;
 766                comx_reset_dev(dev);
 767                if (line && line->line_init) line->line_init(dev);
 768        } else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) {
 769                int i;
 770
 771                if ((i = simple_strtoul(page, NULL, 10)) != 0) {
 772                        if (i >=0 && i < 10) { 
 773                                ch->lineup_delay = i; 
 774                        } else {
 775                                printk(KERN_ERR "comx: invalid lineup_delay value\n");
 776                        }
 777                }
 778        }
 779out:
 780        free_page((unsigned long)page);
 781        return count;
 782}
 783
 784static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 785{
 786        struct proc_dir_entry *new_dir, *debug_file;
 787        struct net_device *dev;
 788        struct comx_channel *ch;
 789        int ret = -EIO;
 790
 791        if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) {
 792                return -ENOMEM;
 793        }
 794        memset(dev, 0, sizeof(struct net_device));
 795
 796        if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, 
 797                comx_root_dir)) == NULL) {
 798                goto cleanup_dev;
 799        }
 800
 801        new_dir->nlink = 2;
 802        new_dir->data = NULL; // ide jon majd a struct dev
 803
 804        /* Ezek kellenek */
 805        if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644, 
 806            strlen(HWNAME_NONE) + 1, new_dir)) {
 807                goto cleanup_new_dir;
 808        }
 809        if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644, 
 810            strlen(PROTONAME_NONE) + 1, new_dir)) {
 811                goto cleanup_filename_hardware;
 812        }
 813        if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) {
 814                goto cleanup_filename_protocol;
 815        }
 816        if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) {
 817                goto cleanup_filename_status;
 818        }
 819
 820        if ((debug_file = create_proc_entry(FILENAME_DEBUG, 
 821            S_IFREG | 0644, new_dir)) == NULL) {
 822                goto cleanup_filename_lineupdelay;
 823        }
 824        debug_file->data = (void *)debug_file; 
 825        debug_file->read_proc = NULL; // see below
 826        debug_file->write_proc = &comx_write_proc;
 827        debug_file->nlink = 1;
 828
 829        strcpy(dev->name, (char *)new_dir->name);
 830        dev->init = comx_init_dev;
 831
 832        if (register_netdevice(dev)) {
 833                goto cleanup_filename_debug;
 834        }
 835        ch=dev->priv;
 836        if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), 
 837                                 GFP_KERNEL)) == NULL) {
 838                goto cleanup_register;
 839        }
 840        memset(ch->if_ptr, 0, sizeof(struct ppp_device));
 841        ch->debug_file = debug_file; 
 842        ch->procdir = new_dir;
 843        new_dir->data = dev;
 844
 845        ch->debug_start = ch->debug_end = 0;
 846        if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE, 
 847            GFP_KERNEL)) == NULL) {
 848                ret = -ENOMEM;
 849                goto cleanup_if_ptr;
 850        }
 851
 852        ch->lineup_delay = DEFAULT_LINEUP_DELAY;
 853
 854        MOD_INC_USE_COUNT;
 855        return 0;
 856cleanup_if_ptr:
 857        kfree(ch->if_ptr);
 858cleanup_register:
 859        unregister_netdevice(dev);
 860cleanup_filename_debug:
 861        remove_proc_entry(FILENAME_DEBUG, new_dir);
 862cleanup_filename_lineupdelay:
 863        remove_proc_entry(FILENAME_LINEUPDELAY, new_dir);
 864cleanup_filename_status:
 865        remove_proc_entry(FILENAME_STATUS, new_dir);
 866cleanup_filename_protocol:
 867        remove_proc_entry(FILENAME_PROTOCOL, new_dir);
 868cleanup_filename_hardware:
 869        remove_proc_entry(FILENAME_HARDWARE, new_dir);
 870cleanup_new_dir:
 871        remove_proc_entry(dentry->d_name.name, comx_root_dir);
 872cleanup_dev:
 873        kfree(dev);
 874        return ret;
 875}
 876
 877static int comx_rmdir(struct inode *dir, struct dentry *dentry)
 878{
 879        struct proc_dir_entry *entry = dentry->d_inode->u.generic_ip;
 880        struct net_device *dev = entry->data;
 881        struct comx_channel *ch = dev->priv;
 882        int ret;
 883
 884        if (dev->flags & IFF_UP) {
 885                printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
 886                return -EBUSY;
 887        }
 888
 889        if (ch->protocol && ch->protocol->line_exit && 
 890            (ret=ch->protocol->line_exit(dev))) {
 891                return ret;
 892        }
 893        if (ch->hardware && ch->hardware->hw_exit && 
 894           (ret=ch->hardware->hw_exit(dev))) { 
 895                if(ch->protocol && ch->protocol->line_init) {
 896                        ch->protocol->line_init(dev);
 897                }
 898                return ret;
 899        }
 900        ch->protocol = NULL;
 901        ch->hardware = NULL;
 902
 903        del_timer(&ch->loadavg_timer);
 904        kfree(ch->avg_bytes);
 905
 906        unregister_netdev(dev);
 907        if (ch->debug_area) {
 908                kfree(ch->debug_area);
 909        }
 910        if (dev->priv) {
 911                kfree(dev->priv);
 912        }
 913        kfree(dev);
 914
 915        remove_proc_entry(FILENAME_DEBUG, entry);
 916        remove_proc_entry(FILENAME_LINEUPDELAY, entry);
 917        remove_proc_entry(FILENAME_STATUS, entry);
 918        remove_proc_entry(FILENAME_HARDWARE, entry);
 919        remove_proc_entry(FILENAME_PROTOCOL, entry);
 920        remove_proc_entry(dentry->d_name.name, comx_root_dir);
 921
 922        MOD_DEC_USE_COUNT;
 923        return 0;
 924}
 925
 926static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry)
 927{
 928        struct proc_dir_entry *de;
 929        struct inode *inode = NULL;
 930
 931        if ((de = (struct proc_dir_entry *) dir->u.generic_ip) != NULL) {
 932                for (de = de->subdir ; de ; de = de->next) {
 933                        if ((de && de->low_ino) && 
 934                            (de->namelen == dentry->d_name.len) &&
 935                            (memcmp(dentry->d_name.name, de->name, 
 936                            de->namelen) == 0)) {
 937                                if ((inode = proc_get_inode(dir->i_sb, 
 938                                    de->low_ino, de)) == NULL) { 
 939                                        printk(KERN_ERR "COMX: lookup error\n"); 
 940                                        return ERR_PTR(-EINVAL); 
 941                                }
 942                                break;
 943                        }
 944                }
 945        }
 946        dentry->d_op = &comx_dentry_operations;
 947        d_add(dentry, inode);
 948        return NULL;
 949}
 950
 951int comx_strcasecmp(const char *cs, const char *ct)
 952{
 953        register signed char __res;
 954
 955        while (1) {
 956                if ((__res = toupper(*cs) - toupper(*ct++)) != 0 || !*cs++) {
 957                        break;
 958                }
 959        }
 960        return __res;
 961}
 962
 963static int comx_delete_dentry(struct dentry *dentry)
 964{
 965        return 1;
 966}
 967
 968static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
 969        int size, struct proc_dir_entry *dir)
 970{
 971        struct proc_dir_entry *new_file;
 972
 973        if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
 974                new_file->data = (void *)new_file;
 975                new_file->read_proc = &comx_read_proc;
 976                new_file->write_proc = &comx_write_proc;
 977                new_file->size = size;
 978                new_file->nlink = 1;
 979        }
 980        return(new_file);
 981}
 982
 983int comx_register_hardware(struct comx_hardware *comx_hw)
 984{
 985        struct comx_hardware *hw = comx_channels;
 986
 987        if (!hw) {
 988                comx_channels = comx_hw;
 989        } else {
 990                while (hw->next != NULL && strcmp(comx_hw->name, hw->name) != 0) {
 991                        hw = hw->next;
 992                }
 993                if (strcmp(comx_hw->name, hw->name) == 0) {
 994                        return -1;
 995                }
 996                hw->next = comx_hw;
 997        }
 998
 999        printk(KERN_INFO "COMX: driver for hardware type %s, version %s\n", comx_hw->name, comx_hw->version);
1000        return 0;
1001}
1002
1003int comx_unregister_hardware(char *name)
1004{
1005        struct comx_hardware *hw = comx_channels;
1006
1007        if (!hw) {
1008                return -1;
1009        }
1010
1011        if (strcmp(hw->name, name) == 0) {
1012                comx_channels = comx_channels->next;
1013                return 0;
1014        }
1015
1016        while (hw->next != NULL && strcmp(hw->next->name,name) != 0) {
1017                hw = hw->next;
1018        }
1019
1020        if (hw->next != NULL && strcmp(hw->next->name, name) == 0) {
1021                hw->next = hw->next->next;
1022                return 0;
1023        }
1024        return -1;
1025}
1026
1027int comx_register_protocol(struct comx_protocol *comx_line)
1028{
1029        struct comx_protocol *pr = comx_lines;
1030
1031        if (!pr) {
1032                comx_lines = comx_line;
1033        } else {
1034                while (pr->next != NULL && strcmp(comx_line->name, pr->name) !=0) {
1035                        pr = pr->next;
1036                }
1037                if (strcmp(comx_line->name, pr->name) == 0) {
1038                        return -1;
1039                }
1040                pr->next = comx_line;
1041        }
1042
1043        printk(KERN_INFO "COMX: driver for protocol type %s, version %s\n", comx_line->name, comx_line->version);
1044        return 0;
1045}
1046
1047int comx_unregister_protocol(char *name)
1048{
1049        struct comx_protocol *pr = comx_lines;
1050
1051        if (!pr) {
1052                return -1;
1053        }
1054
1055        if (strcmp(pr->name, name) == 0) {
1056                comx_lines = comx_lines->next;
1057                return 0;
1058        }
1059
1060        while (pr->next != NULL && strcmp(pr->next->name,name) != 0) {
1061                pr = pr->next;
1062        }
1063
1064        if (pr->next != NULL && strcmp(pr->next->name, name) == 0) {
1065                pr->next = pr->next->next;
1066                return 0;
1067        }
1068        return -1;
1069}
1070
1071#ifdef MODULE
1072#define comx_init init_module
1073#endif
1074
1075int __init comx_init(void)
1076{
1077        struct proc_dir_entry *new_file;
1078
1079        comx_root_dir = create_proc_entry("comx", 
1080                S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root);
1081        if (!comx_root_dir)
1082                return -ENOMEM;
1083        comx_root_dir->proc_iops = &comx_root_inode_ops;
1084
1085        if ((new_file = create_proc_entry(FILENAME_HARDWARELIST, 
1086           S_IFREG | 0444, comx_root_dir)) == NULL) {
1087                return -ENOMEM;
1088        }
1089        
1090        new_file->data = new_file;
1091        new_file->read_proc = &comx_root_read_proc;
1092        new_file->write_proc = NULL;
1093        new_file->nlink = 1;
1094
1095        if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST, 
1096           S_IFREG | 0444, comx_root_dir)) == NULL) {
1097                return -ENOMEM;
1098        }
1099        
1100        new_file->data = new_file;
1101        new_file->read_proc = &comx_root_read_proc;
1102        new_file->write_proc = NULL;
1103        new_file->nlink = 1;
1104
1105
1106        printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>\n", 
1107                VERSION);
1108
1109#ifndef MODULE
1110#ifdef CONFIG_COMX_HW_COMX
1111        comx_hw_comx_init();
1112#endif
1113#ifdef CONFIG_COMX_HW_LOCOMX
1114        comx_hw_locomx_init();
1115#endif
1116#ifdef CONFIG_COMX_HW_MIXCOM
1117        comx_hw_mixcom_init();
1118#endif
1119#ifdef CONFIG_COMX_PROTO_HDLC
1120        comx_proto_hdlc_init();
1121#endif
1122#ifdef CONFIG_COMX_PROTO_PPP
1123        comx_proto_ppp_init();
1124#endif
1125#ifdef CONFIG_COMX_PROTO_LAPB
1126        comx_proto_lapb_init();
1127#endif
1128#ifdef CONFIG_COMX_PROTO_FR
1129        comx_proto_fr_init();
1130#endif
1131#endif
1132
1133        return 0;
1134}
1135
1136#ifdef MODULE
1137void cleanup_module(void)
1138{
1139        remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
1140        remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
1141        remove_proc_entry(comx_root_dir->name, &proc_root);
1142}
1143#endif
1144
1145EXPORT_SYMBOL(comx_register_hardware);
1146EXPORT_SYMBOL(comx_unregister_hardware);
1147EXPORT_SYMBOL(comx_register_protocol);
1148EXPORT_SYMBOL(comx_unregister_protocol);
1149EXPORT_SYMBOL(comx_debug_skb);
1150EXPORT_SYMBOL(comx_debug_bytes);
1151EXPORT_SYMBOL(comx_debug);
1152EXPORT_SYMBOL(comx_lineup_func);
1153EXPORT_SYMBOL(comx_status);
1154EXPORT_SYMBOL(comx_rx);
1155EXPORT_SYMBOL(comx_strcasecmp);
1156EXPORT_SYMBOL(comx_root_dir);
1157
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.