pcmcia_resource.c

来自「linux 内核源代码」· C语言 代码 · 共 973 行 · 第 1/2 页

C
973
字号
	config_t *c = p_dev->function_config;	int i;	if (p_dev->_locked) {		p_dev->_locked = 0;		if (--(s->lock_count) == 0) {			s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */			s->socket.Vpp = 0;			s->socket.io_irq = 0;			s->ops->set_socket(s, &s->socket);		}	}	if (c->state & CONFIG_LOCKED) {		c->state &= ~CONFIG_LOCKED;		if (c->state & CONFIG_IO_REQ)			for (i = 0; i < MAX_IO_WIN; i++) {				if (!s->io[i].res)					continue;				s->io[i].Config--;				if (s->io[i].Config != 0)					continue;				io.map = i;				s->ops->set_io_map(s, &io);			}	}	return CS_SUCCESS;} /* pcmcia_release_configuration *//** pcmcia_release_io * * Release_io() releases the I/O ranges allocated by a client.  This * may be invoked some time after a card ejection has already dumped * the actual socket configuration, so if the client is "stale", we * don't bother checking the port ranges against the current socket * values. */static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req){	struct pcmcia_socket *s = p_dev->socket;	config_t *c = p_dev->function_config;	if (!p_dev->_io )		return CS_BAD_HANDLE;	p_dev->_io = 0;	if ((c->io.BasePort1 != req->BasePort1) ||	    (c->io.NumPorts1 != req->NumPorts1) ||	    (c->io.BasePort2 != req->BasePort2) ||	    (c->io.NumPorts2 != req->NumPorts2))		return CS_BAD_ARGS;	c->state &= ~CONFIG_IO_REQ;	release_io_space(s, req->BasePort1, req->NumPorts1);	if (req->NumPorts2)		release_io_space(s, req->BasePort2, req->NumPorts2);	return CS_SUCCESS;} /* pcmcia_release_io */static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req){	struct pcmcia_socket *s = p_dev->socket;	config_t *c= p_dev->function_config;	if (!p_dev->_irq)		return CS_BAD_HANDLE;	p_dev->_irq = 0;	if (c->state & CONFIG_LOCKED)		return CS_CONFIGURATION_LOCKED;	if (c->irq.Attributes != req->Attributes)		return CS_BAD_ATTRIBUTE;	if (s->irq.AssignedIRQ != req->AssignedIRQ)		return CS_BAD_IRQ;	if (--s->irq.Config == 0) {		c->state &= ~CONFIG_IRQ_REQ;		s->irq.AssignedIRQ = 0;	}	if (req->Attributes & IRQ_HANDLE_PRESENT) {		free_irq(req->AssignedIRQ, req->Instance);	}#ifdef CONFIG_PCMCIA_PROBE	pcmcia_used_irq[req->AssignedIRQ]--;#endif	return CS_SUCCESS;} /* pcmcia_release_irq */int pcmcia_release_window(window_handle_t win){	struct pcmcia_socket *s;	if ((win == NULL) || (win->magic != WINDOW_MAGIC))		return CS_BAD_HANDLE;	s = win->sock;	if (!(win->handle->_win & CLIENT_WIN_REQ(win->index)))		return CS_BAD_HANDLE;	/* Shut down memory window */	win->ctl.flags &= ~MAP_ACTIVE;	s->ops->set_mem_map(s, &win->ctl);	s->state &= ~SOCKET_WIN_REQ(win->index);	/* Release system memory */	if (win->ctl.res) {		release_resource(win->ctl.res);		kfree(win->ctl.res);		win->ctl.res = NULL;	}	win->handle->_win &= ~CLIENT_WIN_REQ(win->index);	win->magic = 0;	return CS_SUCCESS;} /* pcmcia_release_window */EXPORT_SYMBOL(pcmcia_release_window);int pcmcia_request_configuration(struct pcmcia_device *p_dev,				 config_req_t *req){	int i;	u_int base;	struct pcmcia_socket *s = p_dev->socket;	config_t *c;	pccard_io_map iomap;	if (!(s->state & SOCKET_PRESENT))		return CS_NO_CARD;	if (req->IntType & INT_CARDBUS)		return CS_UNSUPPORTED_MODE;	c = p_dev->function_config;	if (c->state & CONFIG_LOCKED)		return CS_CONFIGURATION_LOCKED;	/* Do power control.  We don't allow changes in Vcc. */	s->socket.Vpp = req->Vpp;	if (s->ops->set_socket(s, &s->socket))		return CS_BAD_VPP;	/* Pick memory or I/O card, DMA mode, interrupt */	c->IntType = req->IntType;	c->Attributes = req->Attributes;	if (req->IntType & INT_MEMORY_AND_IO)		s->socket.flags |= SS_IOCARD;	if (req->IntType & INT_ZOOMED_VIDEO)		s->socket.flags |= SS_ZVCARD | SS_IOCARD;	if (req->Attributes & CONF_ENABLE_DMA)		s->socket.flags |= SS_DMA_MODE;	if (req->Attributes & CONF_ENABLE_SPKR)		s->socket.flags |= SS_SPKR_ENA;	if (req->Attributes & CONF_ENABLE_IRQ)		s->socket.io_irq = s->irq.AssignedIRQ;	else		s->socket.io_irq = 0;	s->ops->set_socket(s, &s->socket);	s->lock_count++;	/* Set up CIS configuration registers */	base = c->ConfigBase = req->ConfigBase;	c->CardValues = req->Present;	if (req->Present & PRESENT_COPY) {		c->Copy = req->Copy;		pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);	}	if (req->Present & PRESENT_OPTION) {		if (s->functions == 1) {			c->Option = req->ConfigIndex & COR_CONFIG_MASK;		} else {			c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;			c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;			if (req->Present & PRESENT_IOBASE_0)				c->Option |= COR_ADDR_DECODE;		}		if (c->state & CONFIG_IRQ_REQ)			if (!(c->irq.Attributes & IRQ_FORCED_PULSE))				c->Option |= COR_LEVEL_REQ;		pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);		mdelay(40);	}	if (req->Present & PRESENT_STATUS) {		c->Status = req->Status;		pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);	}	if (req->Present & PRESENT_PIN_REPLACE) {		c->Pin = req->Pin;		pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);	}	if (req->Present & PRESENT_EXT_STATUS) {		c->ExtStatus = req->ExtStatus;		pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);	}	if (req->Present & PRESENT_IOBASE_0) {		u_char b = c->io.BasePort1 & 0xff;		pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);		b = (c->io.BasePort1 >> 8) & 0xff;		pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);	}	if (req->Present & PRESENT_IOSIZE) {		u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;		pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);	}	/* Configure I/O windows */	if (c->state & CONFIG_IO_REQ) {		iomap.speed = io_speed;		for (i = 0; i < MAX_IO_WIN; i++)			if (s->io[i].res) {				iomap.map = i;				iomap.flags = MAP_ACTIVE;				switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) {				case IO_DATA_PATH_WIDTH_16:					iomap.flags |= MAP_16BIT; break;				case IO_DATA_PATH_WIDTH_AUTO:					iomap.flags |= MAP_AUTOSZ; break;				default:					break;				}				iomap.start = s->io[i].res->start;				iomap.stop = s->io[i].res->end;				s->ops->set_io_map(s, &iomap);				s->io[i].Config++;			}	}	c->state |= CONFIG_LOCKED;	p_dev->_locked = 1;	return CS_SUCCESS;} /* pcmcia_request_configuration */EXPORT_SYMBOL(pcmcia_request_configuration);/** pcmcia_request_io * * Request_io() reserves ranges of port addresses for a socket. * I have not implemented range sharing or alias addressing. */int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req){	struct pcmcia_socket *s = p_dev->socket;	config_t *c;	if (!(s->state & SOCKET_PRESENT))		return CS_NO_CARD;	if (!req)		return CS_UNSUPPORTED_MODE;	c = p_dev->function_config;	if (c->state & CONFIG_LOCKED)		return CS_CONFIGURATION_LOCKED;	if (c->state & CONFIG_IO_REQ)		return CS_IN_USE;	if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))		return CS_BAD_ATTRIBUTE;	if ((req->NumPorts2 > 0) &&	    (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))		return CS_BAD_ATTRIBUTE;	if (alloc_io_space(s, req->Attributes1, &req->BasePort1,			   req->NumPorts1, req->IOAddrLines))		return CS_IN_USE;	if (req->NumPorts2) {		if (alloc_io_space(s, req->Attributes2, &req->BasePort2,				   req->NumPorts2, req->IOAddrLines)) {			release_io_space(s, req->BasePort1, req->NumPorts1);			return CS_IN_USE;		}	}	c->io = *req;	c->state |= CONFIG_IO_REQ;	p_dev->_io = 1;	return CS_SUCCESS;} /* pcmcia_request_io */EXPORT_SYMBOL(pcmcia_request_io);/** pcmcia_request_irq * * Request_irq() reserves an irq for this client. * * Also, since Linux only reserves irq's when they are actually * hooked, we don't guarantee that an irq will still be available * when the configuration is locked.  Now that I think about it, * there might be a way to fix this using a dummy handler. */#ifdef CONFIG_PCMCIA_PROBEstatic irqreturn_t test_action(int cpl, void *dev_id){	return IRQ_NONE;}#endifint pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req){	struct pcmcia_socket *s = p_dev->socket;	config_t *c;	int ret = CS_IN_USE, irq = 0;	int type;	if (!(s->state & SOCKET_PRESENT))		return CS_NO_CARD;	c = p_dev->function_config;	if (c->state & CONFIG_LOCKED)		return CS_CONFIGURATION_LOCKED;	if (c->state & CONFIG_IRQ_REQ)		return CS_IN_USE;	/* Decide what type of interrupt we are registering */	type = 0;	if (s->functions > 1)		/* All of this ought to be handled higher up */		type = IRQF_SHARED;	if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)		type = IRQF_SHARED;#ifdef CONFIG_PCMCIA_PROBE	if (s->irq.AssignedIRQ != 0) {		/* If the interrupt is already assigned, it must be the same */		irq = s->irq.AssignedIRQ;	} else {		int try;		u32 mask = s->irq_mask;		void *data = &p_dev->dev.driver; /* something unique to this device */		for (try = 0; try < 64; try++) {			irq = try % 32;			/* marked as available by driver, and not blocked by userspace? */			if (!((mask >> irq) & 1))				continue;			/* avoid an IRQ which is already used by a PCMCIA card */			if ((try < 32) && pcmcia_used_irq[irq])				continue;			/* register the correct driver, if possible, of check whether			 * registering a dummy handle works, i.e. if the IRQ isn't			 * marked as used by the kernel resource management core */			ret = request_irq(irq,					  (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,					  type,					  p_dev->devname,					  (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);			if (!ret) {				if (!(req->Attributes & IRQ_HANDLE_PRESENT))					free_irq(irq, data);				break;			}		}	}#endif	/* only assign PCI irq if no IRQ already assigned */	if (ret && !s->irq.AssignedIRQ) {		if (!s->pci_irq)			return ret;		type = IRQF_SHARED;		irq = s->pci_irq;	}	if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) {		if (request_irq(irq, req->Handler, type,  p_dev->devname, req->Instance))			return CS_IN_USE;	}	/* Make sure the fact the request type was overridden is passed back */	if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {		req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;		printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n");		printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n");	}	c->irq.Attributes = req->Attributes;	s->irq.AssignedIRQ = req->AssignedIRQ = irq;	s->irq.Config++;	c->state |= CONFIG_IRQ_REQ;	p_dev->_irq = 1;#ifdef CONFIG_PCMCIA_PROBE	pcmcia_used_irq[irq]++;#endif	return CS_SUCCESS;} /* pcmcia_request_irq */EXPORT_SYMBOL(pcmcia_request_irq);/** pcmcia_request_window * * Request_window() establishes a mapping between card memory space * and system memory space. */int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh){	struct pcmcia_socket *s = (*p_dev)->socket;	window_t *win;	u_long align;	int w;	if (!(s->state & SOCKET_PRESENT))		return CS_NO_CARD;	if (req->Attributes & (WIN_PAGED | WIN_SHARED))		return CS_BAD_ATTRIBUTE;	/* Window size defaults to smallest available */	if (req->Size == 0)		req->Size = s->map_size;	align = (((s->features & SS_CAP_MEM_ALIGN) ||		  (req->Attributes & WIN_STRICT_ALIGN)) ?		 req->Size : s->map_size);	if (req->Size & (s->map_size-1))		return CS_BAD_SIZE;	if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||	    (req->Base & (align-1)))		return CS_BAD_BASE;	if (req->Base)		align = 0;	/* Allocate system memory window */	for (w = 0; w < MAX_WIN; w++)		if (!(s->state & SOCKET_WIN_REQ(w))) break;	if (w == MAX_WIN)		return CS_OUT_OF_RESOURCE;	win = &s->win[w];	win->magic = WINDOW_MAGIC;	win->index = w;	win->handle = *p_dev;	win->sock = s;	if (!(s->features & SS_CAP_STATIC_MAP)) {		win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,						      (req->Attributes & WIN_MAP_BELOW_1MB), s);		if (!win->ctl.res)			return CS_IN_USE;	}	(*p_dev)->_win |= CLIENT_WIN_REQ(w);	/* Configure the socket controller */	win->ctl.map = w+1;	win->ctl.flags = 0;	win->ctl.speed = req->AccessSpeed;	if (req->Attributes & WIN_MEMORY_TYPE)		win->ctl.flags |= MAP_ATTRIB;	if (req->Attributes & WIN_ENABLE)		win->ctl.flags |= MAP_ACTIVE;	if (req->Attributes & WIN_DATA_WIDTH_16)		win->ctl.flags |= MAP_16BIT;	if (req->Attributes & WIN_USE_WAIT)		win->ctl.flags |= MAP_USE_WAIT;	win->ctl.card_start = 0;	if (s->ops->set_mem_map(s, &win->ctl) != 0)		return CS_BAD_ARGS;	s->state |= SOCKET_WIN_REQ(w);	/* Return window handle */	if (s->features & SS_CAP_STATIC_MAP) {		req->Base = win->ctl.static_start;	} else {		req->Base = win->ctl.res->start;	}	*wh = win;	return CS_SUCCESS;} /* pcmcia_request_window */EXPORT_SYMBOL(pcmcia_request_window);void pcmcia_disable_device(struct pcmcia_device *p_dev) {	pcmcia_release_configuration(p_dev);	pcmcia_release_io(p_dev, &p_dev->io);	pcmcia_release_irq(p_dev, &p_dev->irq);	if (&p_dev->win)		pcmcia_release_window(p_dev->win);}EXPORT_SYMBOL(pcmcia_disable_device);

⌨️ 快捷键说明

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