亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關(guān)于我們
? 蟲蟲下載站

?? atp.c

?? 內(nèi)核是系統(tǒng)的心臟
?? C
?? 第 1 頁 / 共 2 頁
字號:
/* atp.c: Attached (pocket) ethernet adaptor driver for linux. */
/*
	Written 1993 by Donald Becker.
	Copyright 1993 United States Government as represented by the Director,
	National Security Agency.  This software may only be used and distributed
	according to the terms of the GNU Public License as modified by SRC,
	incorported herein by reference.

	The author may be reached as becker@super.org or
	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715

*/

static char *version =
	"atp.c:v0.04 2/25/94 Donald Becker (becker@super.org)\n";

/*
	This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket
	ethernet adaptor.  This is a common low-cost OEM pocket ethernet
	adaptor, sold under many names.

  Sources:
	This driver was written from the packet driver assembly code provided by
	Vincent Bono of AT-Lan-Tec.	 Ever try to figure out how a complicated
	device works just from the assembly code?  It ain't pretty.  The following
	description is written based on guesses and writing lots of special-purpose
	code to test my theorized operation.

					Theory of Operation
	
	The RTL8002 adaptor seems to be built around a custom spin of the SEEQ
	controller core.  It probably has a 16K or 64K internal packet buffer, of
	which the first 4K is devoted to transmit and the rest to receive.
	The controller maintains the queue of received packet and the packet buffer
	access pointer internally, with only 'reset to beginning' and 'skip to next
	packet' commands visible.  The transmit packet queue holds two (or more?)
	packets: both 'retransmit this packet' (due to collision) and 'transmit next
	packet' commands must be started by hand.

	The station address is stored in a standard bit-serial EEPROM which must be
	read (ughh) by the device driver.  (Provisions have been made for
	substituting a 74S288 PROM, but I haven't gotten reports of any models
	using it.)  Unlike built-in devices, a pocket adaptor can temporarily lose
	power without indication to the device driver.  The major effect is that
	the station address, receive filter (promiscuous, etc.) and transceiver
	must be reset.

	The controller itself has 16 registers, some of which use only the lower
	bits.  The registers are read and written 4 bits at a time.  The four bit
	register address is presented on the data lines along with a few additional
	timing and control bits.  The data is then read from status port or written
	to the data port.

	Since the bulk data transfer of the actual packets through the slow
	parallel port dominates the driver's running time, four distinct data
	(non-register) transfer modes are provided by the adaptor, two in each
	direction.  In the first mode timing for the nibble transfers is
	provided through the data port.  In the second mode the same timing is
	provided through the control port.  In either case the data is read from
	the status port and written to the data port, just as it is accessing
	registers.

	In addition to the basic data transfer methods, several more are modes are
	created by adding some delay by doing multiple reads of the data to allow
	it to stabilize.  This delay seems to be needed on most machines.

	The data transfer mode is stored in the 'dev->if_port' field.  Its default
	value is '4'.  It may be overriden at boot-time using the third parameter
	to the "ether=..." initialization.

	The header file <atp.h> provides inline functions that encapsulate the
	register and data access methods.  These functions are hand-tuned to
	generate reasonable object code.  This header file also documents my
	interpretations of the device registers.
*/

#include <linux/config.h>		/* Used only to override default values. */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <errno.h>

#include "dev.h"
#include "eth.h"
#include "skbuff.h"
#include "arp.h"

#include "atp.h"

/* Compatibility definitions for earlier kernel versions. */
#ifndef HAVE_AUTOIRQ
/* From auto_irq.c, in ioport.h for later versions. */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
/* The map from IRQ number (as passed to the interrupt handler) to
   'struct device'. */
extern struct device *irq2dev_map[16];
#endif

#ifndef HAVE_ALLOC_SKB
#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
#define kfree_skbmem(addr, size) kfree_s(addr,size);
#endif

#ifndef HAVE_PORTRESERVE
#define check_region(ioaddr, size)		0
#define snarf_region(ioaddr, size);		do ; while (0)
#endif

