2 * Device driver framework for the COMX line of synchronous serial boards
4 * for Linux kernel 2.2.X / 2.4.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.
14 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.85)
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.
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
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
35 * Version 0.82 (99/07/08):
36 * - Handle stats correctly if the lowlevel driver is
37 * is not a comx one (locomx - z85230)
39 * Version 0.83 (99/07/15):
40 * - reset line_status when interface is down
42 * Version 0.84 (99/12/01):
43 * - comx_status should not check for IFF_UP (to report
44 * line status from dev->open())
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
50 * Changed (00/10/29, Henner Eisen):
51 * - comx_rx() / comxlapb_data_indication() return status.
54 #define VERSION "0.85"
56 #include <linux/config.h>
57 #include <linux/module.h>
59 #include <linux/types.h>
60 #include <linux/jiffies.h>
61 #include <linux/netdevice.h>
62 #include <linux/proc_fs.h>
63 #include <asm/uaccess.h>
64 #include <linux/ctype.h>
65 #include <linux/init.h>
66 #include <linux/smp_lock.h>
69 #include <linux/kmod.h>
72 #ifndef CONFIG_PROC_FS
73 #error For now, COMX really needs the /proc filesystem
76 #include <net/syncppp.h>
79 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
80 MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
81 MODULE_LICENSE("GPL");
83 static struct comx_hardware *comx_channels = NULL;
84 static struct comx_protocol *comx_lines = NULL;
86 static int comx_mkdir(struct inode *, struct dentry *, int);
87 static int comx_rmdir(struct inode *, struct dentry *);
88 static struct dentry *comx_lookup(struct inode *, struct dentry *, struct nameidata *);
90 static struct inode_operations comx_root_inode_ops = {
91 .lookup = comx_lookup,
96 static int comx_delete_dentry(struct dentry *dentry);
97 static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
98 int size, struct proc_dir_entry *dir);
100 static struct dentry_operations comx_dentry_operations = {
101 .d_delete = comx_delete_dentry,
105 static struct proc_dir_entry * comx_root_dir;
107 struct comx_debugflags_struct comx_debugflags[] = {
108 { "comx_rx", DEBUG_COMX_RX },
109 { "comx_tx", DEBUG_COMX_TX },
110 { "hw_tx", DEBUG_HW_TX },
111 { "hw_rx", DEBUG_HW_RX },
112 { "hdlc_keepalive", DEBUG_HDLC_KEEPALIVE },
113 { "comxppp", DEBUG_COMX_PPP },
114 { "comxlapb", DEBUG_COMX_LAPB },
115 { "dlci", DEBUG_COMX_DLCI },
120 int comx_debug(struct net_device *dev, char *fmt, ...)
122 struct comx_channel *ch = dev->priv;
127 if (!ch->debug_area) return 0;
129 if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM;
132 len = vsprintf(str = page, fmt, args);
135 if (len >= PAGE_SIZE) {
136 printk(KERN_ERR "comx_debug: PANIC! len = %d !!!\n", len);
137 free_page((unsigned long)page);
143 int free = (ch->debug_start - ch->debug_end + ch->debug_size)
146 to_copy = min_t(int, free ? free : ch->debug_size,
147 min_t(int, ch->debug_size - ch->debug_end, len));
148 memcpy(ch->debug_area + ch->debug_end, str, to_copy);
151 ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size;
152 if (ch->debug_start == ch->debug_end) // Full ? push start away
153 ch->debug_start = (ch->debug_start + len + 1) %
155 ch->debug_file->size = (ch->debug_end - ch->debug_start +
156 ch->debug_size) % ch->debug_size;
159 free_page((unsigned long)page);
163 int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg)
165 struct comx_channel *ch = dev->priv;
167 if (!ch->debug_area) return 0;
168 if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg);
169 if (!skb->len) comx_debug(dev, "%s: %s empty skb\n\n", dev->name, msg);
171 return comx_debug_bytes(dev, skb->data, skb->len, msg);
174 int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len,
178 struct comx_channel *ch = dev->priv;
180 if (!ch->debug_area) return 0;
182 comx_debug(dev, "%s: %s len %d\n", dev->name, msg, len);
189 sprintf(line,"%04d ", pos);
191 sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]);
192 sprintf(line + 60 + (pos % 16), "%c",
193 isprint(bytes[pos]) ? bytes[pos] : '.');
195 } while (pos != len && pos % 16);
197 while ( i++ != 78 ) if (line[i] == 0) line[i] = ' ';
201 comx_debug(dev, "%s", line);
203 comx_debug(dev, "\n");
207 static void comx_loadavg_timerfun(unsigned long d)
209 struct net_device *dev = (struct net_device *)d;
210 struct comx_channel *ch = dev->priv;
212 ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;
213 ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] =
214 ch->current_stats->tx_bytes;
216 ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size;
218 mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]);
222 static void comx_reset_timerfun(unsigned long d)
224 struct net_device *dev = (struct net_device *)d;
225 struct comx_channel *ch = dev->priv;
227 if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {
228 if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {
233 mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout);
237 static int comx_open(struct net_device *dev)
239 struct comx_channel *ch = dev->priv;
240 struct proc_dir_entry *comxdir = ch->procdir->subdir;
243 if (!ch->protocol || !ch->hardware) return -ENODEV;
245 if ((ret = ch->HW_open(dev))) return ret;
246 if ((ret = ch->LINE_open(dev))) {
251 for (; comxdir ; comxdir = comxdir->next) {
252 if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
253 strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
254 comxdir->mode = S_IFREG | 0444;
258 ch->reset_pending = 1;
259 ch->reset_timeout = 30;
260 ch->reset_timer.function = comx_reset_timerfun;
261 ch->reset_timer.data = (unsigned long)dev;
262 ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout;
263 add_timer(&ch->reset_timer);
269 static int comx_close(struct net_device *dev)
271 struct comx_channel *ch = dev->priv;
272 struct proc_dir_entry *comxdir = ch->procdir->subdir;
275 if (test_and_clear_bit(0, &ch->lineup_pending)) {
276 del_timer(&ch->lineup_timer);
280 del_timer(&ch->reset_timer);
283 if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) {
284 ret = ch->LINE_close(dev);
289 if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) {
290 ret = ch->HW_close(dev);
295 for (; comxdir ; comxdir = comxdir->next) {
296 if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
297 strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
298 comxdir->mode = S_IFREG | 0644;
304 void comx_status(struct net_device *dev, int status)
306 struct comx_channel *ch = dev->priv;
309 if(status & (PROTO_UP | PROTO_LOOP)) {
310 clear_bit(0,&ch->reset_pending);
314 printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %s\n",
315 dev->name, status & LINE_UP ? "UP" : "DOWN",
316 status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ?
319 ch->line_status = status;
322 static int comx_xmit(struct sk_buff *skb, struct net_device *dev)
324 struct comx_channel *ch = dev->priv;
327 if (skb->len > dev->mtu + dev->hard_header_len) {
328 printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %d\n", dev->name,
329 (int)skb->len, dev->mtu);
332 if (ch->debug_flags & DEBUG_COMX_TX) {
333 comx_debug_skb(dev, skb, "comx_xmit skb");
336 rc=ch->LINE_xmit(skb, dev);
337 // if (!rc) dev_kfree_skb(skb);
342 static int comx_header(struct sk_buff *skb, struct net_device *dev,
343 unsigned short type, void *daddr, void *saddr, unsigned len)
345 struct comx_channel *ch = dev->priv;
347 if (ch->LINE_header) {
348 return (ch->LINE_header(skb, dev, type, daddr, saddr, len));
354 static int comx_rebuild_header(struct sk_buff *skb)
356 struct net_device *dev = skb->dev;
357 struct comx_channel *ch = dev->priv;
359 if (ch->LINE_rebuild_header) {
360 return(ch->LINE_rebuild_header(skb));
366 int comx_rx(struct net_device *dev, struct sk_buff *skb)
368 struct comx_channel *ch = dev->priv;
370 if (ch->debug_flags & DEBUG_COMX_RX) {
371 comx_debug_skb(dev, skb, "comx_rx skb");
375 dev->last_rx = jiffies;
380 static struct net_device_stats *comx_stats(struct net_device *dev)
382 struct comx_channel *ch = dev->priv;
384 return ch->current_stats;
387 void comx_lineup_func(unsigned long d)
389 struct net_device *dev = (struct net_device *)d;
390 struct comx_channel *ch = dev->priv;
392 del_timer(&ch->lineup_timer);
393 clear_bit(0, &ch->lineup_pending);
395 if (ch->LINE_status) {
396 ch->LINE_status(dev, ch->line_status |= LINE_UP);
400 #define LOADAVG(avg, off) (int) \
401 ((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) \
402 % ch->loadavg_size + off] - ch->avg_bytes[(ch->loadavg_counter - 1 \
403 - ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) \
404 % ch->loadavg_size + off]) / ch->loadavg[avg] * 8)
406 static int comx_statistics(struct net_device *dev, char *page)
408 struct comx_channel *ch = dev->priv;
415 len += sprintf(page + len, "Interface administrative status is %s, "
416 "modem status is %s, protocol is %s\n",
417 dev->flags & IFF_UP ? "UP" : "DOWN",
418 ch->line_status & LINE_UP ? "UP" : "DOWN",
419 ch->line_status & PROTO_LOOP ? "LOOP" :
420 ch->line_status & PROTO_UP ? "UP" : "DOWN");
421 len += sprintf(page + len, "Modem status changes: %lu, Transmitter status "
422 "is %s, tbusy: %d\n", ch->current_stats->tx_carrier_errors, ch->HW_txe ?
423 ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", netif_running(dev));
424 len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (",
425 LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0));
427 for (i=0; i != 3; i++) {
430 tf = ch->loadavg[i] % 60 == 0 &&
431 ch->loadavg[i] / 60 > 0 ? 'm' : 's';
432 tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s",
433 ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf,
434 i == 2 ? ")\n" : "/");
436 len += sprintf(page + len,
437 "%s (output): %d / %d / %d bits/s (%s", tmpstr,
438 LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size),
439 LOADAVG(2, ch->loadavg_size), tmpstr);
441 len += sprintf(page + len, "Debug flags: ");
443 while (comx_debugflags[i].name) {
444 if (ch->debug_flags & comx_debugflags[i].value)
445 len += sprintf(page + len, "%s ",
446 comx_debugflags[i].name);
449 len += sprintf(page + len, "%s\n", tmp == len ? "none" : "");
451 len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, "
452 "aborts: %lu\n buffer overrun: %lu, pbuffer overrun: %lu\n"
453 "TX errors: underrun: %lu\n",
454 ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors,
455 ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors,
456 ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors,
457 ch->current_stats->tx_fifo_errors);
459 if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) {
460 len += ch->LINE_statistics(dev, page + len);
462 len += sprintf(page+len, "Line status: driver not initialized\n");
464 if (ch->HW_statistics && (ch->init_status & HW_OPEN)) {
465 len += ch->HW_statistics(dev, page + len);
467 len += sprintf(page+len, "Board status: driver not initialized\n");
473 static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
475 struct comx_channel *ch = dev->priv;
477 if (ch->LINE_ioctl) {
478 return(ch->LINE_ioctl(dev, ifr, cmd));
483 static void comx_reset_dev(struct net_device *dev)
485 dev->open = comx_open;
486 dev->stop = comx_close;
487 dev->hard_start_xmit = comx_xmit;
488 dev->hard_header = comx_header;
489 dev->rebuild_header = comx_rebuild_header;
490 dev->get_stats = comx_stats;
491 dev->do_ioctl = comx_ioctl;
492 dev->change_mtu = NULL;
493 dev->tx_queue_len = 20;
494 dev->flags = IFF_NOARP;
497 static int comx_init_dev(struct net_device *dev)
499 struct comx_channel *ch;
501 if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) {
504 memset(ch, 0, sizeof(struct comx_channel));
507 ch->loadavg[1] = 300;
508 ch->loadavg[2] = 900;
509 ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1;
510 if ((ch->avg_bytes = kmalloc(ch->loadavg_size *
511 sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) {
516 memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2);
517 ch->loadavg_counter = 0;
518 ch->loadavg_timer.function = comx_loadavg_timerfun;
519 ch->loadavg_timer.data = (unsigned long)dev;
520 ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0];
521 add_timer(&ch->loadavg_timer);
523 dev->priv = (void *)ch;
525 ch->line_status &= ~LINE_UP;
527 ch->current_stats = &ch->stats;
533 static int comx_read_proc(char *page, char **start, off_t off, int count,
534 int *eof, void *data)
536 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
537 struct net_device *dev = file->parent->data;
538 struct comx_channel *ch = dev->priv;
541 if (strcmp(file->name, FILENAME_STATUS) == 0) {
542 len = comx_statistics(dev, page);
543 } else if (strcmp(file->name, FILENAME_HARDWARE) == 0) {
544 len = sprintf(page, "%s\n", ch->hardware ?
545 ch->hardware->name : HWNAME_NONE);
546 } else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) {
547 len = sprintf(page, "%s\n", ch->protocol ?
548 ch->protocol->name : PROTONAME_NONE);
549 } else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) {
550 len = sprintf(page, "%01d\n", ch->lineup_delay);
559 if (count >= len - off) {
562 return min_t(int, count, len - off);
566 static int comx_root_read_proc(char *page, char **start, off_t off, int count,
567 int *eof, void *data)
569 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
570 struct comx_hardware *hw;
571 struct comx_protocol *line;
575 if (strcmp(file->name, FILENAME_HARDWARELIST) == 0) {
576 for(hw=comx_channels;hw;hw=hw->next)
577 len+=sprintf(page+len, "%s\n", hw->name);
578 } else if (strcmp(file->name, FILENAME_PROTOCOLLIST) == 0) {
579 for(line=comx_lines;line;line=line->next)
580 len+=sprintf(page+len, "%s\n", line->name);
589 if (count >= len - off) {
592 return min_t(int, count, len - off);
597 static int comx_write_proc(struct file *file, const char *buffer, u_long count,
600 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
601 struct net_device *dev = (struct net_device *)entry->parent->data;
602 struct comx_channel *ch = dev->priv;
604 struct comx_hardware *hw = comx_channels;
605 struct comx_protocol *line = comx_lines;
608 if (count > PAGE_SIZE) {
609 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
613 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
615 if(copy_from_user(page, buffer, count))
621 if (page[count-1] == '\n')
622 page[count-1] = '\0';
623 else if (count < PAGE_SIZE)
625 else if (page[count]) {
630 if (strcmp(entry->name, FILENAME_DEBUG) == 0) {
634 if ((i = simple_strtoul(page, NULL, 10)) != 0) {
637 save_flags(flags); cli();
638 if (ch->debug_area) kfree(ch->debug_area);
639 if ((ch->debug_area = kmalloc(ch->debug_size = i,
640 GFP_KERNEL)) == NULL) {
643 ch->debug_start = ch->debug_end = 0;
644 restore_flags(flags);
645 free_page((unsigned long)page);
646 return ret ? ret : count;
649 if (*page != '+' && *page != '-') {
650 free_page((unsigned long)page);
653 while (comx_debugflags[i].value &&
654 strncmp(comx_debugflags[i].name, page + 1,
655 strlen(comx_debugflags[i].name))) {
659 if (comx_debugflags[i].value == 0) {
660 printk(KERN_ERR "Invalid debug option\n");
661 free_page((unsigned long)page);
665 ch->debug_flags |= comx_debugflags[i].value;
667 ch->debug_flags &= ~comx_debugflags[i].value;
669 } else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) {
670 if(strlen(page)>10) {
671 free_page((unsigned long)page);
675 if (strcmp(hw->name, page) == 0) {
682 if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){
683 request_module("comx-hw-%s",page);
687 if (comx_strcasecmp(hw->name, page) == 0) {
695 if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw) {
696 free_page((unsigned long)page);
699 if (ch->init_status & HW_OPEN) {
700 free_page((unsigned long)page);
703 if (ch->hardware && ch->hardware->hw_exit &&
704 (ret=ch->hardware->hw_exit(dev))) {
705 free_page((unsigned long)page);
709 entry->size = strlen(page) + 1;
710 if (hw && hw->hw_init) hw->hw_init(dev);
711 } else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) {
712 if(strlen(page)>10) {
713 free_page((unsigned long)page);
717 if (comx_strcasecmp(line->name, page) == 0) {
724 if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
725 request_module("comx-proto-%s",page);
729 if (comx_strcasecmp(line->name, page) == 0) {
737 if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) {
738 free_page((unsigned long)page);
742 if (ch->init_status & LINE_OPEN) {
743 free_page((unsigned long)page);
747 if (ch->protocol && ch->protocol->line_exit &&
748 (ret=ch->protocol->line_exit(dev))) {
749 free_page((unsigned long)page);
753 entry->size = strlen(page) + 1;
755 if (line && line->line_init) line->line_init(dev);
756 } else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) {
759 if ((i = simple_strtoul(page, NULL, 10)) != 0) {
760 if (i >=0 && i < 10) {
761 ch->lineup_delay = i;
763 printk(KERN_ERR "comx: invalid lineup_delay value\n");
768 free_page((unsigned long)page);
772 static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode)
774 struct proc_dir_entry *new_dir, *debug_file;
775 struct net_device *dev;
776 struct comx_channel *ch;
779 if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) {
782 memset(dev, 0, sizeof(struct net_device));
785 if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR,
786 comx_root_dir)) == NULL) {
791 new_dir->data = NULL; // ide jon majd a struct dev
794 if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644,
795 strlen(HWNAME_NONE) + 1, new_dir)) {
796 goto cleanup_new_dir;
798 if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644,
799 strlen(PROTONAME_NONE) + 1, new_dir)) {
800 goto cleanup_filename_hardware;
802 if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) {
803 goto cleanup_filename_protocol;
805 if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) {
806 goto cleanup_filename_status;
809 if ((debug_file = create_proc_entry(FILENAME_DEBUG,
810 S_IFREG | 0644, new_dir)) == NULL) {
811 goto cleanup_filename_lineupdelay;
813 debug_file->data = (void *)debug_file;
814 debug_file->read_proc = NULL; // see below
815 debug_file->write_proc = &comx_write_proc;
816 debug_file->nlink = 1;
818 strcpy(dev->name, (char *)new_dir->name);
819 dev->init = comx_init_dev;
821 if (register_netdevice(dev)) {
822 goto cleanup_filename_debug;
825 if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device),
826 GFP_KERNEL)) == NULL) {
827 goto cleanup_register;
829 memset(ch->if_ptr, 0, sizeof(struct ppp_device));
830 ch->debug_file = debug_file;
831 ch->procdir = new_dir;
834 ch->debug_start = ch->debug_end = 0;
835 if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE,
836 GFP_KERNEL)) == NULL) {
841 ch->lineup_delay = DEFAULT_LINEUP_DELAY;
849 unregister_netdevice(dev);
850 cleanup_filename_debug:
851 remove_proc_entry(FILENAME_DEBUG, new_dir);
852 cleanup_filename_lineupdelay:
853 remove_proc_entry(FILENAME_LINEUPDELAY, new_dir);
854 cleanup_filename_status:
855 remove_proc_entry(FILENAME_STATUS, new_dir);
856 cleanup_filename_protocol:
857 remove_proc_entry(FILENAME_PROTOCOL, new_dir);
858 cleanup_filename_hardware:
859 remove_proc_entry(FILENAME_HARDWARE, new_dir);
861 remove_proc_entry(dentry->d_name.name, comx_root_dir);
868 static int comx_rmdir(struct inode *dir, struct dentry *dentry)
870 struct proc_dir_entry *entry = PDE(dentry->d_inode);
871 struct net_device *dev;
872 struct comx_channel *ch;
878 if (dev->flags & IFF_UP) {
879 printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
884 if (ch->protocol && ch->protocol->line_exit &&
885 (ret=ch->protocol->line_exit(dev))) {
889 if (ch->hardware && ch->hardware->hw_exit &&
890 (ret=ch->hardware->hw_exit(dev))) {
891 if(ch->protocol && ch->protocol->line_init) {
892 ch->protocol->line_init(dev);
900 del_timer(&ch->loadavg_timer);
901 kfree(ch->avg_bytes);
903 unregister_netdev(dev);
904 if (ch->debug_area) {
905 kfree(ch->debug_area);
912 remove_proc_entry(FILENAME_DEBUG, entry);
913 remove_proc_entry(FILENAME_LINEUPDELAY, entry);
914 remove_proc_entry(FILENAME_STATUS, entry);
915 remove_proc_entry(FILENAME_HARDWARE, entry);
916 remove_proc_entry(FILENAME_PROTOCOL, entry);
917 remove_proc_entry(dentry->d_name.name, comx_root_dir);
924 static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
926 struct proc_dir_entry *de;
927 struct inode *inode = NULL;
930 if ((de = PDE(dir)) != NULL) {
931 for (de = de->subdir ; de ; de = de->next) {
932 if ((de->namelen == dentry->d_name.len) &&
933 (memcmp(dentry->d_name.name, de->name,
934 de->namelen) == 0)) {
935 if ((inode = proc_get_inode(dir->i_sb,
936 de->low_ino, de)) == NULL) {
937 printk(KERN_ERR "COMX: lookup error\n");
939 return ERR_PTR(-EINVAL);
946 dentry->d_op = &comx_dentry_operations;
947 d_add(dentry, inode);
951 int comx_strcasecmp(const char *cs, const char *ct)
953 register signed char __res;
956 if ((__res = toupper(*cs) - toupper(*ct++)) != 0 || !*cs++) {
963 static int comx_delete_dentry(struct dentry *dentry)
968 static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
969 int size, struct proc_dir_entry *dir)
971 struct proc_dir_entry *new_file;
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;
983 int comx_register_hardware(struct comx_hardware *comx_hw)
985 struct comx_hardware *hw = comx_channels;
988 comx_channels = comx_hw;
990 while (hw->next != NULL && strcmp(comx_hw->name, hw->name) != 0) {
993 if (strcmp(comx_hw->name, hw->name) == 0) {
999 printk(KERN_INFO "COMX: driver for hardware type %s, version %s\n", comx_hw->name, comx_hw->version);
1003 int comx_unregister_hardware(char *name)
1005 struct comx_hardware *hw = comx_channels;
1011 if (strcmp(hw->name, name) == 0) {
1012 comx_channels = comx_channels->next;
1016 while (hw->next != NULL && strcmp(hw->next->name,name) != 0) {
1020 if (hw->next != NULL && strcmp(hw->next->name, name) == 0) {
1021 hw->next = hw->next->next;
1027 int comx_register_protocol(struct comx_protocol *comx_line)
1029 struct comx_protocol *pr = comx_lines;
1032 comx_lines = comx_line;
1034 while (pr->next != NULL && strcmp(comx_line->name, pr->name) !=0) {
1037 if (strcmp(comx_line->name, pr->name) == 0) {
1040 pr->next = comx_line;
1043 printk(KERN_INFO "COMX: driver for protocol type %s, version %s\n", comx_line->name, comx_line->version);
1047 int comx_unregister_protocol(char *name)
1049 struct comx_protocol *pr = comx_lines;
1055 if (strcmp(pr->name, name) == 0) {
1056 comx_lines = comx_lines->next;
1060 while (pr->next != NULL && strcmp(pr->next->name,name) != 0) {
1064 if (pr->next != NULL && strcmp(pr->next->name, name) == 0) {
1065 pr->next = pr->next->next;
1071 static int __init comx_init(void)
1073 struct proc_dir_entry *new_file;
1075 comx_root_dir = create_proc_entry("comx",
1076 S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root);
1079 comx_root_dir->proc_iops = &comx_root_inode_ops;
1081 if ((new_file = create_proc_entry(FILENAME_HARDWARELIST,
1082 S_IFREG | 0444, comx_root_dir)) == NULL) {
1086 new_file->data = new_file;
1087 new_file->read_proc = &comx_root_read_proc;
1088 new_file->write_proc = NULL;
1089 new_file->nlink = 1;
1091 if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST,
1092 S_IFREG | 0444, comx_root_dir)) == NULL) {
1096 new_file->data = new_file;
1097 new_file->read_proc = &comx_root_read_proc;
1098 new_file->write_proc = NULL;
1099 new_file->nlink = 1;
1102 printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>\n",
1107 static void __exit comx_exit(void)
1109 remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
1110 remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
1111 remove_proc_entry(comx_root_dir->name, &proc_root);
1114 module_init(comx_init);
1115 module_exit(comx_exit);
1117 EXPORT_SYMBOL(comx_register_hardware);
1118 EXPORT_SYMBOL(comx_unregister_hardware);
1119 EXPORT_SYMBOL(comx_register_protocol);
1120 EXPORT_SYMBOL(comx_unregister_protocol);
1121 EXPORT_SYMBOL(comx_debug_skb);
1122 EXPORT_SYMBOL(comx_debug_bytes);
1123 EXPORT_SYMBOL(comx_debug);
1124 EXPORT_SYMBOL(comx_lineup_func);
1125 EXPORT_SYMBOL(comx_status);
1126 EXPORT_SYMBOL(comx_rx);
1127 EXPORT_SYMBOL(comx_strcasecmp);
1128 EXPORT_SYMBOL(comx_root_dir);