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 + -
显示快捷键?