Merge with 2.3.99-pre9.
[linux-2.6/linux-mips.git] / drivers / net / wan / comx.c
blobd8e76deefb285a035df541a2aca972e4c94ec4bd
1 /*
2 * Device driver framework for the COMX line of synchronous serial boards
3 *
4 * for Linux kernel 2.2.X
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>
11 * Copyright (C) 1995-1999 ITConsult-Pro Co.
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
18 * Version 0.80 (99/06/11):
19 * - clean up source code (playing a bit of indent)
20 * - port back to kernel, add support for non-module versions
21 * - add support for board resets when channel protocol is down
22 * - reset the device structure after protocol exit
23 * the syncppp driver needs it
24 * - add support for /proc/comx/protocols and
25 * /proc/comx/boardtypes
27 * Version 0.81 (99/06/21):
28 * - comment out the board reset support code, the locomx
29 * driver seems not buggy now
30 * - printk() levels fixed
32 * Version 0.82 (99/07/08):
33 * - Handle stats correctly if the lowlevel driver is
34 * is not a comx one (locomx - z85230)
36 * Version 0.83 (99/07/15):
37 * - reset line_status when interface is down
39 * Version 0.84 (99/12/01):
40 * - comx_status should not check for IFF_UP (to report
41 * line status from dev->open())
44 #define VERSION "0.84"
46 #include <linux/config.h>
47 #include <linux/module.h>
48 #include <linux/version.h>
50 #include <linux/types.h>
51 #include <linux/sched.h>
52 #include <linux/netdevice.h>
53 #include <linux/proc_fs.h>
54 #include <asm/uaccess.h>
55 #include <linux/ctype.h>
56 #include <linux/init.h>
58 #ifdef CONFIG_KMOD
59 #include <linux/kmod.h>
60 #endif
62 #ifndef CONFIG_PROC_FS
63 #error For now, COMX really needs the /proc filesystem
64 #endif
66 #include "comx.h"
67 #include "syncppp.h"
69 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
70 MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
72 extern int comx_hw_comx_init(void);
73 extern int comx_hw_locomx_init(void);
74 extern int comx_hw_mixcom_init(void);
75 extern int comx_proto_hdlc_init(void);
76 extern int comx_proto_ppp_init(void);
77 extern int comx_proto_syncppp_init(void);
78 extern int comx_proto_lapb_init(void);
79 extern int comx_proto_fr_init(void);
81 static struct comx_hardware *comx_channels = NULL;
82 static struct comx_protocol *comx_lines = NULL;
84 static struct inode_operations comx_root_inode_ops = {
85 lookup: comx_lookup,
86 mkdir: comx_mkdir,
87 rmdir: comx_rmdir,
90 static int comx_delete_dentry(struct dentry *dentry);
91 static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
92 int size, struct proc_dir_entry *dir);
94 static struct dentry_operations comx_dentry_operations = {
95 d_delete: comx_delete_dentry,
99 static struct proc_dir_entry * comx_root_dir;
101 struct comx_debugflags_struct comx_debugflags[] = {
102 { "comx_rx", DEBUG_COMX_RX },
103 { "comx_tx", DEBUG_COMX_TX },
104 { "hw_tx", DEBUG_HW_TX },
105 { "hw_rx", DEBUG_HW_RX },
106 { "hdlc_keepalive", DEBUG_HDLC_KEEPALIVE },
107 { "comxppp", DEBUG_COMX_PPP },
108 { "comxlapb", DEBUG_COMX_LAPB },
109 { "dlci", DEBUG_COMX_DLCI },
110 { NULL, 0 }
114 int comx_debug(struct net_device *dev, char *fmt, ...)
116 struct comx_channel *ch = dev->priv;
117 char *page,*str;
118 va_list args;
119 int len;
121 if (!ch->debug_area) return 0;
123 if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM;
125 va_start(args, fmt);
126 len = vsprintf(str = page, fmt, args);
127 va_end(args);
129 if (len >= PAGE_SIZE) {
130 printk(KERN_ERR "comx_debug: PANIC! len = %d !!!\n", len);
131 free_page((unsigned long)page);
132 return -EINVAL;
135 while (len) {
136 int to_copy;
137 int free = (ch->debug_start - ch->debug_end + ch->debug_size)
138 % ch->debug_size;
140 to_copy = min( free ? free : ch->debug_size,
141 min (ch->debug_size - ch->debug_end, len) );
142 memcpy(ch->debug_area + ch->debug_end, str, to_copy);
143 str += to_copy;
144 len -= to_copy;
145 ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size;
146 if (ch->debug_start == ch->debug_end) // Full ? push start away
147 ch->debug_start = (ch->debug_start + len + 1) %
148 ch->debug_size;
149 ch->debug_file->size = (ch->debug_end - ch->debug_start +
150 ch->debug_size) % ch->debug_size;
153 free_page((unsigned long)page);
154 return 0;
157 int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg)
159 struct comx_channel *ch = dev->priv;
161 if (!ch->debug_area) return 0;
162 if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg);
163 if (!skb->len) comx_debug(dev, "%s: %s empty skb\n\n", dev->name, msg);
165 return comx_debug_bytes(dev, skb->data, skb->len, msg);
168 int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len,
169 char *msg)
171 int pos = 0;
172 struct comx_channel *ch = dev->priv;
174 if (!ch->debug_area) return 0;
176 comx_debug(dev, "%s: %s len %d\n", dev->name, msg, len);
178 while (pos != len) {
179 char line[80];
180 int i = 0;
182 memset(line, 0, 80);
183 sprintf(line,"%04d ", pos);
184 do {
185 sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]);
186 sprintf(line + 60 + (pos % 16), "%c",
187 isprint(bytes[pos]) ? bytes[pos] : '.');
188 pos++;
189 } while (pos != len && pos % 16);
191 while ( i++ != 78 ) if (line[i] == 0) line[i] = ' ';
192 line[77] = '\n';
193 line[78] = 0;
195 comx_debug(dev, "%s", line);
197 comx_debug(dev, "\n");
198 return 0;
201 static void comx_loadavg_timerfun(unsigned long d)
203 struct net_device *dev = (struct net_device *)d;
204 struct comx_channel *ch = dev->priv;
206 ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;
207 ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] =
208 ch->current_stats->tx_bytes;
210 ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size;
212 mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]);
215 #if 0
216 static void comx_reset_timerfun(unsigned long d)
218 struct net_device *dev = (struct net_device *)d;
219 struct comx_channel *ch = dev->priv;
221 if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {
222 if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {
223 ch->HW_reset(dev);
227 mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout);
229 #endif
231 static int comx_open(struct net_device *dev)
233 struct comx_channel *ch = dev->priv;
234 struct proc_dir_entry *comxdir = ch->procdir->subdir;
235 int ret=0;
237 if (!ch->protocol || !ch->hardware) return -ENODEV;
239 if ((ret = ch->HW_open(dev))) return ret;
240 if ((ret = ch->LINE_open(dev))) {
241 ch->HW_close(dev);
242 return ret;
245 for (; comxdir ; comxdir = comxdir->next) {
246 if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
247 strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
248 comxdir->mode = S_IFREG | 0444;
251 #if 0
252 ch->reset_pending = 1;
253 ch->reset_timeout = 30;
254 ch->reset_timer.function = comx_reset_timerfun;
255 ch->reset_timer.data = (unsigned long)dev;
256 ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout;
257 add_timer(&ch->reset_timer);
258 #endif
260 return 0;
263 static int comx_close(struct net_device *dev)
265 struct comx_channel *ch = dev->priv;
266 struct proc_dir_entry *comxdir = ch->procdir->subdir;
267 int ret = -ENODEV;
269 if (test_and_clear_bit(0, &ch->lineup_pending)) {
270 del_timer(&ch->lineup_timer);
273 #if 0
274 del_timer(&ch->reset_timer);
275 #endif
277 if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) {
278 ret = ch->LINE_close(dev);
281 if (ret) return ret;
283 if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) {
284 ret = ch->HW_close(dev);
287 ch->line_status=0;
289 for (; comxdir ; comxdir = comxdir->next) {
290 if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
291 strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
292 comxdir->mode = S_IFREG | 0644;
295 return ret;
298 void comx_status(struct net_device *dev, int status)
300 struct comx_channel *ch = dev->priv;
302 #if 0
303 if(status & (PROTO_UP | PROTO_LOOP)) {
304 clear_bit(0,&ch->reset_pending);
306 #endif
308 printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %s\n",
309 dev->name, status & LINE_UP ? "UP" : "DOWN",
310 status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ?
311 "UP" : "DOWN");
313 ch->line_status = status;
316 static int comx_xmit(struct sk_buff *skb, struct net_device *dev)
318 struct comx_channel *ch = dev->priv;
319 int rc;
321 if (skb->len > dev->mtu + dev->hard_header_len) {
322 printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %d\n", dev->name,
323 (int)skb->len, dev->mtu);
326 if (ch->debug_flags & DEBUG_COMX_TX) {
327 comx_debug_skb(dev, skb, "comx_xmit skb");
330 rc=ch->LINE_xmit(skb, dev);
331 // if (!rc) dev_kfree_skb(skb);
333 return rc;
336 static int comx_header(struct sk_buff *skb, struct net_device *dev,
337 unsigned short type, void *daddr, void *saddr, unsigned len)
339 struct comx_channel *ch = dev->priv;
341 if (ch->LINE_header) {
342 return (ch->LINE_header(skb, dev, type, daddr, saddr, len));
343 } else {
344 return 0;
348 static int comx_rebuild_header(struct sk_buff *skb)
350 struct net_device *dev = skb->dev;
351 struct comx_channel *ch = dev->priv;
353 if (ch->LINE_rebuild_header) {
354 return(ch->LINE_rebuild_header(skb));
355 } else {
356 return 0;
360 int comx_rx(struct net_device *dev, struct sk_buff *skb)
362 struct comx_channel *ch = dev->priv;
364 if (ch->debug_flags & DEBUG_COMX_RX) {
365 comx_debug_skb(dev, skb, "comx_rx skb");
367 if (skb) {
368 netif_rx(skb);
370 return 0;
373 static struct net_device_stats *comx_stats(struct net_device *dev)
375 struct comx_channel *ch = (struct comx_channel *)dev->priv;
377 return ch->current_stats;
380 void comx_lineup_func(unsigned long d)
382 struct net_device *dev = (struct net_device *)d;
383 struct comx_channel *ch = dev->priv;
385 del_timer(&ch->lineup_timer);
386 clear_bit(0, &ch->lineup_pending);
388 if (ch->LINE_status) {
389 ch->LINE_status(dev, ch->line_status |= LINE_UP);
393 #define LOADAVG(avg, off) (int) \
394 ((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) \
395 % ch->loadavg_size + off] - ch->avg_bytes[(ch->loadavg_counter - 1 \
396 - ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) \
397 % ch->loadavg_size + off]) / ch->loadavg[avg] * 8)
399 static int comx_statistics(struct net_device *dev, char *page)
401 struct comx_channel *ch = dev->priv;
402 int len = 0;
403 int tmp;
404 int i = 0;
405 char tmpstr[20];
406 int tmpstrlen = 0;
408 len += sprintf(page + len, "Interface administrative status is %s, "
409 "modem status is %s, protocol is %s\n",
410 dev->flags & IFF_UP ? "UP" : "DOWN",
411 ch->line_status & LINE_UP ? "UP" : "DOWN",
412 ch->line_status & PROTO_LOOP ? "LOOP" :
413 ch->line_status & PROTO_UP ? "UP" : "DOWN");
414 len += sprintf(page + len, "Modem status changes: %lu, Transmitter status "
415 "is %s, tbusy: %d\n", ch->current_stats->tx_carrier_errors, ch->HW_txe ?
416 ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", netif_running(dev));
417 len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (",
418 LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0));
419 tmpstr[0] = 0;
420 for (i=0; i != 3; i++) {
421 char tf;
423 tf = ch->loadavg[i] % 60 == 0 &&
424 ch->loadavg[i] / 60 > 0 ? 'm' : 's';
425 tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s",
426 ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf,
427 i == 2 ? ")\n" : "/");
429 len += sprintf(page + len,
430 "%s (output): %d / %d / %d bits/s (%s", tmpstr,
431 LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size),
432 LOADAVG(2, ch->loadavg_size), tmpstr);
434 len += sprintf(page + len, "Debug flags: ");
435 tmp = len; i = 0;
436 while (comx_debugflags[i].name) {
437 if (ch->debug_flags & comx_debugflags[i].value)
438 len += sprintf(page + len, "%s ",
439 comx_debugflags[i].name);
440 i++;
442 len += sprintf(page + len, "%s\n", tmp == len ? "none" : "");
444 len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, "
445 "aborts: %lu\n buffer overrun: %lu, pbuffer overrun: %lu\n"
446 "TX errors: underrun: %lu\n",
447 ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors,
448 ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors,
449 ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors,
450 ch->current_stats->tx_fifo_errors);
452 if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) {
453 len += ch->LINE_statistics(dev, page + len);
454 } else {
455 len += sprintf(page+len, "Line status: driver not initialized\n");
457 if (ch->HW_statistics && (ch->init_status & HW_OPEN)) {
458 len += ch->HW_statistics(dev, page + len);
459 } else {
460 len += sprintf(page+len, "Board status: driver not initialized\n");
463 return len;
466 static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
468 struct comx_channel *ch = dev->priv;
470 if (ch->LINE_ioctl) {
471 return(ch->LINE_ioctl(dev, ifr, cmd));
473 return -EINVAL;
476 static void comx_reset_dev(struct net_device *dev)
478 dev->open = comx_open;
479 dev->stop = comx_close;
480 dev->hard_start_xmit = comx_xmit;
481 dev->hard_header = comx_header;
482 dev->rebuild_header = comx_rebuild_header;
483 dev->get_stats = comx_stats;
484 dev->do_ioctl = comx_ioctl;
485 dev->change_mtu = NULL;
486 dev->tx_queue_len = 20;
487 dev->flags = IFF_NOARP;
490 static int comx_init_dev(struct net_device *dev)
492 struct comx_channel *ch;
494 if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) {
495 return -ENOMEM;
497 memset(ch, 0, sizeof(struct comx_channel));
499 ch->loadavg[0] = 5;
500 ch->loadavg[1] = 300;
501 ch->loadavg[2] = 900;
502 ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1;
503 if ((ch->avg_bytes = kmalloc(ch->loadavg_size *
504 sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) {
505 return -ENOMEM;
508 memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2);
509 ch->loadavg_counter = 0;
510 ch->loadavg_timer.function = comx_loadavg_timerfun;
511 ch->loadavg_timer.data = (unsigned long)dev;
512 ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0];
513 add_timer(&ch->loadavg_timer);
515 dev->priv = (void *)ch;
516 ch->dev = dev;
517 ch->line_status &= ~LINE_UP;
519 ch->current_stats = &ch->stats;
521 comx_reset_dev(dev);
522 return 0;
525 static int comx_read_proc(char *page, char **start, off_t off, int count,
526 int *eof, void *data)
528 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
529 struct net_device *dev = file->parent->data;
530 struct comx_channel *ch=(struct comx_channel *)dev->priv;
531 int len = 0;
533 if (strcmp(file->name, FILENAME_STATUS) == 0) {
534 len = comx_statistics(dev, page);
535 } else if (strcmp(file->name, FILENAME_HARDWARE) == 0) {
536 len = sprintf(page, "%s\n", ch->hardware ?
537 ch->hardware->name : HWNAME_NONE);
538 } else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) {
539 len = sprintf(page, "%s\n", ch->protocol ?
540 ch->protocol->name : PROTONAME_NONE);
541 } else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) {
542 len = sprintf(page, "%01d\n", ch->lineup_delay);
545 if (off >= len) {
546 *eof = 1;
547 return 0;
550 *start = page + off;
551 if (count >= len - off) {
552 *eof = 1;
554 return( min(count, len - off) );
558 static int comx_root_read_proc(char *page, char **start, off_t off, int count,
559 int *eof, void *data)
561 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
562 struct comx_hardware *hw;
563 struct comx_protocol *line;
565 int len = 0;
567 if (strcmp(file->name, FILENAME_HARDWARELIST) == 0) {
568 for(hw=comx_channels;hw;hw=hw->next)
569 len+=sprintf(page+len, "%s\n", hw->name);
570 } else if (strcmp(file->name, FILENAME_PROTOCOLLIST) == 0) {
571 for(line=comx_lines;line;line=line->next)
572 len+=sprintf(page+len, "%s\n", line->name);
575 if (off >= len) {
576 *eof = 1;
577 return 0;
580 *start = page + off;
581 if (count >= len - off) {
582 *eof = 1;
584 return( min(count, len - off) );
589 static int comx_write_proc(struct file *file, const char *buffer, u_long count,
590 void *data)
592 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
593 struct net_device *dev = (struct net_device *)entry->parent->data;
594 struct comx_channel *ch=(struct comx_channel *)dev->priv;
595 char *page;
596 struct comx_hardware *hw = comx_channels;
597 struct comx_protocol *line = comx_lines;
598 char str[30];
599 int ret=0;
601 if (count > PAGE_SIZE) {
602 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
603 return -ENOSPC;
606 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
608 copy_from_user(page, buffer, count);
610 if (*(page + count - 1) == '\n') *(page + count - 1) = 0;
612 if (strcmp(entry->name, FILENAME_DEBUG) == 0) {
613 int i;
614 int ret = 0;
616 if ((i = simple_strtoul(page, NULL, 10)) != 0) {
617 unsigned long flags;
619 save_flags(flags); cli();
620 if (ch->debug_area) kfree(ch->debug_area);
621 if ((ch->debug_area = kmalloc(ch->debug_size = i,
622 GFP_KERNEL)) == NULL) {
623 ret = -ENOMEM;
625 ch->debug_start = ch->debug_end = 0;
626 restore_flags(flags);
627 free_page((unsigned long)page);
628 return count;
631 if (*page != '+' && *page != '-') {
632 free_page((unsigned long)page);
633 return -EINVAL;
635 while (comx_debugflags[i].value &&
636 strncmp(comx_debugflags[i].name, page + 1,
637 strlen(comx_debugflags[i].name))) {
638 i++;
641 if (comx_debugflags[i].value == 0) {
642 printk(KERN_ERR "Invalid debug option\n");
643 free_page((unsigned long)page);
644 return -EINVAL;
646 if (*page == '+') {
647 ch->debug_flags |= comx_debugflags[i].value;
648 } else {
649 ch->debug_flags &= ~comx_debugflags[i].value;
651 } else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) {
652 if(strlen(page)>10) {
653 free_page((unsigned long)page);
654 return -EINVAL;
656 while (hw) {
657 if (strcmp(hw->name, page) == 0) {
658 break;
659 } else {
660 hw = hw->next;
663 #ifdef CONFIG_KMOD
664 if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){
665 sprintf(str,"comx-hw-%s",page);
666 request_module(str);
668 hw=comx_channels;
669 while (hw) {
670 if (comx_strcasecmp(hw->name, page) == 0) {
671 break;
672 } else {
673 hw = hw->next;
676 #endif
678 if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw) {
679 free_page((unsigned long)page);
680 return -ENODEV;
682 if (ch->init_status & HW_OPEN) {
683 free_page((unsigned long)page);
684 return -EBUSY;
686 if (ch->hardware && ch->hardware->hw_exit &&
687 (ret=ch->hardware->hw_exit(dev))) {
688 free_page((unsigned long)page);
689 return ret;
691 ch->hardware = hw;
692 entry->size = strlen(page) + 1;
693 if (hw && hw->hw_init) hw->hw_init(dev);
694 } else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) {
695 if(strlen(page)>10) {
696 free_page((unsigned long)page);
697 return -EINVAL;
699 while (line) {
700 if (comx_strcasecmp(line->name, page) == 0) {
701 break;
702 } else {
703 line = line->next;
706 #ifdef CONFIG_KMOD
707 if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
708 sprintf(str,"comx-proto-%s",page);
709 request_module(str);
711 line=comx_lines;
712 while (line) {
713 if (comx_strcasecmp(line->name, page) == 0) {
714 break;
715 } else {
716 line = line->next;
719 #endif
721 if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) {
722 free_page((unsigned long)page);
723 return -ENODEV;
726 if (ch->init_status & LINE_OPEN) {
727 free_page((unsigned long)page);
728 return -EBUSY;
731 if (ch->protocol && ch->protocol->line_exit &&
732 (ret=ch->protocol->line_exit(dev))) {
733 free_page((unsigned long)page);
734 return ret;
736 ch->protocol = line;
737 entry->size = strlen(page) + 1;
738 comx_reset_dev(dev);
739 if (line && line->line_init) line->line_init(dev);
740 } else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) {
741 int i;
743 if ((i = simple_strtoul(page, NULL, 10)) != 0) {
744 if (i >=0 && i < 10) {
745 ch->lineup_delay = i;
746 } else {
747 printk(KERN_ERR "comx: invalid lineup_delay value\n");
752 free_page((unsigned long)page);
753 return count;
756 static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode)
758 struct proc_dir_entry *new_dir, *debug_file;
759 struct net_device *dev;
760 struct comx_channel *ch;
762 if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR,
763 comx_root_dir)) == NULL) {
764 return -EIO;
767 new_dir->nlink = 2;
768 new_dir->data = NULL; // ide jon majd a struct dev
770 /* Ezek kellenek */
771 if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644,
772 strlen(HWNAME_NONE) + 1, new_dir)) {
773 return -ENOMEM;
775 if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644,
776 strlen(PROTONAME_NONE) + 1, new_dir)) {
777 return -ENOMEM;
779 if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) {
780 return -ENOMEM;
782 if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) {
783 return -ENOMEM;
786 if ((debug_file = create_proc_entry(FILENAME_DEBUG,
787 S_IFREG | 0644, new_dir)) == NULL) {
788 return -ENOMEM;
790 debug_file->data = (void *)debug_file;
791 debug_file->read_proc = NULL; // see below
792 debug_file->write_proc = &comx_write_proc;
793 debug_file->nlink = 1;
795 if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) {
796 return -ENOMEM;
798 memset(dev, 0, sizeof(struct net_device));
799 strcpy(dev->name, (char *)new_dir->name);
800 dev->init = comx_init_dev;
802 if (register_netdevice(dev)) {
803 return -EIO;
805 ch=dev->priv;
806 if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device),
807 GFP_KERNEL)) == NULL) {
808 return -ENOMEM;
810 memset(ch->if_ptr, 0, sizeof(struct ppp_device));
811 ch->debug_file = debug_file;
812 ch->procdir = new_dir;
813 new_dir->data = dev;
815 ch->debug_start = ch->debug_end = 0;
816 if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE,
817 GFP_KERNEL)) == NULL) {
818 return -ENOMEM;
821 ch->lineup_delay = DEFAULT_LINEUP_DELAY;
823 MOD_INC_USE_COUNT;
824 return 0;
827 static int comx_rmdir(struct inode *dir, struct dentry *dentry)
829 struct proc_dir_entry *entry = dentry->d_inode->u.generic_ip;
830 struct net_device *dev = entry->data;
831 struct comx_channel *ch = dev->priv;
832 int ret;
834 if (dev->flags & IFF_UP) {
835 printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
836 return -EBUSY;
839 if (ch->protocol && ch->protocol->line_exit &&
840 (ret=ch->protocol->line_exit(dev))) {
841 return ret;
843 if (ch->hardware && ch->hardware->hw_exit &&
844 (ret=ch->hardware->hw_exit(dev))) {
845 if(ch->protocol && ch->protocol->line_init) {
846 ch->protocol->line_init(dev);
848 return ret;
850 ch->protocol = NULL;
851 ch->hardware = NULL;
853 del_timer(&ch->loadavg_timer);
854 kfree(ch->avg_bytes);
856 unregister_netdev(dev);
857 if (ch->debug_area) {
858 kfree(ch->debug_area);
860 if (dev->priv) {
861 kfree(dev->priv);
863 kfree(dev);
865 remove_proc_entry(FILENAME_DEBUG, entry);
866 remove_proc_entry(FILENAME_LINEUPDELAY, entry);
867 remove_proc_entry(FILENAME_STATUS, entry);
868 remove_proc_entry(FILENAME_HARDWARE, entry);
869 remove_proc_entry(FILENAME_PROTOCOL, entry);
870 remove_proc_entry(dentry->d_name.name, comx_root_dir);
872 MOD_DEC_USE_COUNT;
873 return 0;
876 static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry)
878 struct proc_dir_entry *de;
879 struct inode *inode = NULL;
881 if ((de = (struct proc_dir_entry *) dir->u.generic_ip) != NULL) {
882 for (de = de->subdir ; de ; de = de->next) {
883 if ((de && de->low_ino) &&
884 (de->namelen == dentry->d_name.len) &&
885 (memcmp(dentry->d_name.name, de->name,
886 de->namelen) == 0)) {
887 if ((inode = proc_get_inode(dir->i_sb,
888 de->low_ino, de)) == NULL) {
889 printk(KERN_ERR "COMX: lookup error\n");
890 return ERR_PTR(-EINVAL);
892 break;
896 dentry->d_op = &comx_dentry_operations;
897 d_add(dentry, inode);
898 return NULL;
901 int comx_strcasecmp(const char *cs, const char *ct)
903 register signed char __res;
905 while (1) {
906 if ((__res = toupper(*cs) - toupper(*ct++)) != 0 || !*cs++) {
907 break;
910 return __res;
913 static int comx_delete_dentry(struct dentry *dentry)
915 return 1;
918 static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
919 int size, struct proc_dir_entry *dir)
921 struct proc_dir_entry *new_file;
923 if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
924 new_file->data = (void *)new_file;
925 new_file->read_proc = &comx_read_proc;
926 new_file->write_proc = &comx_write_proc;
927 new_file->size = size;
928 new_file->nlink = 1;
930 return(new_file);
933 int comx_register_hardware(struct comx_hardware *comx_hw)
935 struct comx_hardware *hw = comx_channels;
937 if (!hw) {
938 comx_channels = comx_hw;
939 } else {
940 while (hw->next != NULL && strcmp(comx_hw->name, hw->name) != 0) {
941 hw = hw->next;
943 if (strcmp(comx_hw->name, hw->name) == 0) {
944 return -1;
946 hw->next = comx_hw;
949 printk(KERN_INFO "COMX: driver for hardware type %s, version %s\n", comx_hw->name, comx_hw->version);
950 return 0;
953 int comx_unregister_hardware(char *name)
955 struct comx_hardware *hw = comx_channels;
957 if (!hw) {
958 return -1;
961 if (strcmp(hw->name, name) == 0) {
962 comx_channels = comx_channels->next;
963 return 0;
966 while (hw->next != NULL && strcmp(hw->next->name,name) != 0) {
967 hw = hw->next;
970 if (hw->next != NULL && strcmp(hw->next->name, name) == 0) {
971 hw->next = hw->next->next;
972 return 0;
974 return -1;
977 int comx_register_protocol(struct comx_protocol *comx_line)
979 struct comx_protocol *pr = comx_lines;
981 if (!pr) {
982 comx_lines = comx_line;
983 } else {
984 while (pr->next != NULL && strcmp(comx_line->name, pr->name) !=0) {
985 pr = pr->next;
987 if (strcmp(comx_line->name, pr->name) == 0) {
988 return -1;
990 pr->next = comx_line;
993 printk(KERN_INFO "COMX: driver for protocol type %s, version %s\n", comx_line->name, comx_line->version);
994 return 0;
997 int comx_unregister_protocol(char *name)
999 struct comx_protocol *pr = comx_lines;
1001 if (!pr) {
1002 return -1;
1005 if (strcmp(pr->name, name) == 0) {
1006 comx_lines = comx_lines->next;
1007 return 0;
1010 while (pr->next != NULL && strcmp(pr->next->name,name) != 0) {
1011 pr = pr->next;
1014 if (pr->next != NULL && strcmp(pr->next->name, name) == 0) {
1015 pr->next = pr->next->next;
1016 return 0;
1018 return -1;
1021 #ifdef MODULE
1022 #define comx_init init_module
1023 #endif
1025 int __init comx_init(void)
1027 struct proc_dir_entry *new_file;
1029 comx_root_dir = create_proc_entry("comx",
1030 S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root);
1031 if (!comx_root_dir)
1032 return -ENOMEM;
1033 comx_root_dir->proc_iops = &comx_root_inode_ops;
1035 if ((new_file = create_proc_entry(FILENAME_HARDWARELIST,
1036 S_IFREG | 0444, comx_root_dir)) == NULL) {
1037 return -ENOMEM;
1040 new_file->data = new_file;
1041 new_file->read_proc = &comx_root_read_proc;
1042 new_file->write_proc = NULL;
1043 new_file->nlink = 1;
1045 if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST,
1046 S_IFREG | 0444, comx_root_dir)) == NULL) {
1047 return -ENOMEM;
1050 new_file->data = new_file;
1051 new_file->read_proc = &comx_root_read_proc;
1052 new_file->write_proc = NULL;
1053 new_file->nlink = 1;
1056 printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>\n",
1057 VERSION);
1059 #ifndef MODULE
1060 #ifdef CONFIG_COMX_HW_COMX
1061 comx_hw_comx_init();
1062 #endif
1063 #ifdef CONFIG_COMX_HW_LOCOMX
1064 comx_hw_locomx_init();
1065 #endif
1066 #ifdef CONFIG_COMX_HW_MIXCOM
1067 comx_hw_mixcom_init();
1068 #endif
1069 #ifdef CONFIG_COMX_PROTO_HDLC
1070 comx_proto_hdlc_init();
1071 #endif
1072 #ifdef CONFIG_COMX_PROTO_PPP
1073 comx_proto_ppp_init();
1074 #endif
1075 #ifdef CONFIG_COMX_PROTO_LAPB
1076 comx_proto_lapb_init();
1077 #endif
1078 #ifdef CONFIG_COMX_PROTO_FR
1079 comx_proto_fr_init();
1080 #endif
1081 #endif
1083 return 0;
1086 #ifdef MODULE
1087 void cleanup_module(void)
1089 remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
1090 remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
1091 remove_proc_entry(comx_root_dir->name, &proc_root);
1093 #endif
1095 EXPORT_SYMBOL(comx_register_hardware);
1096 EXPORT_SYMBOL(comx_unregister_hardware);
1097 EXPORT_SYMBOL(comx_register_protocol);
1098 EXPORT_SYMBOL(comx_unregister_protocol);
1099 EXPORT_SYMBOL(comx_debug_skb);
1100 EXPORT_SYMBOL(comx_debug_bytes);
1101 EXPORT_SYMBOL(comx_debug);
1102 EXPORT_SYMBOL(comx_lineup_func);
1103 EXPORT_SYMBOL(comx_status);
1104 EXPORT_SYMBOL(comx_rx);
1105 EXPORT_SYMBOL(comx_strcasecmp);
1106 EXPORT_SYMBOL(comx_root_dir);