/* use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
#define NET_DEBUG 4
#endif
static unsigned int net_debug = NET_DEBUG;

/* The number of low I/O ports used by the ethercard. */
#define ETHERCARD_TOTAL_SIZE	3

/* Index to functions, as function prototypes. */

extern int atp_probe(struct device *dev);

static int atp_probe1(struct device *dev, short ioaddr);
static void init_dev(struct device *dev);
static void get_node_ID(struct device *dev);
static unsigned short eeprom_op(short ioaddr, unsigned int cmd);
static int net_open(struct device *dev);
static void hardware_init(struct device *dev);
static void write_packet(short ioaddr, int length, unsigned char *packet, int mode);
static void trigger_send(short ioaddr, int length);
static int	net_send_packet(struct sk_buff *skb, struct device *dev);
static void net_interrupt(int reg_ptr);
static void net_rx(struct device *dev);
static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
static int net_close(struct device *dev);
static struct enet_statistics *net_get_stats(struct device *dev);
#ifdef HAVE_MULTICAST
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
#endif


/* Check for a network adaptor of this type, and return '0' iff one exists.
   If dev->base_addr == 0, probe all likely locations.
   If dev->base_addr == 1, always return failure.
   If dev->base_addr == 2, alloate space for the device and return success
   (detachable devices only).
   */
int
atp_init(struct device *dev)
{
	int *port, ports[] = {0x378, 0x278, 0x3bc, 0};
	int base_addr = dev->base_addr;

	if (base_addr > 0x1ff)		/* Check a single specified location. */
		return atp_probe1(dev, base_addr);
	else if (base_addr == 1)	/* Don't probe at all. */
		return ENXIO;

	for (port = ports; *port; port++) {
		int ioaddr = *port;
		outb(0x57, ioaddr + PAR_DATA);
		if (inb(ioaddr + PAR_DATA) != 0x57)
			continue;
		if (atp_probe1(dev, ioaddr) == 0)
			return 0;
	}

	return ENODEV;
}

static int atp_probe1(struct device *dev, short ioaddr)
{
	int saved_ctrl_reg, status;

	outb(0xff, ioaddr + PAR_DATA);
	/* Save the original value of the Control register, in case we guessed
	   wrong. */
	saved_ctrl_reg = inb(ioaddr + PAR_CONTROL);
	/* IRQEN=0, SLCTB=high INITB=high, AUTOFDB=high, STBB=high. */
	outb(0x04, ioaddr + PAR_CONTROL);
	write_reg_high(ioaddr, CMR1, CMR1h_RESET);
	eeprom_delay(2048);
	status = read_nibble(ioaddr, CMR1);

	if ((status & 0x78) != 0x08) {
		/* The pocket adaptor probe failed, restore the control register. */
		outb(saved_ctrl_reg, ioaddr + PAR_CONTROL);
		return 1;
	}
	status = read_nibble(ioaddr, CMR2_h);
	if ((status & 0x78) != 0x10) {
		outb(saved_ctrl_reg, ioaddr + PAR_CONTROL);
		return 1;
	}
	/* Find the IRQ used by triggering an interrupt. */
	write_reg_byte(ioaddr, CMR2, 0x01);			/* No accept mode, IRQ out. */
	write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);	/* Enable Tx and Rx. */

	/* Omit autoIRQ routine for now. Use "table lookup" instead.  Uhgggh. */
	if (ioaddr == 0x378)
		dev->irq = 7;
	else
		dev->irq = 5;
	write_reg_high(ioaddr, CMR1, CMR1h_TxRxOFF); /* Diable Tx and Rx units. */
	write_reg(ioaddr, CMR2, CMR2_NULL);

	dev->base_addr = ioaddr;

	/* Read the station address PROM.  */
	get_node_ID(dev);

	printk("%s: Pocket adaptor found at %#3x, IRQ %d, SAPROM "
		   "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
		   dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
		   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);

	/* Leave the hardware in a reset state. */
    write_reg_high(ioaddr, CMR1, CMR1h_RESET);

	if (net_debug)
		printk(version);

	/* Initialize the device structure. */
	init_dev(dev);
	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
	memset(dev->priv, 0, sizeof(struct net_local));


	{
		struct net_local *lp = (struct net_local *)dev->priv;
		lp->addr_mode = CMR2h_Normal;
	}

	/* For the ATP adaptor the "if_port" is really the data transfer mode. */
	dev->if_port = (dev->mem_start & 0xf) ? dev->mem_start & 0x7 : 4;
	if (dev->mem_end & 0xf)
		net_debug = dev->mem_end & 7;

	dev->open		= net_open;
	dev->stop		= net_close;
	dev->hard_start_xmit = net_send_packet;
	dev->get_stats	= net_get_stats;
#ifdef HAVE_MULTICAST
	dev->set_multicast_list = &set_multicast_list;
#endif

	return 0;
}

/* Fill in the fields of the device structure with ethernet-generic values.
   This should be in a common file instead of per-driver.  */
static void init_dev(struct device *dev)
{
	int i;

	for (i = 0; i < DEV_NUMBUFFS; i++)
		dev->buffs[i] = NULL;

	dev->hard_header	= eth_header;
	dev->add_arp		= eth_add_arp;
	dev->queue_xmit		= dev_queue_xmit;
	dev->rebuild_header = eth_rebuild_header;
	dev->type_trans		= eth_type_trans;

	dev->type			= ARPHRD_ETHER;
	dev->hard_header_len = ETH_HLEN;
	dev->mtu			= 1500; /* eth_mtu */
	dev->addr_len		= ETH_ALEN;
	for (i = 0; i < ETH_ALEN; i++) {
		dev->broadcast[i]=0xff;
	}

	/* New-style flags. */
	dev->flags			= IFF_BROADCAST;
	dev->family			= AF_INET;
	dev->pa_addr		= 0;
	dev->pa_brdaddr		= 0;
	dev->pa_mask		= 0;
	dev->pa_alen		= sizeof(unsigned long);
}

/* Read the station address PROM, usually a word-wide EEPROM. */
static void get_node_ID(struct device *dev)
{
	short ioaddr = dev->base_addr;
	int sa_offset = 0;
	int i;
	
	write_reg(ioaddr, CMR2, CMR2_EEPROM);	  /* Point to the EEPROM control registers. */
	
	/* Some adaptors have the station address at offset 15 instead of offset
	   zero.  Check for it, and fix it if needed. */
	if (eeprom_op(ioaddr, EE_READ(0)) == 0xffff)
		sa_offset = 15;
	
	for (i = 0; i < 3; i++)
		((unsigned short *)dev->dev_addr)[i] =
			ntohs(eeprom_op(ioaddr, EE_READ(sa_offset + i)));
	
	write_reg(ioaddr, CMR2, CMR2_NULL);
}

/*
  An EEPROM read command starts by shifting out 0x60+address, and then
  shifting in the serial data. See the NatSemi databook for details.
 *		   ________________
 * CS : __|
 *			   ___	   ___
 * CLK: ______|	  |___|	  |
 *		 __ _______ _______
 * DI :	 __X_______X_______X
 * DO :	 _________X_______X
 */

static unsigned short eeprom_op(short ioaddr, unsigned int cmd)
{
	unsigned eedata_out = 0;
	int num_bits = EE_CMD_SIZE;
	
	while (--num_bits >= 0) {
		char outval = test_bit(num_bits, &cmd) ? EE_DATA_WRITE : 0;
		write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_LOW);
		eeprom_delay(5);
		write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_HIGH);
		eedata_out <<= 1;
		if (read_nibble(ioaddr, PROM_DATA) & EE_DATA_READ)
			eedata_out++;
		eeprom_delay(5);
	}
	write_reg_high(ioaddr, PROM_CMD, EE_CLK_LOW & ~EE_CS);
	return eedata_out;
}


/* Open/initialize the board.  This is called (in the current kernel)
   sometime after booting when the 'ifconfig' program is run.

   This routine sets everything up anew at each open, even
   registers that "should" only need to be set once at boot, so that
   there is non-reboot way to recover if something goes wrong.

   This is an attachable device: if there is no dev->priv entry then it wasn't
   probed for at boot-time, and we need to probe for it again.
   */
