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
79 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
80 MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
81 MODULE_LICENSE("GPL");
82
83 extern int comx_hw_comx_init(void);
84 extern int comx_hw_locomx_init(void);
85 extern int comx_hw_mixcom_init(void);
86 extern int comx_proto_hdlc_init(void);
87 extern int comx_proto_ppp_init(void);
88 extern int comx_proto_syncppp_init(void);
89 extern int comx_proto_lapb_init(void);
90 extern int comx_proto_fr_init(void);
91
92 static struct comx_hardware *comx_channels = NULL;
93 static struct comx_protocol *comx_lines = NULL;
94
95 static int comx_mkdir(struct inode *, struct dentry *, int);
96 static int comx_rmdir(struct inode *, struct dentry *);
97 static struct dentry *comx_lookup(struct inode *, struct dentry *);
98
99 static struct inode_operations comx_root_inode_ops = {
100 lookup: comx_lookup,
101 mkdir: comx_mkdir,
102 rmdir: comx_rmdir,
103 };
104
105 static int comx_delete_dentry(struct dentry *dentry);
106 static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
107 int size, struct proc_dir_entry *dir);
108
109 static struct dentry_operations comx_dentry_operations = {
110 d_delete: comx_delete_dentry,
111 };
112
113
114 static struct proc_dir_entry * comx_root_dir;
115
116 struct 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
comx_debug(struct net_device * dev,char * fmt,...)129 int 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
comx_debug_skb(struct net_device * dev,struct sk_buff * skb,char * msg)172 int 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
comx_debug_bytes(struct net_device * dev,unsigned char * bytes,int len,char * msg)183 int 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
comx_loadavg_timerfun(unsigned long d)216 static 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
231 static 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
comx_open(struct net_device * dev)246 static 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
comx_close(struct net_device * dev)278 static 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
comx_status(struct net_device * dev,int status)313 void 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
comx_xmit(struct sk_buff * skb,struct net_device * dev)331 static 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
comx_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,void * daddr,void * saddr,unsigned len)351 static 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
comx_rebuild_header(struct sk_buff * skb)363 static 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
comx_rx(struct net_device * dev,struct sk_buff * skb)375 int 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
comx_stats(struct net_device * dev)389 static 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
comx_lineup_func(unsigned long d)396 void 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
comx_statistics(struct net_device * dev,char * page)415 static 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
comx_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)482 static 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
comx_reset_dev(struct net_device * dev)492 static 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
comx_init_dev(struct net_device * dev)506 static 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
comx_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)542 static 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
comx_root_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)575 static 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
comx_write_proc(struct file * file,const char * buffer,u_long count,void * data)606 static 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 }
779 out:
780 free_page((unsigned long)page);
781 return count;
782 }
783
comx_mkdir(struct inode * dir,struct dentry * dentry,int mode)784 static 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;
856 cleanup_if_ptr:
857 kfree(ch->if_ptr);
858 cleanup_register:
859 unregister_netdevice(dev);
860 cleanup_filename_debug:
861 remove_proc_entry(FILENAME_DEBUG, new_dir);
862 cleanup_filename_lineupdelay:
863 remove_proc_entry(FILENAME_LINEUPDELAY, new_dir);
864 cleanup_filename_status:
865 remove_proc_entry(FILENAME_STATUS, new_dir);
866 cleanup_filename_protocol:
867 remove_proc_entry(FILENAME_PROTOCOL, new_dir);
868 cleanup_filename_hardware:
869 remove_proc_entry(FILENAME_HARDWARE, new_dir);
870 cleanup_new_dir:
871 remove_proc_entry(dentry->d_name.name, comx_root_dir);
872 cleanup_dev:
873 kfree(dev);
874 return ret;
875 }
876
comx_rmdir(struct inode * dir,struct dentry * dentry)877 static 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
comx_lookup(struct inode * dir,struct dentry * dentry)926 static 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
comx_strcasecmp(const char * cs,const char * ct)951 int 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
comx_delete_dentry(struct dentry * dentry)963 static int comx_delete_dentry(struct dentry *dentry)
964 {
965 return 1;
966 }
967
create_comx_proc_entry(char * name,int mode,int size,struct proc_dir_entry * dir)968 static 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
comx_register_hardware(struct comx_hardware * comx_hw)983 int 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
comx_unregister_hardware(char * name)1003 int 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
comx_register_protocol(struct comx_protocol * comx_line)1027 int 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
comx_unregister_protocol(char * name)1047 int 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
comx_init(void)1075 int __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
cleanup_module(void)1137 void 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
1145 EXPORT_SYMBOL(comx_register_hardware);
1146 EXPORT_SYMBOL(comx_unregister_hardware);
1147 EXPORT_SYMBOL(comx_register_protocol);
1148 EXPORT_SYMBOL(comx_unregister_protocol);
1149 EXPORT_SYMBOL(comx_debug_skb);
1150 EXPORT_SYMBOL(comx_debug_bytes);
1151 EXPORT_SYMBOL(comx_debug);
1152 EXPORT_SYMBOL(comx_lineup_func);
1153 EXPORT_SYMBOL(comx_status);
1154 EXPORT_SYMBOL(comx_rx);
1155 EXPORT_SYMBOL(comx_strcasecmp);
1156 EXPORT_SYMBOL(comx_root_dir);
1157