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

📄 pccard.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	pccard.c - Interface code for PC-CARD controllers. * *	June 1995, Andrew McRae (andrew@mega.com.au) *------------------------------------------------------------------------- * * 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. * *	$Id: pccard.c,v 1.68.2.3 1999/04/27 18:39:23 jdp Exp $ */#include "opt_devfs.h"#include "opt_pcic.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/proc.h>#include <sys/malloc.h>#include <sys/sysctl.h>#include <sys/conf.h>#ifdef DEVFS#include <sys/devfsext.h>#endif /*DEVFS*/#include <sys/uio.h>#include <sys/poll.h>#include <sys/interrupt.h>#include <i386/isa/isa_device.h>#include <i386/isa/icu.h>#include <i386/isa/intr_machdep.h>#include "apm.h"#if	NAPM > 0#include <machine/apm_bios.h>#endif	/* NAPM > 0 */#include <pccard/cardinfo.h>#include <pccard/driver.h>#include <pccard/slot.h>#include <machine/md_var.h>/* * XXX We shouldn't be using processor-specific/bus-specific code in * here, but we need the start of the ISA hole (IOM_BEGIN). */#ifdef PC98#include <pc98/pc98/pc98.h>#else#include <i386/isa/isa.h>#endifSYSCTL_NODE(_machdep, OID_AUTO, pccard, CTLFLAG_RW, 0, "pccard");static int pcic_resume_reset =#ifdef PCIC_RESUME_RESET	/* opt_pcic.h */	1;#else	0;#endifSYSCTL_INT(_machdep_pccard, OID_AUTO, pcic_resume_reset, CTLFLAG_RW, 	&pcic_resume_reset, 0, "");#define	PCCARD_MEMSIZE	(4*1024)#define MIN(a,b)	((a)<(b)?(a):(b))static int		allocate_driver(struct slot *, struct dev_desc *);static void		inserted(void *);static void		unregister_device_interrupt(struct pccard_devinfo *);static void		disable_slot(struct slot *);static int		invalid_io_memory(unsigned long, int);static struct pccard_device *find_driver(char *);static void		remove_device(struct pccard_devinfo *);static inthand2_t	slot_irq_handler;static void		power_off_slot(void *);static void		pccard_configure(void *);SYSINIT(pccard, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + 1, pccard_configure, NULL);#if	NAPM > 0/* *    For the APM stuff, the apmhook structure is kept *    separate from the slot structure so that the slot *    drivers do not need to know about the hooks (or the *    data structures). */static int	slot_suspend(void *arg);static int	slot_resume(void *arg);static struct	apmhook s_hook[MAXSLOT];	/* APM suspend */static struct	apmhook r_hook[MAXSLOT];	/* APM resume */#endif	/* NAPM > 0 */static struct slot	*pccard_slots[MAXSLOT];	/* slot entries */static struct slot	*slot_list;static struct slot_ctrl *cont_list;static struct pccard_device *drivers;		/* Card drivers *//* *	The driver interface for read/write uses a block *	of memory in the ISA I/O memory space allocated via *	an ioctl setting. */static unsigned long pccard_mem;	/* Physical memory */static unsigned char *pccard_kmem;	/* Kernel virtual address */static	d_open_t	crdopen;static	d_close_t	crdclose;static	d_read_t	crdread;static	d_write_t	crdwrite;static	d_ioctl_t	crdioctl;static	d_poll_t	crdpoll;#define CDEV_MAJOR 50static struct cdevsw crd_cdevsw = 	{ crdopen,	crdclose,	crdread,	crdwrite,	/*50*/	  crdioctl,	nostop,		nullreset,	nodevtotty,/* pcmcia */	  crdpoll,	nommap,		NULL,	"crd",	NULL,	-1 };/* *	pccard_configure - called by autoconf code. *	Probes for various PC-CARD controllers, and *	initialises data structures to point to the *	various slots. * *	Each controller indicates the number of slots *	that it sees, and these are mapped to a master *	slot number accessed via the character device entries. * *	XXX this is a relic.  Each controller has it's own probe *	configuration hook.  Printing a list of configured devices *	with pccard support probably isn't all that useful. */static voidpccard_configure(dummy)	void *dummy;{	struct pccard_device *drv;	/* This isn't strictly correct, but works because of initialize order */	printf("Initializing PC-card drivers:");	for (drv = drivers;  drv != NULL;  drv = drv->next)		printf(" %s", drv->name);	printf("\n");}intpccard_module_handler(module_t mod, int what, void *arg){	struct pccard_device *drv = (struct pccard_device *)arg;	switch(what) {	case MOD_LOAD:		pccard_add_driver(drv);		break;	case MOD_UNLOAD:		pccard_remove_driver(drv);		break;	default:		break;	}	return 0;}/* *	pccard_add_driver - Add a new driver to the list of *	drivers available for allocation. */voidpccard_add_driver(struct pccard_device *drv){	/*	 *	If already loaded, then reject the driver.	 */	if (find_driver(drv->name)) {		printf("Driver %s already loaded\n", drv->name);		return;	}	drv->next = drivers;	drivers = drv;}/* *	pccard_remove_driver - called to unlink driver *	from devices. Usually called when drivers are *	unloaded from kernel. */voidpccard_remove_driver(struct pccard_device *drv){	struct slot *slt;	struct pccard_devinfo *devi, *next;	struct pccard_device *drvlist;	for (slt = slot_list; slt; slt = slt->next)		for (devi = slt->devices; devi; devi = next) {			next = devi->next;			if (devi->drv == drv)				remove_device(devi);		}	/*	 *	Once all the devices belonging to this driver have been	 *	freed, then remove the driver from the list	 *	of registered drivers.	 */	if (drivers == drv)		drivers = drv->next;	else		for (drvlist = drivers; drvlist->next; drvlist = drvlist->next)			if (drvlist->next == drv) {				drvlist->next = drv->next;				break;			}}/* *	pccard_remove_controller - Called when the slot *	driver is unloaded. The plan is to unload *	drivers from the slots, and then remove the *	slots from the slot list, and then finally *	remove the controller structure. Messy... */voidpccard_remove_controller(struct slot_ctrl *ctrl){	struct slot *slt, *next, *last = 0;	struct slot_ctrl *cl;	struct pccard_devinfo *devi;	for (slt = slot_list; slt; slt = next) {		next = slt->next;		/*		 *	If this slot belongs to this controller,		 *	remove this slot.		 */		if (slt->ctrl == ctrl) {			pccard_slots[slt->slotnum] = 0;			if (slt->insert_seq)				untimeout(inserted, (void *)slt, slt->insert_ch);			/*			 * Unload the drivers attached to this slot.			 */			while (devi = slt->devices)				remove_device(devi);			/*			 * Disable the slot and unlink the slot from the 			 * slot list.			 */			disable_slot(slt);			if (last)				last->next = next;			else				slot_list = next;#if NAPM > 0			apm_hook_disestablish(APM_HOOK_SUSPEND,				&s_hook[slt->slotnum]);			apm_hook_disestablish(APM_HOOK_RESUME,				&r_hook[slt->slotnum]);#endif			if (ctrl->extra && slt->cdata)				FREE(slt->cdata, M_DEVBUF);			FREE(slt, M_DEVBUF);			/*			 * Can't use slot after we have freed it.			 */		} else {			last = slt;		}	}	/*	 *	Unlink controller structure from controller list.	 */	if (cont_list == ctrl)		cont_list = ctrl->next;	else		for (cl = cont_list; cl->next; cl = cl->next)			if (cl->next == ctrl) {				cl->next = ctrl->next;				break;			}}/* *	Power off the slot. *	(doing it immediately makes the removal of some cards unstable) */static voidpower_off_slot(void *arg){	struct slot *slt = (struct slot *)arg;	/* Power off the slot. */	slt->pwr_off_pending = 0;	slt->ctrl->disable(slt);}/* *	unregister_device_interrupt - Disable the interrupt generation to *	the device driver which is handling it, so we can remove it. */static voidunregister_device_interrupt(struct pccard_devinfo *devi){	struct slot *slt = devi->slt;	int s;	if (devi->running) {		s = splhigh();		devi->drv->disable(devi);		devi->running = 0;		if (devi->isahd.id_irq && --slt->irqref <= 0) {			printf("Return IRQ=%d\n",slt->irq);			slt->ctrl->mapirq(slt, 0);			INTRDIS(1<<slt->irq);			unregister_intr(slt->irq, slot_irq_handler);			if (devi->drv->imask)				INTRUNMASK(*devi->drv->imask,(1<<slt->irq));			/* Remove from the PCIC controller imask */			if (slt->ctrl->imask)				INTRUNMASK(*(slt->ctrl->imask), (1<<slt->irq));			slt->irq = 0;		}		splx(s);	}}/* *	disable_slot - Disables the slot by removing *	the power and unmapping the I/O */static voiddisable_slot(struct slot *slt){	struct pccard_devinfo *devi;	int i;	/*	 * Unload all the drivers on this slot. Note we can't	 * remove the device structures themselves, because this	 * may be called from the event routine, which is called	 * from the slot controller's ISR, and removing the structures	 * shouldn't happen during the middle of some driver activity.	 *	 * Note that a race condition is possible here; if a	 * driver is accessing the device and it is removed, then	 * all bets are off...	 */	for (devi = slt->devices; devi; devi = devi->next)		unregister_device_interrupt(devi);	/* Power off the slot 1/2 second after removal of the card */	slt->poff_ch = timeout(power_off_slot, (caddr_t)slt, hz / 2);	slt->pwr_off_pending = 1;	/* De-activate all contexts. */	for (i = 0; i < slt->ctrl->maxmem; i++)		if (slt->mem[i].flags & MDF_ACTIVE) {			slt->mem[i].flags = 0;			(void)slt->ctrl->mapmem(slt, i);		}	for (i = 0; i < slt->ctrl->maxio; i++)		if (slt->io[i].flags & IODF_ACTIVE) {			slt->io[i].flags = 0;			(void)slt->ctrl->mapio(slt, i);		}}/* *	APM hooks for suspending and resuming. */#if   NAPM > 0static intslot_suspend(void *arg){	struct slot *slt = arg;	/* This code stolen from pccard_event:card_removed */	if (slt->state == filled) {		int s = splhigh();		disable_slot(slt);		slt->laststate = filled;		slt->state = suspend;		splx(s);		printf("Card disabled, slot %d\n", slt->slotnum);	}	/*	 * Disable any pending timeouts for this slot since we're	 * powering it down/disabling now.	 */	untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);	slt->ctrl->disable(slt);	return (0);}static intslot_resume(void *arg){	struct slot *slt = arg;	if (pcic_resume_reset)		slt->ctrl->resume(slt);	/* This code stolen from pccard_event:card_inserted */	if (slt->state == suspend) {		slt->laststate = suspend;		slt->state = empty;		slt->insert_seq = 1;		untimeout(inserted, (void *)slt, slt->insert_ch);		slt->insert_ch = timeout(inserted, (void *)slt, hz/4);		selwakeup(&slt->selp);	}	return (0);}#endif	/* NAPM > 0 *//* *	pccard_alloc_slot - Called from controller probe *	routine, this function allocates a new PC-CARD slot *	and initialises the data structures using the data provided. *	It returns the allocated structure to the probe routine *	to allow the controller specific data to be initialised. */struct slot *pccard_alloc_slot(struct slot_ctrl *ctrl){	struct slot *slt;	int slotno;	for (slotno = 0; slotno < MAXSLOT; slotno++)		if (pccard_slots[slotno] == 0)			break;	if (slotno == MAXSLOT)		return(0);	MALLOC(slt, struct slot *, sizeof(*slt), M_DEVBUF, M_WAITOK);	bzero(slt, sizeof(*slt));#ifdef DEVFS	slt->devfs_token = devfs_add_devswf(&crd_cdevsw, 		slotno, DV_CHR, 0, 0, 0600, "card%d", slotno);#endif	if (ctrl->extra) {		MALLOC(slt->cdata, void *, ctrl->extra, M_DEVBUF, M_WAITOK);		bzero(slt->cdata, ctrl->extra);	}	slt->ctrl = ctrl;	slt->slotnum = slotno;	pccard_slots[slotno] = slt;	slt->next = slot_list;	slot_list = slt;	/*	 *	If this controller hasn't been seen before, then	 *	link it into the list of controllers.	 */	if (ctrl->slots++ == 0) {		ctrl->next = cont_list;		cont_list = ctrl;		if (ctrl->maxmem > NUM_MEM_WINDOWS)			ctrl->maxmem = NUM_MEM_WINDOWS;		if (ctrl->maxio > NUM_IO_WINDOWS)			ctrl->maxio = NUM_IO_WINDOWS;		printf("PC-Card %s (%d mem & %d I/O windows)\n",			ctrl->name, ctrl->maxmem, ctrl->maxio);	}	callout_handle_init(&slt->insert_ch);	callout_handle_init(&slt->poff_ch);#if NAPM > 0	{		struct apmhook *ap;		ap = &s_hook[slt->slotnum];		ap->ah_fun = slot_suspend;		ap->ah_arg = (void *)slt;		ap->ah_name = ctrl->name;		ap->ah_order = APM_MID_ORDER;		apm_hook_establish(APM_HOOK_SUSPEND, ap);		ap = &r_hook[slt->slotnum];		ap->ah_fun = slot_resume;		ap->ah_arg = (void *)slt;		ap->ah_name = ctrl->name;		ap->ah_order = APM_MID_ORDER;		apm_hook_establish(APM_HOOK_RESUME, ap);	}#endif /* NAPM > 0 */	return(slt);}/* *	pccard_alloc_intr - allocate an interrupt from the *	free interrupts and return its number. The interrupts *	allowed are passed as a mask. */intpccard_alloc_intr(u_int imask, inthand2_t *hand, int unit,		  u_int *maskp, u_int *pcic_imask){	int irq;	unsigned int mask;	for (irq = 1; irq < ICU_LEN; irq++) {		mask = 1ul << irq;		if (!(mask & imask))			continue;		INTRMASK(*maskp, mask);		if (register_intr(irq, 0, 0, hand, maskp, unit) == 0) {			/* add this to the PCIC controller's mask */			if (pcic_imask)				INTRMASK(*pcic_imask, (1 << irq));			update_intr_masks();			INTREN(mask);			return(irq);		}		/* No luck, remove from mask again... */		INTRUNMASK(*maskp, mask);		update_intr_masks();	}	return(-1);}/* *	allocate_driver - Create a new device entry for this *	slot, and attach a driver to it. */static intallocate_driver(struct slot *slt, struct dev_desc *desc){	struct pccard_devinfo *devi;	struct pccard_device *drv;	int err, irq = 0, s;	drv = find_driver(desc->name);	if (drv == 0)		return(ENXIO);	/*

⌨️ 快捷键说明

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