static int net_open(struct device *dev)
{

	/* The interrupt line is turned off (tri-stated) when the device isn't in
	   use.  That's especially important for "attached" interfaces where the
	   port or interrupt may be shared. */
	if (irq2dev_map[dev->irq] != 0
		|| (irq2dev_map[dev->irq] = dev) == 0
		|| request_irq(dev->irq, &net_interrupt)) {
		return -EAGAIN;
	}

	hardware_init(dev);
	dev->start = 1;
	return 0;
}

/* This routine resets the hardware.  We initialize everything, assuming that
   the hardware may have been temporarily detacted. */
static void hardware_init(struct device *dev)
{
	struct net_local *lp = (struct net_local *)dev->priv;
	int ioaddr = dev->base_addr;
    int i;

	write_reg_high(ioaddr, CMR1, CMR1h_RESET);
	
    for (i = 0; i < 6; i++)
		write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);

	write_reg_high(ioaddr, CMR2, lp->addr_mode);

	if (net_debug > 2) {
		printk("%s: Reset: current Rx mode %d.\n", dev->name,
			   (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f);
	}

    write_reg(ioaddr, CMR2, CMR2_IRQOUT);
    write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);

	/* Enable the interrupt line from the serial port. */
	outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);

	/* Unmask the interesting interrupts. */

