| 1 | /* $NetBSD: pcmciavar.h,v 1.35 2011/07/26 22:24:36 dyoung Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 1997 Marc Horowitz. All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions |
| 8 | * are met: |
| 9 | * 1. Redistributions of source code must retain the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer. |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer in the |
| 13 | * documentation and/or other materials provided with the distribution. |
| 14 | * 3. All advertising materials mentioning features or use of this software |
| 15 | * must display the following acknowledgement: |
| 16 | * This product includes software developed by Marc Horowitz. |
| 17 | * 4. The name of the author may not be used to endorse or promote products |
| 18 | * derived from this software without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | */ |
| 31 | |
| 32 | #include <sys/types.h> |
| 33 | #include <sys/queue.h> |
| 34 | |
| 35 | #include <dev/pcmcia/pcmciachip.h> |
| 36 | |
| 37 | extern int pcmcia_verbose; |
| 38 | |
| 39 | /* |
| 40 | * Contains information about mapped/allocated i/o spaces. |
| 41 | */ |
| 42 | struct pcmcia_io_handle { |
| 43 | bus_space_tag_t iot; /* bus space tag (from chipset) */ |
| 44 | bus_space_handle_t ioh; /* mapped space handle */ |
| 45 | bus_addr_t addr; /* resulting address in bus space */ |
| 46 | bus_size_t size; /* size of i/o space */ |
| 47 | int flags; /* misc. information */ |
| 48 | void *ihandle; /* opaque i/o handle */ |
| 49 | }; |
| 50 | |
| 51 | #define PCMCIA_IO_ALLOCATED 0x01 /* i/o space was allocated */ |
| 52 | |
| 53 | /* |
| 54 | * Contains information about allocated memory space. |
| 55 | */ |
| 56 | struct pcmcia_mem_handle { |
| 57 | bus_space_tag_t memt; /* bus space tag (from chipset) */ |
| 58 | bus_space_handle_t memh; /* mapped space handle */ |
| 59 | bus_addr_t addr; /* resulting address in bus space */ |
| 60 | bus_size_t size; /* size of mem space */ |
| 61 | pcmcia_mem_handle_t mhandle; /* opaque memory handle */ |
| 62 | bus_size_t realsize; /* how much we really allocated */ |
| 63 | }; |
| 64 | |
| 65 | /* pcmcia itself */ |
| 66 | |
| 67 | #define PCMCIA_CFE_MWAIT_REQUIRED 0x0001 |
| 68 | #define PCMCIA_CFE_RDYBSY_ACTIVE 0x0002 |
| 69 | #define PCMCIA_CFE_WP_ACTIVE 0x0004 |
| 70 | #define PCMCIA_CFE_BVD_ACTIVE 0x0008 |
| 71 | #define PCMCIA_CFE_IO8 0x0010 |
| 72 | #define PCMCIA_CFE_IO16 0x0020 |
| 73 | #define PCMCIA_CFE_IRQSHARE 0x0040 |
| 74 | #define PCMCIA_CFE_IRQPULSE 0x0080 |
| 75 | #define PCMCIA_CFE_IRQLEVEL 0x0100 |
| 76 | #define PCMCIA_CFE_POWERDOWN 0x0200 |
| 77 | #define PCMCIA_CFE_READONLY 0x0400 |
| 78 | #define PCMCIA_CFE_AUDIO 0x0800 |
| 79 | |
| 80 | struct pcmcia_config_entry { |
| 81 | int number; |
| 82 | u_int32_t flags; |
| 83 | int iftype; |
| 84 | int num_iospace; |
| 85 | |
| 86 | /* |
| 87 | * The card will only decode this mask in any case, so we can |
| 88 | * do dynamic allocation with this in mind, in case the suggestions |
| 89 | * below are no good. |
| 90 | */ |
| 91 | u_long iomask; |
| 92 | struct { |
| 93 | u_long length; |
| 94 | u_long start; |
| 95 | |
| 96 | struct pcmcia_io_handle handle; |
| 97 | int window; |
| 98 | } iospace[4]; /* XXX this could be as high as 16 */ |
| 99 | u_int16_t irqmask; |
| 100 | int num_memspace; |
| 101 | struct { |
| 102 | u_long length; |
| 103 | u_long cardaddr; |
| 104 | u_long hostaddr; |
| 105 | |
| 106 | struct pcmcia_mem_handle handle; |
| 107 | bus_size_t offset; |
| 108 | int window; |
| 109 | |
| 110 | } memspace[2]; /* XXX this could be as high as 8 */ |
| 111 | int maxtwins; |
| 112 | SIMPLEQ_ENTRY(pcmcia_config_entry) cfe_list; |
| 113 | }; |
| 114 | |
| 115 | |
| 116 | struct pcmcia_funce_disk { |
| 117 | int pfd_interface; |
| 118 | }; |
| 119 | |
| 120 | struct pcmcia_funce_lan { |
| 121 | int pfl_nidlen; |
| 122 | u_int8_t pfl_nid[8]; |
| 123 | }; |
| 124 | |
| 125 | union pcmcia_funce { |
| 126 | struct pcmcia_funce_disk pfv_disk; |
| 127 | struct pcmcia_funce_lan pfv_lan; |
| 128 | }; |
| 129 | |
| 130 | |
| 131 | struct pcmcia_function { |
| 132 | /* read off the card */ |
| 133 | int number; |
| 134 | int function; |
| 135 | int last_config_index; |
| 136 | u_long ccr_base; |
| 137 | u_long ccr_mask; |
| 138 | SIMPLEQ_HEAD(, pcmcia_config_entry) cfe_head; |
| 139 | SIMPLEQ_ENTRY(pcmcia_function) pf_list; |
| 140 | /* run-time state */ |
| 141 | struct pcmcia_softc *sc; |
| 142 | device_t child; |
| 143 | struct pcmcia_config_entry *cfe; |
| 144 | struct pcmcia_mem_handle pf_pcmh; |
| 145 | #define pf_ccrt pf_pcmh.memt |
| 146 | #define pf_ccrh pf_pcmh.memh |
| 147 | #define pf_ccr_mhandle pf_pcmh.mhandle |
| 148 | #define pf_ccr_realsize pf_pcmh.realsize |
| 149 | bus_size_t pf_ccr_offset; |
| 150 | int pf_ccr_window; |
| 151 | bus_addr_t pf_mfc_iobase; |
| 152 | bus_addr_t pf_mfc_iomax; |
| 153 | void *pf_ih; |
| 154 | int pf_flags; |
| 155 | |
| 156 | union pcmcia_funce pf_funce; /* CISTPL_FUNCE */ |
| 157 | #define pf_funce_disk_interface pf_funce.pfv_disk.pfd_interface |
| 158 | #define pf_funce_lan_nid pf_funce.pfv_lan.pfl_nid |
| 159 | #define pf_funce_lan_nidlen pf_funce.pfv_lan.pfl_nidlen |
| 160 | }; |
| 161 | |
| 162 | /* pf_flags */ |
| 163 | #define PFF_ENABLED 0x0001 /* function is enabled */ |
| 164 | #define PFF_DETACHED 0x0002 /* card is detached */ |
| 165 | |
| 166 | SIMPLEQ_HEAD(pcmcia_function_head, pcmcia_function); |
| 167 | |
| 168 | struct pcmcia_card { |
| 169 | int cis1_major; |
| 170 | int cis1_minor; |
| 171 | /* XXX waste of space? */ |
| 172 | char cis1_info_buf[256]; |
| 173 | char *cis1_info[4]; |
| 174 | /* |
| 175 | * Use int32_t for manufacturer and product so that they can |
| 176 | * hold the id value found in card CIS and special value that |
| 177 | * indicates no id was found. |
| 178 | */ |
| 179 | int32_t manufacturer; |
| 180 | #define PCMCIA_VENDOR_INVALID -1 |
| 181 | int32_t product; |
| 182 | #define PCMCIA_PRODUCT_INVALID -1 |
| 183 | u_int16_t error; |
| 184 | #define PCMCIA_CIS_INVALID { NULL, NULL, NULL, NULL } |
| 185 | struct pcmcia_function_head pf_head; |
| 186 | }; |
| 187 | |
| 188 | struct pcmcia_softc { |
| 189 | device_t dev; |
| 190 | |
| 191 | /* this stuff is for the socket */ |
| 192 | pcmcia_chipset_tag_t pct; |
| 193 | pcmcia_chipset_handle_t pch; |
| 194 | |
| 195 | /* this stuff is for the card */ |
| 196 | struct pcmcia_card card; |
| 197 | void *ih; |
| 198 | int sc_enabled_count; /* how many functions are |
| 199 | enabled */ |
| 200 | }; |
| 201 | |
| 202 | struct pcmcia_cis_quirk { |
| 203 | int32_t manufacturer; |
| 204 | int32_t product; |
| 205 | const char *cis1_info[4]; |
| 206 | const struct pcmcia_function *pf; |
| 207 | const struct pcmcia_config_entry *cfe; |
| 208 | }; |
| 209 | |
| 210 | struct pcmcia_attach_args { |
| 211 | int32_t manufacturer; |
| 212 | int32_t product; |
| 213 | struct pcmcia_card *card; |
| 214 | struct pcmcia_function *pf; |
| 215 | }; |
| 216 | |
| 217 | struct pcmcia_tuple { |
| 218 | unsigned int code; |
| 219 | unsigned int length; |
| 220 | u_long mult; |
| 221 | bus_size_t ptr; |
| 222 | bus_space_tag_t memt; |
| 223 | bus_space_handle_t memh; |
| 224 | }; |
| 225 | |
| 226 | struct pcmcia_product { |
| 227 | u_int32_t pp_vendor; |
| 228 | u_int32_t pp_product; |
| 229 | const char *pp_cisinfo[4]; |
| 230 | }; |
| 231 | |
| 232 | typedef int (*pcmcia_product_match_fn)(struct pcmcia_attach_args *, |
| 233 | const struct pcmcia_product *, int); |
| 234 | |
| 235 | const void *pcmcia_product_lookup(struct pcmcia_attach_args *, const void *, |
| 236 | size_t, size_t, pcmcia_product_match_fn); |
| 237 | |
| 238 | void pcmcia_devinfo(struct pcmcia_card *, int, char *, size_t); |
| 239 | |
| 240 | void pcmcia_read_cis(struct pcmcia_softc *); |
| 241 | void pcmcia_check_cis_quirks(struct pcmcia_softc *); |
| 242 | void pcmcia_print_cis(struct pcmcia_softc *); |
| 243 | int pcmcia_scan_cis(device_t, |
| 244 | int (*) (struct pcmcia_tuple *, void *), void *); |
| 245 | |
| 246 | #define pcmcia_cis_read_1(tuple, idx0) \ |
| 247 | (bus_space_read_1((tuple)->memt, (tuple)->memh, (tuple)->mult*(idx0))) |
| 248 | |
| 249 | #define pcmcia_tuple_read_1(tuple, idx1) \ |
| 250 | (pcmcia_cis_read_1((tuple), ((tuple)->ptr+(2+(idx1))))) |
| 251 | |
| 252 | #define pcmcia_tuple_read_2(tuple, idx2) \ |
| 253 | (pcmcia_tuple_read_1((tuple), (idx2)) | \ |
| 254 | (pcmcia_tuple_read_1((tuple), (idx2)+1)<<8)) |
| 255 | |
| 256 | #define pcmcia_tuple_read_3(tuple, idx3) \ |
| 257 | (pcmcia_tuple_read_1((tuple), (idx3)) | \ |
| 258 | (pcmcia_tuple_read_1((tuple), (idx3)+1)<<8) | \ |
| 259 | (pcmcia_tuple_read_1((tuple), (idx3)+2)<<16)) |
| 260 | |
| 261 | #define pcmcia_tuple_read_4(tuple, idx4) \ |
| 262 | (pcmcia_tuple_read_1((tuple), (idx4)) | \ |
| 263 | (pcmcia_tuple_read_1((tuple), (idx4)+1)<<8) | \ |
| 264 | (pcmcia_tuple_read_1((tuple), (idx4)+2)<<16) | \ |
| 265 | (pcmcia_tuple_read_1((tuple), (idx4)+3)<<24)) |
| 266 | |
| 267 | #define pcmcia_tuple_read_n(tuple, n, idxn) \ |
| 268 | (((n)==1)?pcmcia_tuple_read_1((tuple), (idxn)) : \ |
| 269 | (((n)==2)?pcmcia_tuple_read_2((tuple), (idxn)) : \ |
| 270 | (((n)==3)?pcmcia_tuple_read_3((tuple), (idxn)) : \ |
| 271 | /* n == 4 */ pcmcia_tuple_read_4((tuple), (idxn))))) |
| 272 | |
| 273 | #define PCMCIA_SPACE_MEMORY 1 |
| 274 | #define PCMCIA_SPACE_IO 2 |
| 275 | |
| 276 | int pcmcia_ccr_read(struct pcmcia_function *, int); |
| 277 | void pcmcia_ccr_write(struct pcmcia_function *, int, int); |
| 278 | |
| 279 | #define pcmcia_mfc(sc) (! SIMPLEQ_EMPTY(&(sc)->card.pf_head) && \ |
| 280 | SIMPLEQ_NEXT(SIMPLEQ_FIRST(&(sc)->card.pf_head), pf_list)) |
| 281 | |
| 282 | void pcmcia_socket_enable(device_t); |
| 283 | void pcmcia_socket_disable(device_t); |
| 284 | void pcmcia_socket_settype(device_t, int); |
| 285 | |
| 286 | int pcmcia_config_alloc(struct pcmcia_function *, |
| 287 | struct pcmcia_config_entry *); |
| 288 | void pcmcia_config_free(struct pcmcia_function *); |
| 289 | int pcmcia_config_map(struct pcmcia_function *); |
| 290 | void pcmcia_config_unmap(struct pcmcia_function *); |
| 291 | |
| 292 | |
| 293 | int pcmcia_function_configure(struct pcmcia_function *, |
| 294 | int (*validator)(struct pcmcia_config_entry *)); |
| 295 | void pcmcia_function_unconfigure(struct pcmcia_function *); |
| 296 | void pcmcia_function_init(struct pcmcia_function *, |
| 297 | struct pcmcia_config_entry *); |
| 298 | int pcmcia_function_enable(struct pcmcia_function *); |
| 299 | void pcmcia_function_disable(struct pcmcia_function *); |
| 300 | |
| 301 | #define pcmcia_io_alloc(pf, start, size, align, pciop) \ |
| 302 | (pcmcia_chip_io_alloc((pf)->sc->pct, pf->sc->pch, (start), \ |
| 303 | (size), (align), (pciop))) |
| 304 | |
| 305 | #define pcmcia_io_free(pf, pciohp) \ |
| 306 | (pcmcia_chip_io_free((pf)->sc->pct, (pf)->sc->pch, (pciohp))) |
| 307 | |
| 308 | int pcmcia_io_map(struct pcmcia_function *, int, |
| 309 | struct pcmcia_io_handle *, int *); |
| 310 | void pcmcia_io_unmap(struct pcmcia_function *, int); |
| 311 | |
| 312 | void pcmcia_free_pf(struct pcmcia_function_head *); |
| 313 | |
| 314 | #define pcmcia_mem_alloc(pf, size, pcmhp) \ |
| 315 | (pcmcia_chip_mem_alloc((pf)->sc->pct, (pf)->sc->pch, (size), (pcmhp))) |
| 316 | |
| 317 | #define pcmcia_mem_free(pf, pcmhp) \ |
| 318 | (pcmcia_chip_mem_free((pf)->sc->pct, (pf)->sc->pch, (pcmhp))) |
| 319 | |
| 320 | #define pcmcia_mem_map(pf, kind, card_addr, size, pcmhp, offsetp, windowp) \ |
| 321 | (pcmcia_chip_mem_map((pf)->sc->pct, (pf)->sc->pch, (kind), \ |
| 322 | (card_addr), (size), (pcmhp), (offsetp), (windowp))) |
| 323 | |
| 324 | #define pcmcia_mem_unmap(pf, window) \ |
| 325 | (pcmcia_chip_mem_unmap((pf)->sc->pct, (pf)->sc->pch, (window))) |
| 326 | |
| 327 | void *pcmcia_intr_establish(struct pcmcia_function *, int, |
| 328 | int (*) (void *), void *); |
| 329 | void pcmcia_intr_disestablish(struct pcmcia_function *, void *); |
| 330 | |