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

📄 if_ul.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
字号:
/*  * Copyright (c) 1994 Shantanu Goel * All Rights Reserved. *  * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. *  * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION.  THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. *//* * Written 1993 by Donald Becker. *  * Copyright 1993 United States Government as represented by the * Director, National Security Agency.	 This software may be used and * distributed according to the terms of the GNU Public License, * incorporated herein by reference. * * The Author may be reached as becker@super.org or * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 */#include <wd.h>#include <ul.h>#if NUL > 0/* * Driver for SMC Ultra ethernet adaptor. * Derived from the Linux driver by Donald Becker. * * Shantanu Goel (goel@cs.columbia.edu) */#include <mach/sa/sys/types.h>#include "vm_param.h"#include <kern/time_out.h>#include <device/device_types.h>#include <device/errno.h>#include <device/io_req.h>#include <device/if_hdr.h>#include <device/if_ether.h>#include <device/net_status.h>#include <device/net_io.h>#include <chips/busses.h>#include <i386/machspl.h>#include <i386/pio.h>#include <i386at/gpl/if_nsreg.h>#define START_PG	0x00	/* first page of TX buffer */#define ULTRA_CMDREG	0	/* offset of ASIC command register */#define  ULTRA_RESET	0x80	/* board reset in ULTRA_CMDREG */#define  ULTRA_MEMEN	0x40	/* enable shared memory */#define ULTRA_NIC_OFF	16	/* NIC register offset */#define ulunit(dev)	minor(dev)/* * Autoconfiguration stuff. */int	ulprobe();void	ulattach();int	ulstd[] = { 0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0 };struct	bus_device *ulinfo[NUL];struct	bus_driver uldriver = {	ulprobe, 0, ulattach, 0, ulstd, "ul", ulinfo, 0, 0, 0};/* * NS8390 state. */struct	nssoftc ulnssoftc[NUL];/* * Ultra state. */struct ulsoftc {	int	sc_mstart;	/* start of board's RAM */	int	sc_mend;	/* end of board's RAM */	int	sc_rmstart;	/* start of receive RAM */	int	sc_rmend;	/* end of receive RAM */} ulsoftc[NUL];void	ulstart(int);void	ul_reset(struct nssoftc *sc);void	ul_input(struct nssoftc *sc, int, char *, int);int	ul_output(struct nssoftc *sc, int, char *, int);/* * Watchdog. */int	ulwstart = 0;void	ulwatch(void);#define ULDEBUG#ifdef ULDEBUGint	uldebug = 0;#define DEBUGF(stmt)	{ if (uldebug) stmt; }#else#define DEBUGF(stmt)#endif/* * Probe for the Ultra. * This looks like an 8013 with the station address PROM * at I/O ports <base>+8 to <base>+13, with a checksum following. */intulprobe(xxx, ui)	int xxx;	struct bus_device *ui;{	int *port;	if (ui->unit >= NUL) {		printf("ul%d: not configured\n", ui->unit);		return (0);	}	for (port = ulstd; *port; port++) {		if (*port < 0)			continue;		/*		 * Check chip ID nibble.		 */		if ((inb(*port + 7) & 0xf0) != 0x20)			continue;		if (ulprobe1(*port, ui)) {			ui->address = *port;			*port = -1;#if NWD > 0			/*			 * XXX: The Western Digital/SMC driver can sometimes			 * probe the Ultra incorrectly.  Remove the Ultra's			 * port from it's list to avoid the problem.			 */			{				int i;				extern int wdstd[];				for (i = 0; wdstd[i]; i++) {					if (wdstd[i] == ui->address) {						wdstd[i] = -1;						break;					}				}			}#endif			return (1);		}	}	return (0);}intulprobe1(port, ui)	int port;	struct bus_device *ui;{	u_char num_pages, irqreg, addr, reg4;	u_char irqmap[] = { 0, 9, 3, 5, 7, 10, 11, 15 };	short num_pages_tbl[4] = { 0x20, 0x40, 0x80, 0xff };	int i, irq, checksum = 0;	int addr_tbl[4] = { 0x0c0000, 0x0e0000, 0xfc0000, 0xfe0000 };	struct ulsoftc *ul = &ulsoftc[ui->unit];	struct nssoftc *ns = &ulnssoftc[ui->unit];	struct ifnet *ifp = &ns->sc_if;	/*	 * Select the station address register set.	 */	reg4 = inb(port + 4) & 0x7f;	outb(port + 4, reg4);	for (i = 0; i < 8; i++)		checksum += inb(port + 8 + i);	if ((checksum & 0xff) != 0xff)		return (0);	/*	 * Use 2 transmit buffers.	 */	ns->sc_pingpong = 1;	printf("ul%d: SMC Ultra at 0x%03x, ", ui->unit, port);	for (i = 0; i < ETHER_ADDR_LEN; i++) {		if (i == 0)			printf("%02x", ns->sc_addr[i] = inb(port + 8 + i));		else			printf(":%02x", ns->sc_addr[i] = inb(port + 8 + i));	}	/*	 * Switch from station address to alternate register set	 * and read useful registers there.	 */	outb(port + 4, 0x80 | reg4);	/*	 * Enable FINE16 mode to avoid BIOS ROM width mismatches	 * during reboot.	 */	outb(port + 0x0c, 0x80 | inb(port + 0x0c));	irqreg = inb(port + 0x0d);	addr = inb(port + 0x0b);	/*	 * Switch back to station address register set so the MSDOG	 * driver can find the card after a warm boot.	 */	outb(port + 4, reg4);	/*	 * Determine IRQ.  The IRQ bits are split.	 */	irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)];	if (irq == 0) {		printf(", failed to detect IRQ line.\n");		return (0);	}	ui->sysdep1 = irq;	take_dev_irq(ui);	printf(", irq %d", irq);	/*	 * Determine board's RAM location.	 */	ul->sc_mstart = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3];	num_pages = num_pages_tbl[(addr >> 4) & 3];	ul->sc_rmstart = ul->sc_mstart + TX_PAGES(ns) * 256;	ul->sc_mend = ul->sc_rmend		= ul->sc_mstart + (num_pages - START_PG) * 256;	printf(", memory 0x%05x-0x%05x\n", ul->sc_mstart, ul->sc_mend);	/*	 * Initialize 8390 state.	 */	ns->sc_name = ui->name;	ns->sc_unit = ui->unit;	ns->sc_port = port + ULTRA_NIC_OFF;	ns->sc_word16 = 1;	ns->sc_txstrtpg = START_PG;	ns->sc_rxstrtpg = START_PG + TX_PAGES(ns);	ns->sc_stoppg = num_pages;	ns->sc_reset = ul_reset;	ns->sc_input = ul_input;	ns->sc_output = ul_output;	DEBUGF(printf("ul%d: txstrtpg %d rxstrtpg %d num_pages %d\n",		      ui->unit, ns->sc_txstrtpg, ns->sc_rxstrtpg, num_pages));	/*	 * Initialize interface header.	 */	ifp->if_unit = ui->unit;	ifp->if_mtu = ETHERMTU;	ifp->if_flags = IFF_BROADCAST;	ifp->if_header_size = sizeof(struct ether_header);	ifp->if_header_format = HDR_ETHERNET;	ifp->if_address_size = ETHER_ADDR_LEN;	ifp->if_address = ns->sc_addr;	if_init_queues(ifp);	return (1);}voidulattach(ui)	struct bus_device *ui;{	/*	 * void	 */}intulopen(dev, flag)	dev_t dev;	int flag;{	int unit = ulunit(dev), s;	struct bus_device *ui;	if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)		return (ENXIO);	/*	 * Start watchdog.	 */	if (!ulwstart) {		ulwstart++;		timeout(ulwatch, 0, hz);	}	ulnssoftc[unit].sc_if.if_flags |= IFF_UP;	s = splimp();	outb(ui->address, ULTRA_MEMEN);	/* enable memory, 16 bit mode */	outb(ui->address + 5, 0x80);	outb(ui->address + 6, 0x01);	/* enable interrupts and memory */	nsinit(&ulnssoftc[unit]);	splx(s);	return (0);}intuloutput(dev, ior)	dev_t dev;	io_req_t ior;{	int unit = ulunit(dev);	struct bus_device *ui;	if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)		return (ENXIO);	return (net_write(&ulnssoftc[unit].sc_if, ulstart, ior));}intulsetinput(dev, receive_port, priority, filter, filter_count)	dev_t dev;	mach_port_t receive_port;	int priority;	filter_t *filter;	unsigned filter_count;{	int unit = ulunit(dev);	struct bus_device *ui;	if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)		return (ENXIO);	return (net_set_filter(&ulnssoftc[unit].sc_if, receive_port,			       priority, filter, filter_count));}intulgetstat(dev, flavor, status, count)	dev_t dev;	int flavor;	dev_status_t status;	unsigned *count;{	int unit = ulunit(dev);	struct bus_device *ui;	if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)		return (ENXIO);	return (net_getstat(&ulnssoftc[unit].sc_if, flavor, status, count));}intulsetstat(dev, flavor, status, count)	dev_t dev;	int flavor;	dev_status_t status;	unsigned count;{	int unit = ulunit(dev), oflags, s;	struct bus_device *ui;	struct ifnet *ifp;	struct net_status *ns;	if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)		return (ENXIO);	ifp = &ulnssoftc[unit].sc_if;	switch (flavor) {	case NET_STATUS:		if (count < NET_STATUS_COUNT)			return (D_INVALID_SIZE);		ns = (struct net_status *)status;		oflags = ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC);		ifp->if_flags &= ~(IFF_ALLMULTI|IFF_PROMISC);		ifp->if_flags |= ns->flags & (IFF_ALLMULTI|IFF_PROMISC);		if ((ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC)) != oflags) {			s = splimp();			nsinit(&ulnssoftc[unit]);			splx(s);		}		break;	default:		return (D_INVALID_OPERATION);	}	return (D_SUCCESS);}voidulintr(unit)	int unit;{	nsintr(&ulnssoftc[unit]);}voidulstart(unit)	int unit;{	nsstart(&ulnssoftc[unit]);}voidul_reset(ns)	struct nssoftc *ns;{	int port = ns->sc_port - ULTRA_NIC_OFF;	/* ASIC base address */	outb(port, ULTRA_RESET);	outb(0x80, 0);			/* I/O delay */	outb(port, ULTRA_MEMEN);}voidul_input(ns, count, buf, ring_offset)	struct nssoftc *ns;	int count;	char *buf;	int ring_offset;{	int xfer_start;	struct ulsoftc *ul = &ulsoftc[ns->sc_unit];	DEBUGF(printf("ul%d: ring_offset = %d\n", ns->sc_unit, ring_offset));	xfer_start = ul->sc_mstart + ring_offset - (START_PG << 8);	if (xfer_start + count > ul->sc_rmend) {		int semi_count = ul->sc_rmend - xfer_start;		/*		 * Input move must be wrapped.		 */		bcopy((char *)phystokv(xfer_start), buf, semi_count);		count -= semi_count;		bcopy((char *)phystokv(ul->sc_rmstart), buf+semi_count, count);	} else		bcopy((char *)phystokv(xfer_start), buf, count);}intul_output(ns, count, buf, start_page)	struct nssoftc *ns;	int count;	char *buf;	int start_page;{	char *shmem;	int i;	struct ulsoftc *ul = &ulsoftc[ns->sc_unit];	DEBUGF(printf("ul%d: start_page = %d\n", ns->sc_unit, start_page));	shmem = (char *)phystokv(ul->sc_mstart + ((start_page-START_PG) << 8));	bcopy(buf, shmem, count);	while (count <  ETHERMIN + sizeof(struct ether_header)) {		*(shmem + count) = 0;		count++;	}	return (count);}/* * Watchdog. * Check for hung transmissions. */voidulwatch(){	int unit, s;	struct nssoftc *ns;	timeout(ulwatch, 0, hz);	s = splimp();	for (unit = 0; unit < NUL; unit++) {		if (ulinfo[unit] == 0 || ulinfo[unit]->alive == 0)			continue;		ns = &ulnssoftc[unit];		if (ns->sc_timer && --ns->sc_timer == 0) {			printf("ul%d: transmission timeout\n", unit);			nsinit(ns);		}	}	splx(s);}#endif /* NUL > 0 */

⌨️ 快捷键说明

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