?? 快捷鍵說明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美性色黄大片| 在线免费观看日韩欧美| 亚洲精品中文在线| 欧美成人一区二区三区片免费| 高清beeg欧美| 日韩av不卡在线观看| 中文字幕在线一区| 久久亚洲精品国产精品紫薇| 欧美性做爰猛烈叫床潮| 国产成人综合亚洲网站| 日本不卡一二三| 亚洲一区二区欧美| 中文字幕高清一区| 久久久久亚洲综合| 欧美一区二区在线不卡| 欧美网站大全在线观看| 91丨九色丨蝌蚪富婆spa| 国产乱对白刺激视频不卡| 日韩电影在线观看电影| 亚洲情趣在线观看| 国产精品福利一区二区三区| 日韩欧美高清一区| 欧美日本一道本| 欧美综合天天夜夜久久| 一本大道久久a久久精二百| 国产成人精品免费网站| 久久99国产精品成人| 日韩中文字幕1| 亚洲午夜国产一区99re久久| 亚洲欧美日韩一区二区| 国产精品女同一区二区三区| 久久嫩草精品久久久久| 欧美成人精精品一区二区频| 91精品国产麻豆国产自产在线| 在线视频国内自拍亚洲视频| 91美女视频网站| av午夜精品一区二区三区| www.亚洲国产| hitomi一区二区三区精品| 成人高清视频在线观看| 不卡的av电影| 91老师片黄在线观看| 91美女视频网站| 在线观看91精品国产入口| 91麻豆国产精品久久| 日本韩国一区二区| 欧美视频中文一区二区三区在线观看| 色播五月激情综合网| 色综合激情久久| 欧美视频日韩视频在线观看| 欧美视频一区在线| 91麻豆精品国产91久久久资源速度| 欧美中文一区二区三区| 精品视频在线看| 欧美一区二区免费视频| 精品欧美黑人一区二区三区| 欧美不卡一区二区| 中文字幕国产一区| 亚洲老司机在线| 亚洲成人一区二区在线观看| 男女激情视频一区| 国产精品中文字幕日韩精品 | 国产成人综合亚洲网站| 丁香天五香天堂综合| 91天堂素人约啪| 911精品国产一区二区在线| 日韩精品一区二区三区在线播放 | 国产99久久久国产精品潘金网站| 成人午夜在线免费| 在线观看91精品国产入口| 日韩欧美国产午夜精品| 欧美国产1区2区| 午夜婷婷国产麻豆精品| 韩国理伦片一区二区三区在线播放 | 国产一区二区在线观看免费 | 久久99精品国产麻豆婷婷| 国产成人自拍网| 日本丶国产丶欧美色综合| 日韩欧美国产综合一区| 中文文精品字幕一区二区| 亚洲一区在线看| 久久国产免费看| 色婷婷久久久亚洲一区二区三区| 在线观看欧美日本| 久久一二三国产| 亚洲影视在线播放| 国产精品系列在线观看| 欧美日韩一区二区三区在线| 欧美mv日韩mv| 亚洲影视在线播放| 成人三级伦理片| 欧美一区二区播放| 亚洲欧美乱综合| 国产高清久久久久| 6080国产精品一区二区| 国产精品免费网站在线观看| 日本成人在线看| 一本一道久久a久久精品综合蜜臀| 日韩一区二区麻豆国产| 亚洲欧洲精品一区二区三区不卡 | 色综合一个色综合| 国产亚洲污的网站| 男人的天堂亚洲一区| 在线亚洲免费视频| 日本一区二区三区高清不卡| 肉丝袜脚交视频一区二区| 91浏览器在线视频| 欧美韩日一区二区三区| 久久成人精品无人区| 欧洲另类一二三四区| 国产日韩欧美精品在线| 六月丁香综合在线视频| 欧美丝袜丝交足nylons| 亚洲色图在线播放| 国产精品1区2区3区在线观看| 4438成人网| 午夜a成v人精品| 91国产福利在线| 亚洲欧美国产高清| 波多野结衣的一区二区三区| 久久精品视频在线免费观看| 蜜桃av一区二区| 欧美一卡二卡在线观看| 亚洲高清免费观看| 欧美在线视频你懂得| 亚洲欧洲制服丝袜| 91在线你懂得| 1024亚洲合集| 99v久久综合狠狠综合久久| 国产精品视频一二三区| 国产1区2区3区精品美女| 久久久久综合网| 国产.欧美.日韩| 国产精品免费观看视频| 成人国产一区二区三区精品| 国产欧美va欧美不卡在线| 国产不卡视频在线播放| 国产视频911| 国产成人精品三级| 亚洲欧美怡红院| 在线观看亚洲一区| 午夜精品在线看| 欧美一二三区精品| 久久99国产精品成人| 久久精品在这里| av网站免费线看精品| 亚洲精品视频在线看| 91黄色在线观看| 天天色 色综合| 日韩一区二区在线看片| 精一区二区三区| 国产欧美一区在线| 色综合久久中文字幕| 一区二区三区电影在线播| 色国产综合视频| 日韩电影在线观看一区| 亚洲精品一区二区三区精华液 | 91麻豆免费看片| 天天av天天翘天天综合网色鬼国产| 欧美狂野另类xxxxoooo| 久久精品国内一区二区三区| 久久久精品国产免费观看同学| 成人国产亚洲欧美成人综合网| 亚洲精品日韩综合观看成人91| 精品视频在线免费| 国产一区二区在线影院| 日韩毛片精品高清免费| 欧美电视剧免费观看| 成人网页在线观看| 亚洲国产一区二区视频| 精品日韩一区二区三区免费视频| 国产a精品视频| 亚洲成人一区二区| 久久久国产精华| 欧美又粗又大又爽| 精品在线一区二区| 亚洲欧洲色图综合| 日韩欧美在线网站| 91美女福利视频| 激情六月婷婷久久| 亚洲美女免费在线| 精品成人一区二区三区| 91浏览器入口在线观看| 九九热在线视频观看这里只有精品| 国产精品私人影院| 91精品国产高清一区二区三区| 不卡视频在线看| 蜜臀久久99精品久久久久宅男 | 在线亚洲免费视频| 国产精品亚洲第一区在线暖暖韩国| 一区二区三区在线免费| 精品三级av在线| 欧美日韩一区二区不卡| 国产成人在线电影| 视频一区免费在线观看| 国产精品盗摄一区二区三区| 欧美老肥妇做.爰bbww视频| 成人av小说网| 狠狠久久亚洲欧美| 亚洲成人激情综合网|