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