📄 cardbus.c
字号:
list_add_tail(&c[i].dev.global_list, &pci_devices);#else if (i < fn-1) { c[i].dev.sibling = c[i].dev.next = &c[i+1].dev; }#endif }#ifdef NEWER_LINUX_PCI list_del(&tmp.global_list);#else s->cap.cb_bus->devices = &c[0].dev; /* Link into PCI device chain */ c[fn-1].dev.next = tmp.next; pci_devices = &c[0].dev;#endif for (i = 0; i < fn; i++) { c[i].dev.vendor = vend; pci_readw(&c[i].dev, PCI_DEVICE_ID, &c[i].dev.device); pci_readl(&c[i].dev, PCI_CLASS_REVISION, &c[i].dev.class); c[i].dev.class >>= 8;#ifdef NEW_LINUX_PCI c[i].dev.hdr_type = hdr;#endif#ifdef HAS_PROC_BUS pci_proc_attach_device(&c[i].dev);#endif } return CS_SUCCESS;}void cb_free(socket_info_t *s){ cb_config_t *c = s->cb_config; if (c) {#ifdef NEWER_LINUX_PCI int i; for (i = 0; i < s->functions; i++) list_del(&c[i].dev.global_list); INIT_LIST_HEAD(&s->cap.cb_bus->devices);#else struct pci_dev **p, *q; /* Unlink from PCI device chain */ for (p = &pci_devices; *p; p = &((*p)->next)) if (*p == &c[0].dev) break; for (q = *p; q; q = q->next) { if (q->bus != (*p)->bus) break;#ifdef HAS_PROC_BUS pci_proc_detach_device(q);#endif } if (*p) *p = q; s->cap.cb_bus->devices = NULL;#endif kfree(s->cb_config); s->cb_config = NULL; printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cardbus); }}/*===================================================================== cb_config() has the job of allocating all system resources that a Cardbus card requires. Rather than using the CIS (which seems to not always be present), it treats the card as an ordinary PCI device, and probes the base address registers to determine each function's IO and memory space needs. It is called from the RequestIO card service. ======================================================================*/int cb_config(socket_info_t *s){ cb_config_t *c = s->cb_config; u_char fn = s->functions; u_char i, j, *name; u_int sz, align, m, mask[3], num[3], base[3]; int irq; printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cardbus); /* Determine IO and memory space needs */ num[B_IO] = num[B_M1] = num[B_M2] = 0; mask[B_IO] = mask[B_M1] = mask[B_M2] = 0; for (i = 0; i < fn; i++) { for (j = 0; j < 6; j++) { pci_writel(&c[i].dev, CB_BAR(j), 0xffffffff); pci_readl(&c[i].dev, CB_BAR(j), &sz); if (sz == 0) continue; if (sz & PCI_BASE_ADDRESS_SPACE) { m = B_IO; sz &= PCI_BASE_ADDRESS_IO_MASK; } else { m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1; sz &= PCI_BASE_ADDRESS_MEM_MASK; } sz = FIND_FIRST_BIT(sz); c[i].size[j] = sz | m; if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE; num[m] += sz; mask[m] |= sz; } pci_writel(&c[i].dev, CB_ROM_BASE, 0xffffffff); pci_readl(&c[i].dev, CB_ROM_BASE, &sz); if (sz != 0) { sz = FIND_FIRST_BIT(sz & ~0x00000001); c[i].size[6] = sz | B_M1; if (sz < PAGE_SIZE) sz = PAGE_SIZE; num[B_M1] += sz; mask[B_M1] |= sz; } } /* Allocate system resources */ name = "cb_enabler"; s->io[0].NumPorts = num[B_IO]; s->io[0].BasePort = 0; if (num[B_IO]) { for (align = 1; align < mask[B_IO]; align <<= 1) ; if (find_io_region(&s->io[0].BasePort, num[B_IO], align, name) != 0) { printk(KERN_NOTICE "cs: could not allocate %d IO ports for" " CardBus socket %d\n", num[B_IO], s->sock); goto failed; } base[B_IO] = s->io[0].BasePort + num[B_IO]; } s->win[0].size = num[B_M1]; s->win[0].base = 0; if (num[B_M1]) { for (align = 1; align < mask[B_M1]; align <<= 1) ; if (find_mem_region(&s->win[0].base, num[B_M1], align, 0, name) != 0) { printk(KERN_NOTICE "cs: could not allocate %dK memory for" " CardBus socket %d\n", num[B_M1]/1024, s->sock); goto failed; } base[B_M1] = s->win[0].base + num[B_M1]; } s->win[1].size = num[B_M2]; s->win[1].base = 0; if (num[B_M2]) { for (align = 1; align < mask[B_M2]; align <<= 1) ; if (find_mem_region(&s->win[1].base, num[B_M2], align, 0, name) != 0) { printk(KERN_NOTICE "cs: could not allocate %dK memory for" " CardBus socket %d\n", num[B_M2]/1024, s->sock); goto failed; } base[B_M2] = s->win[1].base + num[B_M2]; } /* Set up base address registers */ while (mask[B_IO] | mask[B_M1] | mask[B_M2]) { num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO]; num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1]; num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2]; for (i = 0; i < fn; i++) { for (j = 0; j < 7; j++) { sz = c[i].size[j]; m = sz & 3; sz &= ~3; align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz; if (sz && (align == num[m])) { base[m] -= align; if (j < 6) printk(KERN_INFO " fn %d bar %d: ", i, j+1); else printk(KERN_INFO " fn %d rom: ", i); printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io", base[m], base[m]+sz-1); BASE(c[i], j) = base[m]; FLAGS(c[i], j) |= map_flags[m]; } } } } /* Allocate interrupt if needed */ s->irq.AssignedIRQ = irq = 0; for (i = 0; i < fn; i++) { pci_readb(&c[i].dev, PCI_INTERRUPT_PIN, &j); if (j == 0) continue; if ((irq == 0) && s->cap.pci_irq) irq = s->cap.pci_irq;#ifdef CONFIG_ISA if (irq == 0) { int try; for (try = 0; try < 2; try++) { for (irq = 0; irq < 32; irq++) if (((s->cap.irq_mask >> irq) & 1) && (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0)) break; if (irq < 32) break; } if (irq == 32) irq = 0; } if (irq == 0) { printk(KERN_NOTICE "cs: could not allocate interrupt" " for CardBus socket %d\n", s->sock); goto failed; }#endif } if (irq) printk(KERN_INFO " irq %d\n", irq); s->irq.AssignedIRQ = irq; for (i = 0; i < fn; i++) c[i].dev.irq = irq; return CS_SUCCESS;failed: cb_release(s); return CS_OUT_OF_RESOURCE;}/*====================================================================== cb_release() releases all the system resources (IO and memory space, and interrupt) committed for a Cardbus card by a prior call to cb_config(). It is called from the ReleaseIO() service. ======================================================================*/void cb_release(socket_info_t *s){ cb_config_t *c = s->cb_config; DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cardbus); if (s->win[0].size > 0) release_mem_region(s->win[0].base, s->win[0].size); if (s->win[1].size > 0) release_mem_region(s->win[1].base, s->win[1].size); if (s->io[0].NumPorts > 0) release_region(s->io[0].BasePort, s->io[0].NumPorts); s->io[0].NumPorts = 0;#ifdef CONFIG_ISA if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq);#endif}/*===================================================================== cb_enable() has the job of configuring a socket for a Cardbus card, and initializing the card's PCI configuration registers. It first sets up the Cardbus bridge windows, for IO and memory accesses. Then, it initializes each card function's base address registers, interrupt line register, and command register. It is called as part of the RequestConfiguration card service. It should be called after a previous call to cb_config() (via the RequestIO service). ======================================================================*/void cb_enable(socket_info_t *s){ u_char i, j, bus = s->cap.cardbus; cb_config_t *c = s->cb_config; DEBUG(0, "cs: cb_enable(bus %d)\n", bus); /* Configure bridge */ if (s->cb_cis_virt) cb_release_cis_mem(s); for (i = 0; i < 3; i++) { cb_bridge_map m; switch (i) { case B_IO: m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE; m.start = s->io[0].BasePort; m.stop = m.start + s->io[0].NumPorts - 1; break; case B_M1: m.map = 0; m.flags = MAP_ACTIVE; m.start = s->win[0].base; m.stop = m.start + s->win[0].size - 1; break; case B_M2: m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE; m.start = s->win[1].base; m.stop = m.start + s->win[1].size - 1; break; } if (m.start == 0) continue; DEBUG(0, " bridge %s map %d (flags 0x%x): 0x%x-0x%x\n", (m.flags & MAP_IOSPACE) ? "io" : "mem", m.map, m.flags, m.start, m.stop); s->ss_entry(s->sock, SS_SetBridge, &m); } /* Set up base address registers */ for (i = 0; i < s->functions; i++) { for (j = 0; j < 6; j++) { if (BASE(c[i], j) != 0) pci_writel(&c[i].dev, CB_BAR(j), BASE(c[i], j) | FLAGS(c[i], j)); } if (ROM(c[i]) != 0) pci_writel(&c[i].dev, CB_ROM_BASE, ROM(c[i]) | 1); } /* Set up a few basic PCI registers */ for (i = 0; i < s->functions; i++) { pci_writeb(&c[i].dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY); /* These are lame but I don't know how to do any better */ pci_writeb(&c[i].dev, PCI_CACHE_LINE_SIZE, 8); pci_writeb(&c[i].dev, PCI_LATENCY_TIMER, 64); } if (s->irq.AssignedIRQ) { for (i = 0; i < s->functions; i++) pci_writeb(&c[i].dev, PCI_INTERRUPT_LINE, s->irq.AssignedIRQ); s->socket.io_irq = s->irq.AssignedIRQ; s->ss_entry(s->sock, SS_SetSocket, &s->socket); }}/*====================================================================== cb_disable() unconfigures a Cardbus card previously set up by cb_enable(). It is called from the ReleaseConfiguration service. ======================================================================*/void cb_disable(socket_info_t *s){ u_char i; cb_bridge_map m = { 0, 0, 0, 0xffff }; DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cardbus); /* Turn off bridge windows */ if (s->cb_cis_virt) cb_release_cis_mem(s); for (i = 0; i < 3; i++) { switch (i) { case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break; case B_M1: m.map = m.flags = 0; break; case B_M2: m.map = 1; m.flags = 0; break; } s->ss_entry(s->sock, SS_SetBridge, &m); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -