| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * cardbus.c -- 16-bit PCMCIA core support | 
|  | 3 | * | 
|  | 4 | * This program is free software; you can redistribute it and/or modify | 
|  | 5 | * it under the terms of the GNU General Public License version 2 as | 
|  | 6 | * published by the Free Software Foundation. | 
|  | 7 | * | 
|  | 8 | * The initial developer of the original code is David A. Hinds | 
|  | 9 | * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds | 
|  | 10 | * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved. | 
|  | 11 | * | 
|  | 12 | * (C) 1999		David A. Hinds | 
|  | 13 | */ | 
|  | 14 |  | 
|  | 15 | /* | 
|  | 16 | * Cardbus handling has been re-written to be more of a PCI bridge thing, | 
|  | 17 | * and the PCI code basically does all the resource handling. | 
|  | 18 | * | 
|  | 19 | *		Linus, Jan 2000 | 
|  | 20 | */ | 
|  | 21 |  | 
|  | 22 |  | 
|  | 23 | #include <linux/module.h> | 
|  | 24 | #include <linux/kernel.h> | 
|  | 25 | #include <linux/string.h> | 
|  | 26 | #include <linux/slab.h> | 
|  | 27 | #include <linux/mm.h> | 
|  | 28 | #include <linux/pci.h> | 
|  | 29 | #include <linux/ioport.h> | 
|  | 30 | #include <asm/irq.h> | 
|  | 31 | #include <asm/io.h> | 
|  | 32 |  | 
|  | 33 | #define IN_CARD_SERVICES | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | #include <pcmcia/cs_types.h> | 
|  | 35 | #include <pcmcia/ss.h> | 
|  | 36 | #include <pcmcia/cs.h> | 
|  | 37 | #include <pcmcia/bulkmem.h> | 
|  | 38 | #include <pcmcia/cistpl.h> | 
|  | 39 | #include "cs_internal.h" | 
|  | 40 |  | 
|  | 41 | /*====================================================================*/ | 
|  | 42 |  | 
|  | 43 | #define FIND_FIRST_BIT(n)	((n) - ((n) & ((n)-1))) | 
|  | 44 |  | 
|  | 45 | /* Offsets in the Expansion ROM Image Header */ | 
|  | 46 | #define ROM_SIGNATURE		0x0000	/* 2 bytes */ | 
|  | 47 | #define ROM_DATA_PTR		0x0018	/* 2 bytes */ | 
|  | 48 |  | 
|  | 49 | /* Offsets in the CardBus PC Card Data Structure */ | 
|  | 50 | #define PCDATA_SIGNATURE	0x0000	/* 4 bytes */ | 
|  | 51 | #define PCDATA_VPD_PTR		0x0008	/* 2 bytes */ | 
|  | 52 | #define PCDATA_LENGTH		0x000a	/* 2 bytes */ | 
|  | 53 | #define PCDATA_REVISION		0x000c | 
|  | 54 | #define PCDATA_IMAGE_SZ		0x0010	/* 2 bytes */ | 
|  | 55 | #define PCDATA_ROM_LEVEL	0x0012	/* 2 bytes */ | 
|  | 56 | #define PCDATA_CODE_TYPE	0x0014 | 
|  | 57 | #define PCDATA_INDICATOR	0x0015 | 
|  | 58 |  | 
|  | 59 | /*===================================================================== | 
|  | 60 |  | 
|  | 61 | Expansion ROM's have a special layout, and pointers specify an | 
|  | 62 | image number and an offset within that image.  xlate_rom_addr() | 
|  | 63 | converts an image/offset address to an absolute offset from the | 
|  | 64 | ROM's base address. | 
|  | 65 |  | 
|  | 66 | =====================================================================*/ | 
|  | 67 |  | 
|  | 68 | static u_int xlate_rom_addr(void __iomem *b, u_int addr) | 
|  | 69 | { | 
|  | 70 | u_int img = 0, ofs = 0, sz; | 
|  | 71 | u_short data; | 
|  | 72 | while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { | 
|  | 73 | if (img == (addr >> 28)) | 
|  | 74 | return (addr & 0x0fffffff) + ofs; | 
|  | 75 | data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8); | 
|  | 76 | sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + | 
|  | 77 | (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); | 
|  | 78 | if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80)) | 
|  | 79 | break; | 
|  | 80 | b += sz; | 
|  | 81 | ofs += sz; | 
|  | 82 | img++; | 
|  | 83 | } | 
|  | 84 | return 0; | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | /*===================================================================== | 
|  | 88 |  | 
|  | 89 | These are similar to setup_cis_mem and release_cis_mem for 16-bit | 
|  | 90 | cards.  The "result" that is used externally is the cb_cis_virt | 
|  | 91 | pointer in the struct pcmcia_socket structure. | 
|  | 92 |  | 
|  | 93 | =====================================================================*/ | 
|  | 94 |  | 
|  | 95 | static void cb_release_cis_mem(struct pcmcia_socket * s) | 
|  | 96 | { | 
|  | 97 | if (s->cb_cis_virt) { | 
|  | 98 | cs_dbg(s, 1, "cb_release_cis_mem()\n"); | 
|  | 99 | iounmap(s->cb_cis_virt); | 
|  | 100 | s->cb_cis_virt = NULL; | 
|  | 101 | s->cb_cis_res = NULL; | 
|  | 102 | } | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | static int cb_setup_cis_mem(struct pcmcia_socket * s, struct resource *res) | 
|  | 106 | { | 
|  | 107 | unsigned int start, size; | 
|  | 108 |  | 
|  | 109 | if (res == s->cb_cis_res) | 
|  | 110 | return 0; | 
|  | 111 |  | 
|  | 112 | if (s->cb_cis_res) | 
|  | 113 | cb_release_cis_mem(s); | 
|  | 114 |  | 
|  | 115 | start = res->start; | 
|  | 116 | size = res->end - start + 1; | 
|  | 117 | s->cb_cis_virt = ioremap(start, size); | 
|  | 118 |  | 
|  | 119 | if (!s->cb_cis_virt) | 
|  | 120 | return -1; | 
|  | 121 |  | 
|  | 122 | s->cb_cis_res = res; | 
|  | 123 |  | 
|  | 124 | return 0; | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | /*===================================================================== | 
|  | 128 |  | 
|  | 129 | This is used by the CIS processing code to read CIS information | 
|  | 130 | from a CardBus device. | 
|  | 131 |  | 
|  | 132 | =====================================================================*/ | 
|  | 133 |  | 
|  | 134 | int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void *ptr) | 
|  | 135 | { | 
|  | 136 | struct pci_dev *dev; | 
|  | 137 | struct resource *res; | 
|  | 138 |  | 
|  | 139 | cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); | 
|  | 140 |  | 
|  | 141 | dev = pci_find_slot(s->cb_dev->subordinate->number, 0); | 
|  | 142 | if (!dev) | 
|  | 143 | goto fail; | 
|  | 144 |  | 
|  | 145 | /* Config space? */ | 
|  | 146 | if (space == 0) { | 
|  | 147 | if (addr + len > 0x100) | 
|  | 148 | goto fail; | 
|  | 149 | for (; len; addr++, ptr++, len--) | 
|  | 150 | pci_read_config_byte(dev, addr, ptr); | 
|  | 151 | return 0; | 
|  | 152 | } | 
|  | 153 |  | 
|  | 154 | res = dev->resource + space - 1; | 
|  | 155 | if (!res->flags) | 
|  | 156 | goto fail; | 
|  | 157 |  | 
|  | 158 | if (cb_setup_cis_mem(s, res) != 0) | 
|  | 159 | goto fail; | 
|  | 160 |  | 
|  | 161 | if (space == 7) { | 
|  | 162 | addr = xlate_rom_addr(s->cb_cis_virt, addr); | 
|  | 163 | if (addr == 0) | 
|  | 164 | goto fail; | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | if (addr + len > res->end - res->start) | 
|  | 168 | goto fail; | 
|  | 169 |  | 
|  | 170 | memcpy_fromio(ptr, s->cb_cis_virt + addr, len); | 
|  | 171 | return 0; | 
|  | 172 |  | 
|  | 173 | fail: | 
|  | 174 | memset(ptr, 0xff, len); | 
|  | 175 | return -1; | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | /*===================================================================== | 
|  | 179 |  | 
|  | 180 | cb_alloc() and cb_free() allocate and free the kernel data | 
|  | 181 | structures for a Cardbus device, and handle the lowest level PCI | 
|  | 182 | device setup issues. | 
|  | 183 |  | 
|  | 184 | =====================================================================*/ | 
|  | 185 |  | 
|  | 186 | /* | 
|  | 187 | * Since there is only one interrupt available to CardBus | 
|  | 188 | * devices, all devices downstream of this device must | 
|  | 189 | * be using this IRQ. | 
|  | 190 | */ | 
|  | 191 | static void cardbus_assign_irqs(struct pci_bus *bus, int irq) | 
|  | 192 | { | 
|  | 193 | struct pci_dev *dev; | 
|  | 194 |  | 
|  | 195 | list_for_each_entry(dev, &bus->devices, bus_list) { | 
|  | 196 | u8 irq_pin; | 
|  | 197 |  | 
|  | 198 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); | 
|  | 199 | if (irq_pin) { | 
|  | 200 | dev->irq = irq; | 
|  | 201 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | if (dev->subordinate) | 
|  | 205 | cardbus_assign_irqs(dev->subordinate, irq); | 
|  | 206 | } | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | int cb_alloc(struct pcmcia_socket * s) | 
|  | 210 | { | 
|  | 211 | struct pci_bus *bus = s->cb_dev->subordinate; | 
|  | 212 | struct pci_dev *dev; | 
|  | 213 | unsigned int max, pass; | 
|  | 214 |  | 
|  | 215 | s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); | 
|  | 216 | //	pcibios_fixup_bus(bus); | 
|  | 217 |  | 
|  | 218 | max = bus->secondary; | 
|  | 219 | for (pass = 0; pass < 2; pass++) | 
|  | 220 | list_for_each_entry(dev, &bus->devices, bus_list) | 
|  | 221 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 
|  | 222 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | 
|  | 223 | max = pci_scan_bridge(bus, dev, max, pass); | 
|  | 224 |  | 
|  | 225 | /* | 
|  | 226 | * Size all resources below the CardBus controller. | 
|  | 227 | */ | 
|  | 228 | pci_bus_size_bridges(bus); | 
|  | 229 | pci_bus_assign_resources(bus); | 
|  | 230 | cardbus_assign_irqs(bus, s->pci_irq); | 
|  | 231 | pci_enable_bridges(bus); | 
|  | 232 | pci_bus_add_devices(bus); | 
|  | 233 |  | 
|  | 234 | s->irq.AssignedIRQ = s->pci_irq; | 
|  | 235 | return CS_SUCCESS; | 
|  | 236 | } | 
|  | 237 |  | 
|  | 238 | void cb_free(struct pcmcia_socket * s) | 
|  | 239 | { | 
|  | 240 | struct pci_dev *bridge = s->cb_dev; | 
|  | 241 |  | 
|  | 242 | cb_release_cis_mem(s); | 
|  | 243 |  | 
|  | 244 | if (bridge) | 
|  | 245 | pci_remove_behind_bridge(bridge); | 
|  | 246 | } |