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

📄 strip.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Note: Must make sure sx_size is big enough to receive a stuffed * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's * big enough to receive a large radio neighbour list (currently 4K). */static int allocate_buffers(struct strip *strip_info, int mtu){	struct net_device *dev = strip_info->dev;	int sx_size = max_t(int, STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096);	int tx_size = STRIP_ENCAP_SIZE(mtu) + MaxCommandStringLength;	__u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC);	__u8 *s = kmalloc(sx_size, GFP_ATOMIC);	__u8 *t = kmalloc(tx_size, GFP_ATOMIC);	if (r && s && t) {		strip_info->rx_buff = r;		strip_info->sx_buff = s;		strip_info->tx_buff = t;		strip_info->sx_size = sx_size;		strip_info->tx_size = tx_size;		strip_info->mtu = dev->mtu = mtu;		return (1);	}	kfree(r);	kfree(s);	kfree(t);	return (0);}/* * MTU has been changed by the IP layer.  * We could be in * an upcall from the tty driver, or in an ip packet queue. */static int strip_change_mtu(struct net_device *dev, int new_mtu){	struct strip *strip_info = netdev_priv(dev);	int old_mtu = strip_info->mtu;	unsigned char *orbuff = strip_info->rx_buff;	unsigned char *osbuff = strip_info->sx_buff;	unsigned char *otbuff = strip_info->tx_buff;	if (new_mtu > MAX_SEND_MTU) {		printk(KERN_ERR		       "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n",		       strip_info->dev->name, MAX_SEND_MTU);		return -EINVAL;	}	spin_lock_bh(&strip_lock);	if (!allocate_buffers(strip_info, new_mtu)) {		printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n",		       strip_info->dev->name);		spin_unlock_bh(&strip_lock);		return -ENOMEM;	}	if (strip_info->sx_count) {		if (strip_info->sx_count <= strip_info->sx_size)			memcpy(strip_info->sx_buff, osbuff,			       strip_info->sx_count);		else {			strip_info->discard = strip_info->sx_count;			strip_info->rx_over_errors++;		}	}	if (strip_info->tx_left) {		if (strip_info->tx_left <= strip_info->tx_size)			memcpy(strip_info->tx_buff, strip_info->tx_head,			       strip_info->tx_left);		else {			strip_info->tx_left = 0;			strip_info->tx_dropped++;		}	}	strip_info->tx_head = strip_info->tx_buff;	spin_unlock_bh(&strip_lock);	printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n",	       strip_info->dev->name, old_mtu, strip_info->mtu);	kfree(orbuff);	kfree(osbuff);	kfree(otbuff);	return 0;}static void strip_unlock(struct strip *strip_info){	/*	 * Set the timer to go off in one second.	 */	strip_info->idle_timer.expires = jiffies + 1 * HZ;	add_timer(&strip_info->idle_timer);	netif_wake_queue(strip_info->dev);}/* * If the time is in the near future, time_delta prints the number of * seconds to go into the buffer and returns the address of the buffer. * If the time is not in the near future, it returns the address of the * string "Not scheduled" The buffer must be long enough to contain the * ascii representation of the number plus 9 charactes for the " seconds" * and the null character. */#ifdef CONFIG_PROC_FSstatic char *time_delta(char buffer[], long time){	time -= jiffies;	if (time > LongTime / 2)		return ("Not scheduled");	if (time < 0)		time = 0;	/* Don't print negative times */	sprintf(buffer, "%ld seconds", time / HZ);	return (buffer);}/* get Nth element of the linked list */static struct strip *strip_get_idx(loff_t pos) {	struct list_head *l;	int i = 0;	list_for_each_rcu(l, &strip_list) {		if (pos == i)			return list_entry(l, struct strip, list);		++i;	}	return NULL;}static void *strip_seq_start(struct seq_file *seq, loff_t *pos){	rcu_read_lock();	return *pos ? strip_get_idx(*pos - 1) : SEQ_START_TOKEN;}static void *strip_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct list_head *l;	struct strip *s;	++*pos;	if (v == SEQ_START_TOKEN)		return strip_get_idx(1);	s = v;	l = &s->list;	list_for_each_continue_rcu(l, &strip_list) {		return list_entry(l, struct strip, list);	}	return NULL;}static void strip_seq_stop(struct seq_file *seq, void *v){	rcu_read_unlock();}static void strip_seq_neighbours(struct seq_file *seq,			   const MetricomNodeTable * table,			   const char *title){	/* We wrap this in a do/while loop, so if the table changes */	/* while we're reading it, we just go around and try again. */	struct timeval t;	do {		int i;		t = table->timestamp;		if (table->num_nodes)			seq_printf(seq, "\n %s\n", title);		for (i = 0; i < table->num_nodes; i++) {			MetricomNode node;			spin_lock_bh(&strip_lock);			node = table->node[i];			spin_unlock_bh(&strip_lock);			seq_printf(seq, "  %s\n", node.c);		}	} while (table->timestamp.tv_sec != t.tv_sec		 || table->timestamp.tv_usec != t.tv_usec);}/* * This function prints radio status information via the seq_file * interface.  The interface takes care of buffer size and over * run issues.  * * The buffer in seq_file is PAGESIZE (4K)  * so this routine should never print more or it will get truncated. * With the maximum of 32 portables and 32 poletops * reported, the routine outputs 3107 bytes into the buffer. */static void strip_seq_status_info(struct seq_file *seq, 				  const struct strip *strip_info){	char temp[32];	MetricomAddressString addr_string;	/* First, we must copy all of our data to a safe place, */	/* in case a serial interrupt comes in and changes it.  */	int tx_left = strip_info->tx_left;	unsigned long rx_average_pps = strip_info->rx_average_pps;	unsigned long tx_average_pps = strip_info->tx_average_pps;	unsigned long sx_average_pps = strip_info->sx_average_pps;	int working = strip_info->working;	int firmware_level = strip_info->firmware_level;	long watchdog_doprobe = strip_info->watchdog_doprobe;	long watchdog_doreset = strip_info->watchdog_doreset;	long gratuitous_arp = strip_info->gratuitous_arp;	long arp_interval = strip_info->arp_interval;	FirmwareVersion firmware_version = strip_info->firmware_version;	SerialNumber serial_number = strip_info->serial_number;	BatteryVoltage battery_voltage = strip_info->battery_voltage;	char *if_name = strip_info->dev->name;	MetricomAddress true_dev_addr = strip_info->true_dev_addr;	MetricomAddress dev_dev_addr =	    *(MetricomAddress *) strip_info->dev->dev_addr;	int manual_dev_addr = strip_info->manual_dev_addr;#ifdef EXT_COUNTERS	unsigned long rx_bytes = strip_info->rx_bytes;	unsigned long tx_bytes = strip_info->tx_bytes;	unsigned long rx_rbytes = strip_info->rx_rbytes;	unsigned long tx_rbytes = strip_info->tx_rbytes;	unsigned long rx_sbytes = strip_info->rx_sbytes;	unsigned long tx_sbytes = strip_info->tx_sbytes;	unsigned long rx_ebytes = strip_info->rx_ebytes;	unsigned long tx_ebytes = strip_info->tx_ebytes;#endif	seq_printf(seq, "\nInterface name\t\t%s\n", if_name);	seq_printf(seq, " Radio working:\t\t%s\n", working ? "Yes" : "No");	radio_address_to_string(&true_dev_addr, &addr_string);	seq_printf(seq, " Radio address:\t\t%s\n", addr_string.c);	if (manual_dev_addr) {		radio_address_to_string(&dev_dev_addr, &addr_string);		seq_printf(seq, " Device address:\t%s\n", addr_string.c);	}	seq_printf(seq, " Firmware version:\t%s", !working ? "Unknown" :		     !firmware_level ? "Should be upgraded" :		     firmware_version.c);	if (firmware_level >= ChecksummedMessages)		seq_printf(seq, " (Checksums Enabled)");	seq_printf(seq, "\n");	seq_printf(seq, " Serial number:\t\t%s\n", serial_number.c);	seq_printf(seq, " Battery voltage:\t%s\n", battery_voltage.c);	seq_printf(seq, " Transmit queue (bytes):%d\n", tx_left);	seq_printf(seq, " Receive packet rate:   %ld packets per second\n",		     rx_average_pps / 8);	seq_printf(seq, " Transmit packet rate:  %ld packets per second\n",		     tx_average_pps / 8);	seq_printf(seq, " Sent packet rate:      %ld packets per second\n",		     sx_average_pps / 8);	seq_printf(seq, " Next watchdog probe:\t%s\n",		     time_delta(temp, watchdog_doprobe));	seq_printf(seq, " Next watchdog reset:\t%s\n",		     time_delta(temp, watchdog_doreset));	seq_printf(seq, " Next gratuitous ARP:\t");	if (!memcmp	    (strip_info->dev->dev_addr, zero_address.c,	     sizeof(zero_address)))		seq_printf(seq, "Disabled\n");	else {		seq_printf(seq, "%s\n", time_delta(temp, gratuitous_arp));		seq_printf(seq, " Next ARP interval:\t%ld seconds\n",			     JIFFIE_TO_SEC(arp_interval));	}	if (working) {#ifdef EXT_COUNTERS		seq_printf(seq, "\n");		seq_printf(seq,			     " Total bytes:         \trx:\t%lu\ttx:\t%lu\n",			     rx_bytes, tx_bytes);		seq_printf(seq,			     "  thru radio:         \trx:\t%lu\ttx:\t%lu\n",			     rx_rbytes, tx_rbytes);		seq_printf(seq,			     "  thru serial port:   \trx:\t%lu\ttx:\t%lu\n",			     rx_sbytes, tx_sbytes);		seq_printf(seq,			     " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n",			     rx_ebytes, tx_ebytes);#endif		strip_seq_neighbours(seq, &strip_info->poletops,					"Poletops:");		strip_seq_neighbours(seq, &strip_info->portables,					"Portables:");	}}/* * This function is exports status information from the STRIP driver through * the /proc file system. */static int strip_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN)		seq_printf(seq, "strip_version: %s\n", StripVersion);	else		strip_seq_status_info(seq, (const struct strip *)v);	return 0;}static struct seq_operations strip_seq_ops = {	.start = strip_seq_start,	.next  = strip_seq_next,	.stop  = strip_seq_stop,	.show  = strip_seq_show,};static int strip_seq_open(struct inode *inode, struct file *file){	return seq_open(file, &strip_seq_ops);}static struct file_operations strip_seq_fops = {	.owner	 = THIS_MODULE,	.open    = strip_seq_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release,};#endif/************************************************************************//* Sending routines							*/static void ResetRadio(struct strip *strip_info){	struct tty_struct *tty = strip_info->tty;	static const char init[] = "ate0q1dt**starmode\r**";	StringDescriptor s = { init, sizeof(init) - 1 };	/* 	 * If the radio isn't working anymore,	 * we should clear the old status information.	 */	if (strip_info->working) {		printk(KERN_INFO "%s: No response: Resetting radio.\n",		       strip_info->dev->name);		strip_info->firmware_version.c[0] = '\0';		strip_info->serial_number.c[0] = '\0';		strip_info->battery_voltage.c[0] = '\0';		strip_info->portables.num_nodes = 0;		do_gettimeofday(&strip_info->portables.timestamp);		strip_info->poletops.num_nodes = 0;		do_gettimeofday(&strip_info->poletops.timestamp);	}	strip_info->pps_timer = jiffies;	strip_info->rx_pps_count = 0;	strip_info->tx_pps_count = 0;	strip_info->sx_pps_count = 0;	strip_info->rx_average_pps = 0;	strip_info->tx_average_pps = 0;	strip_info->sx_average_pps = 0;	/* Mark radio address as unknown */	*(MetricomAddress *) & strip_info->true_dev_addr = zero_address;	if (!strip_info->manual_dev_addr)		*(MetricomAddress *) strip_info->dev->dev_addr =		    zero_address;	strip_info->working = FALSE;	strip_info->firmware_level = NoStructure;	strip_info->next_command = CompatibilityCommand;	strip_info->watchdog_doprobe = jiffies + 10 * HZ;	strip_info->watchdog_doreset = jiffies + 1 * HZ;	/* If the user has selected a baud rate above 38.4 see what magic we have to do */	if (strip_info->user_baud > B38400) {		/*		 * Subtle stuff: Pay attention :-)		 * If the serial port is currently at the user's selected (>38.4) rate,		 * then we temporarily switch to 19.2 and issue the ATS304 command		 * to tell the radio to switch to the user's selected rate.		 * If the serial port is not currently at that rate, that means we just		 * issued the ATS304 command last time through, so this time we restore		 * the user's selected rate and issue the normal starmode reset string.		 */		if (strip_info->user_baud == get_baud(tty)) {			static const char b0[] = "ate0q1s304=57600\r";			static const char b1[] = "ate0q1s304=115200\r";			static const StringDescriptor baudstring[2] =			    { {b0, sizeof(b0) - 1}			, {b1, sizeof(b1) - 1}			};			set_baud(tty, B19200);			if (strip_info->user_baud == B57600)				s = baudstring[0];			else if (strip_info->user_baud == B115200)				s = baudstring[1];			else				s = baudstring[1];	/* For now */		} else			set_baud(tty, strip_info->user_baud);	}	tty->driver->write(tty, s.string, s.length);#ifdef EXT_COUNTERS	strip_info->tx_ebytes += s.length;#endif}/* * Called by the driver when there's room for more data.  If we have * more packets to send, we send them here. */static void strip_write_some_more(struct tty_struct *tty){	struct strip *strip_info = (struct strip *) tty->disc_data;

⌨️ 快捷键说明

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