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

📄 pccard.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	 *	If an instance of this driver is already installed,	 *	but not running, then remove it. If it is running,	 *	then reject the request.	 */	for (devi = slt->devices; devi; devi = devi->next)		if (devi->drv == drv && devi->isahd.id_unit == desc->unit) {			if (devi->running)				return(EBUSY);			remove_device(devi);			break;		}	/*	 *	If an interrupt mask has been given, then check it	 *	against the slot interrupt (if one has been allocated).	 */	if (desc->irqmask && drv->imask) {		if ((slt->ctrl->irqs & desc->irqmask) == 0)			return(EINVAL);		if (slt->irq) {			if (((1 << slt->irq) & desc->irqmask) == 0)				return(EINVAL);			slt->irqref++;			irq = slt->irq;		} else {			/*			 * Attempt to allocate an interrupt.			 * XXX We lose at the moment if the second 			 * device relies on a different interrupt mask.			 */			irq = pccard_alloc_intr(desc->irqmask,				slot_irq_handler, (int)slt,				drv->imask, slt->ctrl->imask);			if (irq < 0)				return(EINVAL);			slt->irq = irq;			slt->irqref = 1;			slt->ctrl->mapirq(slt, slt->irq);		}	}	MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF, M_WAITOK);	bzero(devi, sizeof(*devi));	/*	 *	Create an entry for the device under this slot.	 */	devi->running = 1;	devi->drv = drv;	devi->slt = slt;	devi->isahd.id_irq = irq;	devi->isahd.id_unit = desc->unit;	devi->isahd.id_msize = desc->memsize;	devi->isahd.id_iobase = desc->iobase;	bcopy(desc->misc, devi->misc, sizeof(desc->misc));	if (irq)		devi->isahd.id_irq = 1 << irq;	devi->isahd.id_flags = desc->flags;	/*	 *	Convert the memory to kernel space.	 */	if (desc->mem)		devi->isahd.id_maddr = 		    (caddr_t)(void *)(uintptr_t)		    (desc->mem + atdevbase - IOM_BEGIN);	else		devi->isahd.id_maddr = 0;	devi->next = slt->devices;	slt->devices = devi;	s = splhigh();	err = drv->enable(devi);	splx(s);	/*	 *	If the enable functions returns no error, then the	 *	device has been successfully installed. If so, then	 *	attach it to the slot, otherwise free it and return	 *	the error.  We assume that when we free the device,	 *	it will also set 'running' to off.	 */	if (err)		remove_device(devi);	return(err);}static voidremove_device(struct pccard_devinfo *devi){	struct slot *slt = devi->slt;	struct pccard_devinfo *list;	/*	 *	If an interrupt is enabled on this slot,	 *	then unregister it if no-one else is using it.	 */	unregister_device_interrupt(devi);	/*	 *	Remove from device list on this slot.	 */	if (slt->devices == devi)		slt->devices = devi->next;	else		for (list = slt->devices; list->next; list = list->next)			if (list->next == devi) {				list->next = devi->next;				break;			}	/*	 *	Finally, free the memory space.	 */	FREE(devi, M_DEVBUF);}/* *	card insert routine - Called from a timeout to debounce *	insertion events. */static voidinserted(void *arg){	struct slot *slt = arg;	slt->state = filled;	/*	 *	Enable 5V to the card so that the CIS can be read.	 */	slt->pwr.vcc = 50;	slt->pwr.vpp = 0;	/*	 * Disable any pending timeouts for this slot, and explicitly	 * power it off right now.  Then, re-enable the power using	 * the (possibly new) power settings.	 */	untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);	power_off_slot(slt);	slt->ctrl->power(slt);	printf("Card inserted, slot %d\n", slt->slotnum);	/*	 *	Now start resetting the card.	 */	slt->ctrl->reset(slt);}/* *	Card event callback. Called at splhigh to prevent *	device interrupts from interceding. */voidpccard_event(struct slot *slt, enum card_event event){	if (slt->insert_seq) {		slt->insert_seq = 0;		untimeout(inserted, (void *)slt, slt->insert_ch);	}	switch(event) {	case card_removed:		/*		 *	The slot and devices are disabled, but the		 *	data structures are not unlinked.		 */		if (slt->state == filled) {			int s = splhigh();			disable_slot(slt);			slt->state = empty;			splx(s);			printf("Card removed, slot %d\n", slt->slotnum);			pccard_remove_beep();			selwakeup(&slt->selp);		}		break;	case card_inserted:		slt->insert_seq = 1;		slt->insert_ch = timeout(inserted, (void *)slt, hz/4);		pccard_remove_beep();		break;	}}/* *	slot_irq_handler - Interrupt handler for shared irq devices. */static voidslot_irq_handler(void *arg){	struct pccard_devinfo *devi;	struct slot *slt = (struct slot *)arg;	/*	 *	For each device that has the shared interrupt,	 *	call the interrupt handler. If the interrupt was	 *	caught, the handler returns true.	 */	for (devi = slt->devices; devi; devi = devi->next)		if (devi->isahd.id_irq && devi->running &&		    devi->drv->handler(devi))			return;	/*	 * XXX - Should 'debounce' these for drivers that have recently	 * been removed.	 */	printf("Slot %d, unfielded interrupt (%d)\n", slt->slotnum, slt->irq);}/* *	Device driver interface. */static	intcrdopen(dev_t dev, int oflags, int devtype, struct proc *p){	struct slot *slt;	if (minor(dev) >= MAXSLOT)		return(ENXIO);	slt = pccard_slots[minor(dev)];	if (slt == 0)		return(ENXIO);	if (slt->rwmem == 0)		slt->rwmem = MDF_ATTR;	return(0);}/* *	Close doesn't de-allocate any resources, since *	slots may be assigned to drivers already. */static	intcrdclose(dev_t dev, int fflag, int devtype, struct proc *p){	return(0);}/* *	read interface. Map memory at lseek offset, *	then transfer to user space. */static	intcrdread(dev_t dev, struct uio *uio, int ioflag){	struct slot *slt = pccard_slots[minor(dev)];	struct mem_desc *mp, oldmap;	unsigned char *p;	unsigned int offs;	int error = 0, win, count;	if (slt == 0 || slt->state != filled)		return(ENXIO);	if (pccard_mem == 0)		return(ENOMEM);	for (win = 0; win < slt->ctrl->maxmem; win++)		if ((slt->mem[win].flags & MDF_ACTIVE) == 0)			break;	if (win >= slt->ctrl->maxmem)		return(EBUSY);	mp = &slt->mem[win];	oldmap = *mp;	mp->flags = slt->rwmem|MDF_ACTIVE;#if 0	printf("Rd at offs %d, size %d\n", (int)uio->uio_offset,				uio->uio_resid);#endif	while (uio->uio_resid && error == 0) {		mp->card = uio->uio_offset;		mp->size = PCCARD_MEMSIZE;		mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;		if (error = slt->ctrl->mapmem(slt, win))			break;		offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);		p = pccard_kmem + offs;		count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);		error = uiomove(p, count, uio);	}	/*	 *	Restore original map.	 */	*mp = oldmap;	slt->ctrl->mapmem(slt, win);	return(error);}/* *	crdwrite - Write data to card memory. *	Handles wrap around so that only one memory *	window is used. */static	intcrdwrite(dev_t dev, struct uio *uio, int ioflag){	struct slot *slt = pccard_slots[minor(dev)];	struct mem_desc *mp, oldmap;	unsigned char *p;	unsigned int offs;	int error = 0, win, count;	if (slt == 0 || slt->state != filled)		return(ENXIO);	if (pccard_mem == 0)		return(ENOMEM);	for (win = 0; win < slt->ctrl->maxmem; win++)		if ((slt->mem[win].flags & MDF_ACTIVE)==0)			break;	if (win >= slt->ctrl->maxmem)		return(EBUSY);	mp = &slt->mem[win];	oldmap = *mp;	mp->flags = slt->rwmem|MDF_ACTIVE;#if 0	printf("Wr at offs %d, size %d\n", (int)uio->uio_offset,				uio->uio_resid);#endif	while (uio->uio_resid && error == 0) {		mp->card = uio->uio_offset;		mp->size = PCCARD_MEMSIZE;		mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;		if (error = slt->ctrl->mapmem(slt, win))			break;		offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);		p = pccard_kmem + offs;		count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);#if 0	printf("Writing %d bytes to address 0x%x\n", count, p);#endif		error = uiomove(p, count, uio);	}	/*	 *	Restore original map.	 */	*mp = oldmap;	slt->ctrl->mapmem(slt, win);	return(error);}/* *	ioctl calls - allows setting/getting of memory and I/O *	descriptors, and assignment of drivers. */static	intcrdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p){	struct slot *slt = pccard_slots[minor(dev)];	struct mem_desc *mp;	struct io_desc *ip;	int s, err;	/* beep is disabled until the 1st call of crdioctl() */	pccard_beep_select(BEEP_ON);	if (slt == 0 && cmd != PIOCRWMEM)		return(ENXIO);	switch(cmd) {	default:		if (slt->ctrl->ioctl)			return(slt->ctrl->ioctl(slt, cmd, data));		return(EINVAL);	/*	 * Get slot state.	 */	case PIOCGSTATE:		s = splhigh();		((struct slotstate *)data)->state = slt->state;		((struct slotstate *)data)->laststate = slt->laststate;		slt->laststate = slt->state;		splx(s);		((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;		((struct slotstate *)data)->maxio = slt->ctrl->maxio;		((struct slotstate *)data)->irqs = slt->ctrl->irqs;		break;	/*	 * Get memory context.	 */	case PIOCGMEM:		s = ((struct mem_desc *)data)->window;		if (s < 0 || s >= slt->ctrl->maxmem)			return(EINVAL);		mp = &slt->mem[s];		((struct mem_desc *)data)->flags = mp->flags;		((struct mem_desc *)data)->start = mp->start;		((struct mem_desc *)data)->size = mp->size;		((struct mem_desc *)data)->card = mp->card;		break;	/*	 * Set memory context. If context already active, then unmap it.	 * It is hard to see how the parameters can be checked.	 * At the very least, we only allow root to set the context.	 */	case PIOCSMEM:		if (suser(p->p_ucred, &p->p_acflag))			return(EPERM);		if (slt->state != filled)			return(ENXIO);		s = ((struct mem_desc *)data)->window;		if (s < 0 || s >= slt->ctrl->maxmem)			return(EINVAL);		slt->mem[s] = *((struct mem_desc *)data);		return(slt->ctrl->mapmem(slt, s));	/*	 * Get I/O port context.	 */	case PIOCGIO:		s = ((struct io_desc *)data)->window;		if (s < 0 || s >= slt->ctrl->maxio)			return(EINVAL);		ip = &slt->io[s];		((struct io_desc *)data)->flags = ip->flags;		((struct io_desc *)data)->start = ip->start;		((struct io_desc *)data)->size = ip->size;		break;	/*	 * Set I/O port context.	 */	case PIOCSIO:		if (suser(p->p_ucred, &p->p_acflag))			return(EPERM);		if (slt->state != filled)			return(ENXIO);		s = ((struct io_desc *)data)->window;		if (s < 0 || s >= slt->ctrl->maxio)			return(EINVAL);		slt->io[s] = *((struct io_desc *)data);		return(slt->ctrl->mapio(slt, s));		break;	/*	 * Set memory window flags for read/write interface.	 */	case PIOCRWFLAG:		slt->rwmem = *(int *)data;		break;	/*	 * Set the memory window to be used for the read/write interface.	 */	case PIOCRWMEM:		if (*(unsigned long *)data == 0) {			if (pccard_mem)				*(unsigned long *)data = pccard_mem;			break;		}		if (suser(p->p_ucred, &p->p_acflag))			return(EPERM);		/*		 * Validate the memory by checking it against the I/O		 * memory range. It must also start on an aligned block size.		 */		if (invalid_io_memory(*(unsigned long *)data, PCCARD_MEMSIZE))			return(EINVAL);		if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))			return(EINVAL);		/*		 *	Map it to kernel VM.		 */		pccard_mem = *(unsigned long *)data;		pccard_kmem =		    (unsigned char *)(void *)(uintptr_t)		    (pccard_mem + atdevbase - IOM_BEGIN);		break;	/*	 * Set power values.	 */	case PIOCSPOW:		slt->pwr = *(struct power *)data;		return(slt->ctrl->power(slt));	/*	 * Allocate a driver to this slot.	 */	case PIOCSDRV:		if (suser(p->p_ucred, &p->p_acflag))			return(EPERM);		err = allocate_driver(slt, (struct dev_desc *)data);		if (!err)			pccard_success_beep();		else			pccard_failure_beep();		return err;	case PIOCSBEEP:		if (pccard_beep_select(*(int *)data)) {			return EINVAL;		}		break;	}	return(0);}/* *	poll - Poll on exceptions will return true *	when a change in card status occurs. */static	intcrdpoll(dev_t dev, int events, struct proc *p){	int s;	struct slot *slt = pccard_slots[minor(dev)];	int revents = 0;	if (events & (POLLIN | POLLRDNORM))		revents |= events & (POLLIN | POLLRDNORM);	if (events & (POLLOUT | POLLWRNORM))		revents |= events & (POLLIN | POLLRDNORM);	s = splhigh();	/*	 *	select for exception - card event.	 */	if (events & POLLRDBAND)		if (slt == 0 || slt->laststate != slt->state)			revents |= POLLRDBAND;	if (revents == 0)		selrecord(p, &slt->selp);	splx(s);	return (revents);}/* *	invalid_io_memory - verify that the ISA I/O memory block *	is a valid and unallocated address. *	A simple check of the range is done, and then a *	search of the current devices is done to check for *	overlapping regions. */static intinvalid_io_memory(unsigned long adr, int size){	/* XXX - What's magic about 0xC0000?? */	if (adr < 0xC0000 || (adr+size) > IOM_END)		return(1);	return(0);}static struct pccard_device *find_driver(char *name){	struct pccard_device *drv;	for (drv = drivers; drv; drv = drv->next)		if (strcmp(drv->name, name)==0)			return(drv);	return(0);}static crd_devsw_installed = 0;static voidcrd_drvinit(void *unused){	dev_t dev;	if (!crd_devsw_installed) {		dev = makedev(CDEV_MAJOR, 0);		cdevsw_add(&dev, &crd_cdevsw, NULL);		crd_devsw_installed = 1;	}}SYSINIT(crddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,crd_drvinit,NULL)

⌨️ 快捷键说明

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