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

📄 pcic.c

📁 WaveLAN无线网卡Linux驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Intel PCIC or compatible Controller driver *  May be built using LKM to make a loadable module. *------------------------------------------------------------------------- * * Copyright (c) 1995 Andrew McRae.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//* * pcic98 : PC9801 original PCMCIA controller code for NS/A,Ne,NX/C,NR/L. * by Noriyuki Hosobuchi <yj8n-hsbc@asahi-net.or.jp> */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/select.h>#include <machine/clock.h>#include <i386/isa/icu.h>#include <i386/isa/isa_device.h>#include <pccard/i82365.h>#ifdef	PC98#include <pccard/pcic98reg.h>#endif#include <pccard/cardinfo.h>#include <pccard/driver.h>#include <pccard/slot.h>/* *	Prototypes for interrupt handler. */static void		pcicintr	__P((int unit));static int		pcic_ioctl __P((struct slot *, int, caddr_t));static int		pcic_power __P((struct slot *));static timeout_t 	pcic_reset;static void		pcic_resume(struct slot *);static void		pcic_disable __P((struct slot *));static void		pcic_mapirq __P((struct slot *, int));static timeout_t 	pcictimeout;#ifdef LKMstatic int		pcic_handle __P((struct lkm_table *lkmtp, int cmd));#endifstatic int		pcic_memory(struct slot *, int);static int		pcic_io(struct slot *, int);static u_int		build_freelist(u_int);/* *	Per-slot data table. */static struct pcic_slot {	int slotnum;			/* My slot number */	int index;			/* Index register */	int data;			/* Data register */	int offset;			/* Offset value for index */	char controller;		/* Device type */	char revision;			/* Device Revision */	struct slot *slt;		/* Back ptr to slot */	u_char (*getb)(struct pcic_slot *, int);	void   (*putb)(struct pcic_slot *, int, u_char);	u_char	*regs;			/* Pointer to regs in mem */} pcic_slots[PCIC_MAX_SLOTS];static int		pcic_irq;static unsigned		pcic_imask;static struct slot_ctrl cinfo;/* *	Internal inline functions for accessing the PCIC. *//* * Read a register from the PCIC. */static __inline unsigned chargetb1(struct pcic_slot *sp, int reg){	outb(sp->index, sp->offset + reg);	return inb(sp->data);}static __inline unsigned chargetb2(struct pcic_slot *sp, int reg){	return (sp->regs[reg]);}/* * Write a register on the PCIC */static __inline voidputb1(struct pcic_slot *sp, int reg, unsigned char val){	outb(sp->index, sp->offset + reg);	outb(sp->data, val);}static __inline voidputb2(struct pcic_slot *sp, int reg, unsigned char val){	sp->regs[reg] = val;}/* * Clear bit(s) of a register. */static __inline voidclrb(struct pcic_slot *sp, int reg, unsigned char mask){	sp->putb(sp, reg, sp->getb(sp, reg) & ~mask);}/* * Set bit(s) of a register */static __inline voidsetb(struct pcic_slot *sp, int reg, unsigned char mask){	sp->putb(sp, reg, sp->getb(sp, reg) | mask);}/* * Write a 16 bit value to 2 adjacent PCIC registers */static __inline voidputw(struct pcic_slot *sp, int reg, unsigned short word){	sp->putb(sp, reg, word & 0xFF);	sp->putb(sp, reg + 1, (word >> 8) & 0xff);}/* *	Loadable kernel module interface. */#ifdef	LKM/* *	This defines the lkm_misc module use by modload *	to define the module name. */MOD_MISC(pcic);/* *	Module handler that processes loads and unloads. *	Once the module is loaded, the probe routine *	is called to install the slots (if any). */static intpcic_handle(struct lkm_table *lkmtp, int cmd){	int err = 0;	/* default = success*/	switch(cmd) {	case LKM_E_LOAD:		/*		 * Don't load twice! (lkmexists() is exported by kern_lkm.c)		 */		if (lkmexists(lkmtp))			return(EEXIST);		/*		 *	Call the probe routine to find the slots. If		 *	no slots exist, then don't bother loading the module.		 */		if (pcic_probe() == 0)			return(ENODEV);		break;		/* Success*/	/*	 *	Attempt to unload the slot driver.	 */	case LKM_E_UNLOAD:		printf("Unloading PCIC driver\n");		err = pcic_unload(lkmtp, cmd);		break;		/* Success*/	default:	/* we only understand load/unload*/		err = EINVAL;		break;	}	return(err);}/* * External entry point; should generally match name of .o file.  The * arguments are always the same for all loaded modules.  The "load", * "unload", and "stat" functions in "DISPATCH" will be called under * their respective circumstances unless their value is "lkm_nullcmd". * If called, they are called with the same arguments (cmd is included to * allow the use of a single function, ver is included for version * matching between modules and the kernel loader for the modules). * * Since we expect to link in the kernel and add external symbols to * the kernel symbol name space in a future version, generally all * functions used in the implementation of a particular module should * be static unless they are expected to be seen in other modules or * to resolve unresolved symbols alread existing in the kernel (the * second case is not likely to ever occur). * * The entry point should return 0 unless it is refusing load (in which * case it should return an errno from errno.h). */intpcic_mod(struct lkm_table *lkmtp, int cmd, int ver){	MOD_DISPATCH(pcic, lkmtp, cmd, ver,		pcic_handle, pcic_handle, lkm_nullcmd);}/* *	pcic_unload - Called when unloading a LKM. *	Disables interrupts and resets PCIC. */static intpcic_unload(struct lkm_table *lkmtp, int cmd){	int	slot;	struct pcic_slot *sp = pcic_slots;	untimeout(pcictimeout, 0);	if (pcic_irq) {		for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, sp++) {			if (sp->slt)				sp->putb(sp, PCIC_STAT_INT, 0);		}		unregister_intr(pcic_irq, pcicintr);	}	pccard_remove_controller(&cinfo);	return(0);}#endif /* LKM */#if 0static voidpcic_dump_attributes(unsigned char *scratch, int maxlen){	int i,j,k;	i = 0;	while (scratch[i] != 0xff && i < maxlen) {		unsigned char link = scratch[i+2];		/*		 *	Dump attribute memory		 */		if (scratch[i]) {			printf("[%02x] ", i);			for (j = 0; j < 2 * link + 4 && j < 128; j += 2)				printf("%02x ", scratch[j + i]);			printf("\n");		}		i += 4 + 2 * link;	}}#endifstatic voidnullfunc(int unit){	/* empty */}static u_intbuild_freelist(u_int pcic_mask){ 	int irq;	u_int mask, freemask;  	/* No free IRQs (yet). */ 	freemask = 0;  	/* Walk through all of the IRQ's and find any that aren't allocated. */ 	for (irq = 1; irq < ICU_LEN; irq++) { 		/* 		 * If the PCIC controller can't generate it, don't		 * bother checking to see if it it's free. 		 */ 		mask = 1 << irq; 		if (!(mask & pcic_mask)) continue;  		/* See if the IRQ is free. */		if (register_intr(irq, 0, 0, nullfunc, NULL, irq) == 0) {			/* Give it back, but add it to the mask */ 			INTRMASK(freemask, mask); 			unregister_intr(irq, nullfunc); 		}	} #ifdef PCIC_DEBUG	printf("Freelist of IRQ's <0x%x>\n", freemask);#endif	return freemask; }/* *	entry point from main code to map/unmap memory context. */static intpcic_memory(struct slot *slt, int win){	struct pcic_slot *sp = slt->cdata;	struct mem_desc *mp = &slt->mem[win];	int reg = mp->window * PCIC_MEMSIZE + PCIC_MEMBASE;#ifdef	PC98	if (sp->controller == PCIC_PC98) {	    if (mp->flags & MDF_ACTIVE) {		/* slot = 0, window = 0, sys_addr = 0xda000, length = 8KB */		unsigned char x;				if ((unsigned long)mp->start != 0xda000) {		    printf("sys_addr must be 0xda000. requested address = 0x%x\n",			   mp->start);		    return(EINVAL);		}				/* omajinai ??? */		outb(PCIC98_REG0, 0);		x = inb(PCIC98_REG1);		x &= 0xfc;		x |= 0x02;		outb(PCIC98_REG1, x);				outw(PCIC98_REG_PAGOFS, 0);				if (mp->flags & MDF_ATTR) {		    outb(PCIC98_REG6, inb(PCIC98_REG6) | PCIC98_ATTRMEM);		}else{		    outb(PCIC98_REG6, inb(PCIC98_REG6) & (~PCIC98_ATTRMEM));		}				outb(PCIC98_REG_WINSEL, PCIC98_MAPWIN);		#if 0		if (mp->flags & MDF_16BITS == 1) {	/* 16bit */		    outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_8BIT));		}else{					/* 8bit */		    outb(PCIC98_REG2, inb(PCIC98_REG2) | PCIC98_8BIT);		}#endif	    }else{		outb(PCIC98_REG_WINSEL, PCIC98_UNMAPWIN);	    }	    return 0;	}#endif	/* PC98 */	if (mp->flags & MDF_ACTIVE) {		unsigned long sys_addr = (unsigned long)mp->start >> 12;		/*		 * Write the addresses, card offsets and length.		 * The values are all stored as the upper 12 bits of the		 * 24 bit address i.e everything is allocated as 4 Kb chunks.		 */		putw(sp, reg, sys_addr & 0xFFF);		putw(sp, reg+2, (sys_addr + (mp->size >> 12) - 1) & 0xFFF);		putw(sp, reg+4, ((mp->card >> 12) - sys_addr) & 0x3FFF);#if 0		printf("card offs = card_adr = 0x%x 0x%x, sys_addr = 0x%x\n", 			mp->card, ((mp->card >> 12) - sys_addr) & 0x3FFF,			sys_addr);#endif		/*		 *	Each 16 bit register has some flags in the upper bits.		 */		if (mp->flags & MDF_16BITS)			setb(sp, reg+1, PCIC_DATA16);		if (mp->flags & MDF_ZEROWS)			setb(sp, reg+1, PCIC_ZEROWS);		if (mp->flags & MDF_WS0)			setb(sp, reg+3, PCIC_MW0);		if (mp->flags & MDF_WS1)			setb(sp, reg+3, PCIC_MW1);		if (mp->flags & MDF_ATTR)			setb(sp, reg+5, PCIC_REG);		if (mp->flags & MDF_WP)			setb(sp, reg+5, PCIC_WP);#if 0	printf("Slot number %d, reg 0x%x, offs 0x%x\n",		sp->slotnum, reg, sp->offset);	printf("Map window to sys addr 0x%x for %d bytes, card 0x%x\n",		mp->start, mp->size, mp->card);	printf("regs are: 0x%02x%02x 0x%02x%02x 0x%02x%02x flags 0x%x\n",		sp->getb(sp, reg), sp->getb(sp, reg+1),		sp->getb(sp, reg+2), sp->getb(sp, reg+3),		sp->getb(sp, reg+4), sp->getb(sp, reg+5),		mp->flags);#endif		/*		 * Enable the memory window. By experiment, we need a delay.		 */		setb(sp, PCIC_ADDRWINE, (1<<win) | PCIC_MEMCS16);		DELAY(50);	} else {#if 0		printf("Unmapping window %d\n", win);#endif		clrb(sp, PCIC_ADDRWINE, 1<<win);		putw(sp, reg, 0);		putw(sp, reg+2, 0);		putw(sp, reg+4, 0);	}	return(0);}/* *	pcic_io - map or unmap I/O context */static intpcic_io(struct slot *slt, int win){	int	mask, reg;	struct pcic_slot *sp = slt->cdata;	struct io_desc *ip = &slt->io[win];#ifdef	PC98	if (sp->controller == PCIC_PC98) {	    unsigned char x;#if 0	    if (win =! 0) {		printf("pcic98:Illegal PCIC I/O window request(%d)!", win);		return(EINVAL);	    }#endif	    if (ip->flags & IODF_ACTIVE) {		unsigned short base;		x = inb(PCIC98_REG2) & 0x0f;		if (! (ip->flags & IODF_16BIT))		    x |= PCIC98_8BIT;		if (ip->size > 16)	/* 128bytes mapping */		    x |= PCIC98_MAP128;		x |= PCIC98_IOMEMORY;		outb(PCIC98_REG2, x);    		base = 0x80d0;		outw(PCIC98_REG4, base);		/* 98side IO base */		outw(PCIC98_REG5, ip->start);	/* card side IO base */#ifdef	PCIC_DEBUG		printf("pcic98: IO mapped 0x%04x(98) -> 0x%04x(Card) and width %d bytes\n",		       base, ip->start, ip->size);#endif		ip->start = base;	    }else{		outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_IOMEMORY));	    }	    return 0;	}#endif	switch (win) {	case 0:		mask = PCIC_IO0_EN;		reg = PCIC_IO0;		break;	case 1:		mask = PCIC_IO1_EN;		reg = PCIC_IO1;		break;	default:		panic("Illegal PCIC I/O window request!");	}	if (ip->flags & IODF_ACTIVE) {		unsigned char x, ioctlv;#ifdef PCIC_DEBUGprintf("Map I/O 0x%x (size 0x%x) on Window %d\n", ip->start, ip->size, win);#endif	/* PCIC_DEBUG */		putw(sp, reg, ip->start);		putw(sp, reg+2, ip->start+ip->size-1);		x = 0;		if (ip->flags & IODF_ZEROWS)			x |= PCIC_IO_0WS;		if (ip->flags & IODF_WS)			x |= PCIC_IO_WS;		if (ip->flags & IODF_CS16)			x |= PCIC_IO_CS16;		if (ip->flags & IODF_16BIT)			x |= PCIC_IO_16BIT;		/*		 * Extract the current flags and merge with new flags.		 * Flags for window 0 in lower nybble, and in upper nybble		 * for window 1.		 */		ioctlv = sp->getb(sp, PCIC_IOCTL);		DELAY(100);		switch (win) {		case 0:			sp->putb(sp, PCIC_IOCTL, x | (ioctlv & 0xf0));			break;		case 1:			sp->putb(sp, PCIC_IOCTL, (x << 4) | (ioctlv & 0xf));			break;		}		DELAY(100);		setb(sp, PCIC_ADDRWINE, mask);		DELAY(100);	} else {		clrb(sp, PCIC_ADDRWINE, mask);		DELAY(100);		putw(sp, reg, 0);		putw(sp, reg + 2, 0);	}	return(0);}/* *	Look for an Intel PCIC (or compatible). *	For each available slot, allocate a PC-CARD slot. *//* *	VLSI 82C146 has incompatibilities about the I/O address  *	of slot 1.  Assume it's the only PCIC whose vendor ID is 0x84, *	contact Nate Williams <nate@FreeBSD.org> if incorrect. */intpcic_probe(void){	int slotnum, i, validslots = 0;	u_int free_irqs;	struct slot *slt;	struct pcic_slot *sp;	unsigned char c;	static int maybe_vlsi = 0;	/* Determine the list of free interrupts */	free_irqs = build_freelist(PCIC_INT_MASK_ALLOWED);		/*	 *	Initialise controller information structure.

⌨️ 快捷键说明

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