⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comx.c

📁 自己根据lkd和情境分析
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Device driver framework for the COMX line of synchronous serial boards *  * for Linux kernel 2.2.X * * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>, *                    Peter Bajan <bajan.peter@synergon.hu>, * Previous maintainer: Tivadar Szemethy <tiv@itc.hu> * Current maintainer: Gergely Madarasz <gorgo@itc.hu> * * Copyright (C) 1995-1999 ITConsult-Pro Co. * * Contributors: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.85) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Version 0.80 (99/06/11): *		- clean up source code (playing a bit of indent) *		- port back to kernel, add support for non-module versions *		- add support for board resets when channel protocol is down *		- reset the device structure after protocol exit *		  the syncppp driver needs it *		- add support for /proc/comx/protocols and  *		  /proc/comx/boardtypes * * Version 0.81 (99/06/21): *		- comment out the board reset support code, the locomx *		  driver seems not buggy now *		- printk() levels fixed * * Version 0.82 (99/07/08): *		- Handle stats correctly if the lowlevel driver is *		  is not a comx one (locomx - z85230) * * Version 0.83 (99/07/15): *		- reset line_status when interface is down * * Version 0.84 (99/12/01): *		- comx_status should not check for IFF_UP (to report *		  line status from dev->open()) * * Version 0.85 (00/08/15): * 		- resource release on failure in comx_mkdir * 		- fix return value on failure at comx_write_proc * * Changed      (00/10/29, Henner Eisen): * 		- comx_rx() / comxlapb_data_indication() return status. */#define VERSION "0.85"#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <asm/uaccess.h>#include <linux/ctype.h>#include <linux/init.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#ifndef CONFIG_PROC_FS#error For now, COMX really needs the /proc filesystem#endif#include <net/syncppp.h>#include "comx.h"MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");MODULE_LICENSE("GPL");extern int comx_hw_comx_init(void);extern int comx_hw_locomx_init(void);extern int comx_hw_mixcom_init(void);extern int comx_proto_hdlc_init(void);extern int comx_proto_ppp_init(void);extern int comx_proto_syncppp_init(void);extern int comx_proto_lapb_init(void);extern int comx_proto_fr_init(void);static struct comx_hardware *comx_channels = NULL;static struct comx_protocol *comx_lines = NULL;static int comx_mkdir(struct inode *, struct dentry *, int);static int comx_rmdir(struct inode *, struct dentry *);static struct dentry *comx_lookup(struct inode *, struct dentry *);static struct inode_operations comx_root_inode_ops = {	lookup:	comx_lookup,	mkdir: comx_mkdir,	rmdir: comx_rmdir,};static int comx_delete_dentry(struct dentry *dentry);static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,	int size, struct proc_dir_entry *dir);static struct dentry_operations comx_dentry_operations = {	d_delete:	comx_delete_dentry,};static struct proc_dir_entry * comx_root_dir;struct comx_debugflags_struct	comx_debugflags[] = {	{ "comx_rx",		DEBUG_COMX_RX		},	{ "comx_tx", 		DEBUG_COMX_TX		},	{ "hw_tx",		DEBUG_HW_TX		},	{ "hw_rx", 		DEBUG_HW_RX		},	{ "hdlc_keepalive",	DEBUG_HDLC_KEEPALIVE	},	{ "comxppp",		DEBUG_COMX_PPP		},	{ "comxlapb",		DEBUG_COMX_LAPB		},	{ "dlci",		DEBUG_COMX_DLCI		},	{ NULL,			0			} };int comx_debug(struct net_device *dev, char *fmt, ...){	struct comx_channel *ch = dev->priv;	char *page,*str;	va_list args;	int len;	if (!ch->debug_area) return 0;	if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM;	va_start(args, fmt);	len = vsprintf(str = page, fmt, args);	va_end(args);	if (len >= PAGE_SIZE) {		printk(KERN_ERR "comx_debug: PANIC! len = %d !!!\n", len);		free_page((unsigned long)page);		return -EINVAL;	}	while (len) {		int to_copy;		int free = (ch->debug_start - ch->debug_end + ch->debug_size) 			% ch->debug_size;		to_copy = min_t(int, free ? free : ch->debug_size, 			      min_t(int, ch->debug_size - ch->debug_end, len));		memcpy(ch->debug_area + ch->debug_end, str, to_copy);		str += to_copy;		len -= to_copy;		ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size;		if (ch->debug_start == ch->debug_end) // Full ? push start away			ch->debug_start = (ch->debug_start + len + 1) % 					ch->debug_size;		ch->debug_file->size = (ch->debug_end - ch->debug_start +					ch->debug_size) % ch->debug_size;	} 	free_page((unsigned long)page);	return 0;}int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg){	struct comx_channel *ch = dev->priv;	if (!ch->debug_area) return 0;	if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg);	if (!skb->len) comx_debug(dev, "%s: %s empty skb\n\n", dev->name, msg);	return comx_debug_bytes(dev, skb->data, skb->len, msg);}int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len, 		char *msg){	int pos = 0;	struct comx_channel *ch = dev->priv;	if (!ch->debug_area) return 0;	comx_debug(dev, "%s: %s len %d\n", dev->name, msg, len);	while (pos != len) {		char line[80];		int i = 0;		memset(line, 0, 80);		sprintf(line,"%04d ", pos);		do {			sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]);			sprintf(line + 60 + (pos % 16), "%c", 				isprint(bytes[pos]) ? bytes[pos] : '.');			pos++;		} while (pos != len && pos % 16);		while ( i++ != 78 ) if (line[i] == 0) line[i] = ' ';		line[77] = '\n';		line[78] = 0;			comx_debug(dev, "%s", line);	}	comx_debug(dev, "\n");	return 0;}static void comx_loadavg_timerfun(unsigned long d){	struct net_device *dev = (struct net_device *)d;	struct comx_channel *ch = dev->priv;	ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;	ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = 		ch->current_stats->tx_bytes;	ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size;	mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]);}#if 0static void comx_reset_timerfun(unsigned long d){ 	struct net_device *dev = (struct net_device *)d;	struct comx_channel *ch = dev->priv;	if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {		if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {			ch->HW_reset(dev);		}	}	mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout);}#endif                                            static int comx_open(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct proc_dir_entry *comxdir = ch->procdir->subdir;	int ret=0;	if (!ch->protocol || !ch->hardware) return -ENODEV;	if ((ret = ch->HW_open(dev))) return ret;	if ((ret = ch->LINE_open(dev))) { 		ch->HW_close(dev); 		return ret; 	};	for (; comxdir ; comxdir = comxdir->next) {		if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||		   strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)			comxdir->mode = S_IFREG | 0444;	}#if 0	ch->reset_pending = 1;	ch->reset_timeout = 30;	ch->reset_timer.function = comx_reset_timerfun;	ch->reset_timer.data = (unsigned long)dev;	ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout;	add_timer(&ch->reset_timer);#endif	return 0;}static int comx_close(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct proc_dir_entry *comxdir = ch->procdir->subdir;	int ret = -ENODEV;	if (test_and_clear_bit(0, &ch->lineup_pending)) {		del_timer(&ch->lineup_timer);	}#if 0		del_timer(&ch->reset_timer);#endif	if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) {		ret = ch->LINE_close(dev);	}	if (ret) return ret;	if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) {		ret = ch->HW_close(dev);	}		ch->line_status=0;	for (; comxdir ; comxdir = comxdir->next) {		if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||		    strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)			comxdir->mode = S_IFREG | 0644;	}	return ret;}void comx_status(struct net_device *dev, int status){	struct comx_channel *ch = dev->priv;#if 0	if(status & (PROTO_UP | PROTO_LOOP)) {		clear_bit(0,&ch->reset_pending);	}#endif	printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %s\n",		    dev->name, status & LINE_UP ? "UP" : "DOWN", 		    status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ? 		    "UP" : "DOWN");		ch->line_status = status;}static int comx_xmit(struct sk_buff *skb, struct net_device *dev){	struct comx_channel *ch = dev->priv;	int rc;	if (skb->len > dev->mtu + dev->hard_header_len) {		printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %d\n", dev->name,		(int)skb->len, dev->mtu);	}		if (ch->debug_flags & DEBUG_COMX_TX) {		comx_debug_skb(dev, skb, "comx_xmit skb");	}		rc=ch->LINE_xmit(skb, dev);//	if (!rc) dev_kfree_skb(skb);	return rc;}static int comx_header(struct sk_buff *skb, struct net_device *dev, 	unsigned short type, void *daddr, void *saddr, unsigned len) {	struct comx_channel *ch = dev->priv;	if (ch->LINE_header) {		return (ch->LINE_header(skb, dev, type, daddr, saddr, len));	} else {		return 0;	}}static int comx_rebuild_header(struct sk_buff *skb) {	struct net_device *dev = skb->dev;	struct comx_channel *ch = dev->priv;	if (ch->LINE_rebuild_header) {		return(ch->LINE_rebuild_header(skb));	} else {		return 0;	}}int comx_rx(struct net_device *dev, struct sk_buff *skb){	struct comx_channel *ch = dev->priv;	if (ch->debug_flags & DEBUG_COMX_RX) {		comx_debug_skb(dev, skb, "comx_rx skb");	}	if (skb) {		netif_rx(skb);		dev->last_rx = jiffies;	}	return 0;}static struct net_device_stats *comx_stats(struct net_device *dev){	struct comx_channel *ch = (struct comx_channel *)dev->priv;	return ch->current_stats;}void comx_lineup_func(unsigned long d){	struct net_device *dev = (struct net_device *)d;	struct comx_channel *ch = dev->priv;	del_timer(&ch->lineup_timer);	clear_bit(0, &ch->lineup_pending);	if (ch->LINE_status) {		ch->LINE_status(dev, ch->line_status |= LINE_UP);	}}#define LOADAVG(avg, off) (int) \	((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) \	% ch->loadavg_size + off] -  ch->avg_bytes[(ch->loadavg_counter - 1 \		- ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) \		% ch->loadavg_size + off]) / ch->loadavg[avg] * 8)static int comx_statistics(struct net_device *dev, char *page){	struct comx_channel *ch = dev->priv;	int len = 0;	int tmp;	int i = 0;	char tmpstr[20];	int tmpstrlen = 0;	len += sprintf(page + len, "Interface administrative status is %s, "		"modem status is %s, protocol is %s\n", 		dev->flags & IFF_UP ? "UP" : "DOWN",		ch->line_status & LINE_UP ? "UP" : "DOWN",		ch->line_status & PROTO_LOOP ? "LOOP" : 		ch->line_status & PROTO_UP ? "UP" : "DOWN");	len += sprintf(page + len, "Modem status changes: %lu, Transmitter status "		"is %s, tbusy: %d\n", ch->current_stats->tx_carrier_errors, ch->HW_txe ? 		ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", netif_running(dev));	len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (",		LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0));	tmpstr[0] = 0;	for (i=0; i != 3; i++) {		char tf;		tf = ch->loadavg[i] % 60 == 0 && 			ch->loadavg[i] / 60 > 0 ? 'm' : 's';		tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s", 			ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf, 			i == 2 ? ")\n" : "/");	}	len += sprintf(page + len, 		"%s              (output): %d / %d / %d bits/s (%s", tmpstr, 		LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size), 		LOADAVG(2, ch->loadavg_size), tmpstr);	len += sprintf(page + len, "Debug flags: ");	tmp = len; i = 0;	while (comx_debugflags[i].name) {		if (ch->debug_flags & comx_debugflags[i].value) 			len += sprintf(page + len, "%s ", 				comx_debugflags[i].name);		i++;	}	len += sprintf(page + len, "%s\n", tmp == len ? "none" : "");	len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, "		"aborts: %lu\n           buffer overrun: %lu, pbuffer overrun: %lu\n"		"TX errors: underrun: %lu\n",		ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors, 		ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors, 		ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors,		ch->current_stats->tx_fifo_errors);	if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) {		len += ch->LINE_statistics(dev, page + len);	} else {		len += sprintf(page+len, "Line status: driver not initialized\n");	}	if (ch->HW_statistics && (ch->init_status & HW_OPEN)) {		len += ch->HW_statistics(dev, page + len);	} else {		len += sprintf(page+len, "Board status: driver not initialized\n");	}	return len;}static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	struct comx_channel *ch = dev->priv;	if (ch->LINE_ioctl) {		return(ch->LINE_ioctl(dev, ifr, cmd));	}	return -EINVAL;}static void comx_reset_dev(struct net_device *dev){	dev->open = comx_open;	dev->stop = comx_close;	dev->hard_start_xmit = comx_xmit;	dev->hard_header = comx_header;	dev->rebuild_header = comx_rebuild_header;	dev->get_stats = comx_stats;	dev->do_ioctl = comx_ioctl;	dev->change_mtu = NULL;	dev->tx_queue_len = 20;	dev->flags = IFF_NOARP;}static int comx_init_dev(struct net_device *dev){	struct comx_channel *ch;	if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) {		return -ENOMEM;	}	memset(ch, 0, sizeof(struct comx_channel));	ch->loadavg[0] = 5;	ch->loadavg[1] = 300;	ch->loadavg[2] = 900;	ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1; 	if ((ch->avg_bytes = kmalloc(ch->loadavg_size * 		sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) {		kfree(ch);		return -ENOMEM;	}	memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2);	ch->loadavg_counter = 0;	ch->loadavg_timer.function = comx_loadavg_timerfun;	ch->loadavg_timer.data = (unsigned long)dev;	ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0];	add_timer(&ch->loadavg_timer);	dev->priv = (void *)ch;	ch->dev = dev;	ch->line_status &= ~LINE_UP;	ch->current_stats = &ch->stats;	comx_reset_dev(dev);	return 0;}static int comx_read_proc(char *page, char **start, off_t off, int count, 	int *eof, void *data){	struct proc_dir_entry *file = (struct proc_dir_entry *)data;	struct net_device *dev = file->parent->data;	struct comx_channel *ch=(struct comx_channel *)dev->priv;	int len = 0;	if (strcmp(file->name, FILENAME_STATUS) == 0) {		len = comx_statistics(dev, page);	} else if (strcmp(file->name, FILENAME_HARDWARE) == 0) {		len = sprintf(page, "%s\n", ch->hardware ? 			ch->hardware->name : HWNAME_NONE);	} else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) {		len = sprintf(page, "%s\n", ch->protocol ? 			ch->protocol->name : PROTONAME_NONE);	} else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) {		len = sprintf(page, "%01d\n", ch->lineup_delay);	}	if (off >= len) {		*eof = 1;		return 0;	}	*start = page + off;	if (count >= len - off) {		*eof = 1;	}	return min_t(int, count, len - off);}static int comx_root_read_proc(char *page, char **start, off_t off, int count, 	int *eof, void *data){	struct proc_dir_entry *file = (struct proc_dir_entry *)data;	struct comx_hardware *hw;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -