1 1.7 thorpej /* $NetBSD: shpcmcia.c,v 1.7 2021/08/07 16:18:52 thorpej Exp $ */ 2 1.1 nonaka 3 1.1 nonaka /*- 4 1.3 nonaka * Copyright (C) 2009 NONAKA Kimihiro <nonaka (at) netbsd.org> 5 1.1 nonaka * All rights reserved. 6 1.1 nonaka * 7 1.1 nonaka * Redistribution and use in source and binary forms, with or without 8 1.1 nonaka * modification, are permitted provided that the following conditions 9 1.1 nonaka * are met: 10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 11 1.1 nonaka * notice, this list of conditions and the following disclaimer. 12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 14 1.1 nonaka * documentation and/or other materials provided with the distribution. 15 1.1 nonaka * 16 1.3 nonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.3 nonaka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.3 nonaka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.3 nonaka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.3 nonaka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.3 nonaka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.3 nonaka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.3 nonaka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.3 nonaka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.3 nonaka * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 nonaka */ 27 1.1 nonaka 28 1.1 nonaka #include <sys/cdefs.h> 29 1.7 thorpej __KERNEL_RCSID(0, "$NetBSD: shpcmcia.c,v 1.7 2021/08/07 16:18:52 thorpej Exp $"); 30 1.1 nonaka 31 1.1 nonaka #include <sys/types.h> 32 1.1 nonaka #include <sys/param.h> 33 1.1 nonaka #include <sys/systm.h> 34 1.1 nonaka #include <sys/device.h> 35 1.5 thorpej #include <sys/kmem.h> 36 1.1 nonaka #include <sys/kthread.h> 37 1.1 nonaka #include <sys/kernel.h> 38 1.1 nonaka #include <sys/callout.h> 39 1.1 nonaka #include <sys/bus.h> 40 1.1 nonaka #include <sys/intr.h> 41 1.1 nonaka 42 1.1 nonaka #include <dev/pcmcia/pcmciachip.h> 43 1.1 nonaka #include <dev/pcmcia/pcmciavar.h> 44 1.1 nonaka 45 1.1 nonaka #include <machine/autoconf.h> 46 1.1 nonaka 47 1.1 nonaka #include <sh3/devreg.h> 48 1.1 nonaka #include <sh3/bscreg.h> 49 1.1 nonaka #include <sh3/pfcreg.h> 50 1.1 nonaka 51 1.1 nonaka #include <evbsh3/ap_ms104_sh4/ap_ms104_sh4reg.h> 52 1.1 nonaka #include <evbsh3/ap_ms104_sh4/ap_ms104_sh4var.h> 53 1.1 nonaka 54 1.1 nonaka #ifdef SHPCMCIA_DEBUG 55 1.1 nonaka #define DPRINTF(s) printf s 56 1.1 nonaka #else 57 1.1 nonaka #define DPRINTF(s) 58 1.1 nonaka #endif 59 1.1 nonaka 60 1.1 nonaka static int shpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, 61 1.1 nonaka bus_size_t, struct pcmcia_mem_handle *); 62 1.1 nonaka static void shpcmcia_chip_mem_free(pcmcia_chipset_handle_t, 63 1.1 nonaka struct pcmcia_mem_handle *); 64 1.1 nonaka static int shpcmcia_chip_mem_map(pcmcia_chipset_handle_t, int, 65 1.1 nonaka bus_addr_t, bus_size_t, struct pcmcia_mem_handle *, 66 1.1 nonaka bus_size_t *, int *); 67 1.1 nonaka static void shpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int); 68 1.1 nonaka static int shpcmcia_chip_io_alloc(pcmcia_chipset_handle_t, 69 1.1 nonaka bus_addr_t, bus_size_t, bus_size_t, 70 1.1 nonaka struct pcmcia_io_handle *); 71 1.1 nonaka static void shpcmcia_chip_io_free(pcmcia_chipset_handle_t, 72 1.1 nonaka struct pcmcia_io_handle *); 73 1.1 nonaka static int shpcmcia_chip_io_map(pcmcia_chipset_handle_t, int, 74 1.1 nonaka bus_addr_t, bus_size_t, struct pcmcia_io_handle *, int *); 75 1.1 nonaka static void shpcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int); 76 1.1 nonaka static void *shpcmcia_chip_intr_establish(pcmcia_chipset_handle_t, 77 1.1 nonaka struct pcmcia_function *, int, int (*)(void *), void *); 78 1.1 nonaka static void shpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, 79 1.1 nonaka void *); 80 1.1 nonaka static void shpcmcia_chip_socket_enable(pcmcia_chipset_handle_t); 81 1.1 nonaka static void shpcmcia_chip_socket_disable(pcmcia_chipset_handle_t); 82 1.1 nonaka static void shpcmcia_chip_socket_settype(pcmcia_chipset_handle_t, 83 1.1 nonaka int); 84 1.1 nonaka 85 1.1 nonaka static struct pcmcia_chip_functions shpcmcia_chip_functions = { 86 1.1 nonaka /* memory space allocation */ 87 1.1 nonaka .mem_alloc = shpcmcia_chip_mem_alloc, 88 1.1 nonaka .mem_free = shpcmcia_chip_mem_free, 89 1.1 nonaka 90 1.1 nonaka /* memory space window mapping */ 91 1.1 nonaka .mem_map = shpcmcia_chip_mem_map, 92 1.1 nonaka .mem_unmap = shpcmcia_chip_mem_unmap, 93 1.1 nonaka 94 1.1 nonaka /* I/O space allocation */ 95 1.1 nonaka .io_alloc = shpcmcia_chip_io_alloc, 96 1.1 nonaka .io_free = shpcmcia_chip_io_free, 97 1.1 nonaka 98 1.1 nonaka /* I/O space window mapping */ 99 1.1 nonaka .io_map = shpcmcia_chip_io_map, 100 1.1 nonaka .io_unmap = shpcmcia_chip_io_unmap, 101 1.1 nonaka 102 1.1 nonaka /* interrupt glue */ 103 1.1 nonaka .intr_establish = shpcmcia_chip_intr_establish, 104 1.1 nonaka .intr_disestablish = shpcmcia_chip_intr_disestablish, 105 1.1 nonaka 106 1.1 nonaka /* card enable/disable */ 107 1.1 nonaka .socket_enable = shpcmcia_chip_socket_enable, 108 1.1 nonaka .socket_disable = shpcmcia_chip_socket_disable, 109 1.1 nonaka .socket_settype = shpcmcia_chip_socket_settype, 110 1.1 nonaka 111 1.1 nonaka /* card detection */ 112 1.1 nonaka .card_detect = NULL, 113 1.1 nonaka }; 114 1.1 nonaka 115 1.1 nonaka /* 116 1.1 nonaka * event thread 117 1.1 nonaka */ 118 1.1 nonaka struct shpcmcia_event { 119 1.1 nonaka SIMPLEQ_ENTRY(shpcmcia_event) pe_q; 120 1.1 nonaka int pe_type; 121 1.1 nonaka }; 122 1.1 nonaka 123 1.1 nonaka /* pe_type */ 124 1.1 nonaka #define SHPCMCIA_EVENT_INSERT 0 125 1.1 nonaka #define SHPCMCIA_EVENT_REMOVE 1 126 1.1 nonaka 127 1.1 nonaka struct shpcmcia_softc; 128 1.1 nonaka struct shpcmcia_handle { 129 1.1 nonaka struct shpcmcia_softc *sc; 130 1.1 nonaka 131 1.1 nonaka int flags; 132 1.1 nonaka #define SHPCMCIA_FLAG_SOCKETP 0x0001 133 1.1 nonaka #define SHPCMCIA_FLAG_CARDP 0x0002 134 1.1 nonaka int laststate; 135 1.1 nonaka #define SHPCMCIA_LASTSTATE_EMPTY 0x0000 136 1.1 nonaka #define SHPCMCIA_LASTSTATE_PRESENT 0x0002 137 1.1 nonaka 138 1.1 nonaka 139 1.1 nonaka int memalloc; 140 1.1 nonaka struct { 141 1.1 nonaka bus_addr_t addr; 142 1.1 nonaka bus_size_t size; 143 1.1 nonaka long offset; 144 1.1 nonaka int kind; 145 1.1 nonaka #define SHPCMCIA_MEM_WINS 5 146 1.1 nonaka } mem[SHPCMCIA_MEM_WINS]; 147 1.1 nonaka 148 1.1 nonaka int ioalloc; 149 1.1 nonaka struct { 150 1.1 nonaka bus_addr_t addr; 151 1.1 nonaka bus_size_t size; 152 1.1 nonaka int width; 153 1.1 nonaka #define SHPCMCIA_IO_WINS 2 154 1.1 nonaka } io[SHPCMCIA_IO_WINS]; 155 1.1 nonaka 156 1.4 chs device_t pcmcia; 157 1.1 nonaka 158 1.1 nonaka int shutdown; 159 1.1 nonaka lwp_t *event_thread; 160 1.1 nonaka SIMPLEQ_HEAD(, shpcmcia_event) events; 161 1.1 nonaka }; 162 1.1 nonaka 163 1.1 nonaka struct shpcmcia_softc { 164 1.1 nonaka device_t sc_dev; 165 1.1 nonaka 166 1.1 nonaka bus_space_tag_t sc_iot; 167 1.1 nonaka bus_space_handle_t sc_ioh; 168 1.1 nonaka bus_space_tag_t sc_memt; 169 1.1 nonaka bus_space_handle_t sc_memh; 170 1.1 nonaka bus_space_tag_t sc_attt; 171 1.1 nonaka bus_space_handle_t sc_atth; 172 1.1 nonaka 173 1.1 nonaka pcmcia_chipset_tag_t sc_pct; 174 1.1 nonaka 175 1.1 nonaka void *sc_ih; 176 1.1 nonaka #if 0 177 1.1 nonaka void *sc_detect_ih; 178 1.1 nonaka #else 179 1.1 nonaka callout_t sc_detect_ch; 180 1.1 nonaka #endif 181 1.1 nonaka 182 1.1 nonaka bus_addr_t sc_membase; 183 1.1 nonaka #define SHPCMCIA_MAX_MEM_PAGES (8 * sizeof(int)) 184 1.1 nonaka 185 1.1 nonaka bus_addr_t sc_iobase; 186 1.1 nonaka bus_size_t sc_iosize; 187 1.1 nonaka 188 1.1 nonaka #define SHPCMCIA_NSLOTS 1 189 1.1 nonaka struct shpcmcia_handle sc_handle[SHPCMCIA_NSLOTS]; 190 1.1 nonaka }; 191 1.1 nonaka 192 1.1 nonaka static int shpcmcia_probe(device_t, cfdata_t, void *); 193 1.1 nonaka static void shpcmcia_attach(device_t, device_t, void *); 194 1.1 nonaka static int shpcmcia_print(void *, const char *); 195 1.1 nonaka 196 1.1 nonaka CFATTACH_DECL_NEW(shpcmcia, sizeof(struct shpcmcia_softc), 197 1.1 nonaka shpcmcia_probe, shpcmcia_attach, NULL, NULL); 198 1.1 nonaka 199 1.1 nonaka #if 0 200 1.1 nonaka static int shpcmcia_card_detect_intr(void *arg); 201 1.1 nonaka #else 202 1.1 nonaka static void shpcmcia_card_detect_poll(void *arg); 203 1.1 nonaka #endif 204 1.1 nonaka 205 1.1 nonaka static void shpcmcia_init_socket(struct shpcmcia_handle *); 206 1.1 nonaka static void shpcmcia_attach_socket(struct shpcmcia_handle *); 207 1.1 nonaka static void shpcmcia_attach_sockets(struct shpcmcia_softc *); 208 1.1 nonaka 209 1.1 nonaka static void shpcmcia_event_thread(void *); 210 1.1 nonaka static void shpcmcia_queue_event(struct shpcmcia_handle *, int); 211 1.1 nonaka 212 1.1 nonaka static void shpcmcia_attach_card(struct shpcmcia_handle *); 213 1.1 nonaka static void shpcmcia_detach_card(struct shpcmcia_handle *, int ); 214 1.1 nonaka static void shpcmcia_deactivate_card(struct shpcmcia_handle *); 215 1.1 nonaka 216 1.1 nonaka static int 217 1.1 nonaka shpcmcia_probe(device_t parent, cfdata_t cfp, void *aux) 218 1.1 nonaka { 219 1.1 nonaka struct mainbus_attach_args *maa = aux; 220 1.1 nonaka 221 1.1 nonaka if (strcmp(maa->ma_name, "shpcmcia") != 0) 222 1.1 nonaka return 0; 223 1.1 nonaka return 1; 224 1.1 nonaka } 225 1.1 nonaka 226 1.1 nonaka static void 227 1.1 nonaka shpcmcia_attach(device_t parent, device_t self, void *aux) 228 1.1 nonaka { 229 1.1 nonaka struct shpcmcia_softc *sc = device_private(self); 230 1.1 nonaka #if 0 231 1.1 nonaka uint32_t reg; 232 1.1 nonaka #endif 233 1.1 nonaka 234 1.1 nonaka sc->sc_dev = self; 235 1.1 nonaka 236 1.1 nonaka aprint_naive("\n"); 237 1.1 nonaka aprint_normal("\n"); 238 1.1 nonaka 239 1.1 nonaka #if 0 240 1.1 nonaka /* setup bus controller */ 241 1.1 nonaka /* max wait */ 242 1.1 nonaka reg = _reg_read_4(SH4_WCR1); 243 1.1 nonaka reg |= 0x00700000; 244 1.1 nonaka _reg_write_4(SH4_WCR1, reg); 245 1.1 nonaka reg = _reg_read_4(SH4_WCR2); 246 1.1 nonaka reg |= 0xfff00000; 247 1.1 nonaka _reg_write_4(SH4_WCR2, reg); 248 1.1 nonaka reg = _reg_read_4(SH4_WCR3); 249 1.1 nonaka reg |= 0x07700000; 250 1.1 nonaka _reg_write_4(SH4_WCR3, reg); 251 1.1 nonaka reg = _reg_read_4(SH4_PCR); 252 1.1 nonaka reg |= 0xffffffff; 253 1.1 nonaka _reg_write_4(SH4_PCR, reg); 254 1.1 nonaka #endif 255 1.1 nonaka 256 1.1 nonaka sc->sc_pct = (pcmcia_chipset_tag_t)&shpcmcia_chip_functions; 257 1.1 nonaka sc->sc_iot = &ap_ms104_sh4_bus_io; 258 1.1 nonaka sc->sc_memt = &ap_ms104_sh4_bus_mem; 259 1.1 nonaka sc->sc_attt = &ap_ms104_sh4_bus_att; 260 1.1 nonaka 261 1.1 nonaka if (bus_space_map(sc->sc_attt, 0x14000000, 4 * 1024, 0, &sc->sc_atth)) 262 1.1 nonaka panic("%s: couldn't map attribute\n", device_xname(sc->sc_dev)); 263 1.1 nonaka if (bus_space_map(sc->sc_iot, 0x15000000, 64 * 1024, 0, 264 1.1 nonaka &sc->sc_ioh)) 265 1.1 nonaka panic("%s: couldn't map io memory\n", device_xname(sc->sc_dev)); 266 1.1 nonaka if (bus_space_map(sc->sc_memt, 0x16000000, 32 * 1024 * 1024, 0, 267 1.1 nonaka &sc->sc_memh)) 268 1.1 nonaka panic("%s: couldn't map memory\n", device_xname(sc->sc_dev)); 269 1.1 nonaka 270 1.1 nonaka sc->sc_iobase = sc->sc_ioh; 271 1.1 nonaka sc->sc_iosize = 64 * 1024; 272 1.1 nonaka sc->sc_membase = sc->sc_memh; 273 1.1 nonaka 274 1.1 nonaka sc->sc_handle[0].sc = sc; 275 1.1 nonaka sc->sc_handle[0].flags = SHPCMCIA_FLAG_SOCKETP; 276 1.1 nonaka sc->sc_handle[0].laststate = SHPCMCIA_LASTSTATE_EMPTY; 277 1.1 nonaka SIMPLEQ_INIT(&sc->sc_handle[0].events); 278 1.1 nonaka 279 1.1 nonaka #if 0 280 1.1 nonaka sc->sc_detect_ih = gpio_intr_establish(GPIO_PIN_CARD_CD, 281 1.1 nonaka shpcmcia_card_detect_intr, sc); 282 1.1 nonaka if (sc->sc_detect_ih == NULL) { 283 1.1 nonaka aprint_error_dev(self, "couldn't establish detect interrupt\n"); 284 1.1 nonaka } 285 1.1 nonaka #else 286 1.1 nonaka callout_init(&sc->sc_detect_ch, 0); 287 1.1 nonaka callout_reset(&sc->sc_detect_ch, hz, shpcmcia_card_detect_poll, sc); 288 1.1 nonaka #endif 289 1.1 nonaka 290 1.1 nonaka shpcmcia_attach_sockets(sc); 291 1.1 nonaka } 292 1.1 nonaka 293 1.1 nonaka static void 294 1.1 nonaka shpcmcia_attach_sockets(struct shpcmcia_softc *sc) 295 1.1 nonaka { 296 1.1 nonaka 297 1.1 nonaka shpcmcia_attach_socket(&sc->sc_handle[0]); 298 1.1 nonaka } 299 1.1 nonaka 300 1.1 nonaka static void 301 1.1 nonaka shpcmcia_attach_socket(struct shpcmcia_handle *h) 302 1.1 nonaka { 303 1.1 nonaka struct pcmciabus_attach_args paa; 304 1.1 nonaka 305 1.1 nonaka /* initialize the rest of the handle */ 306 1.1 nonaka h->shutdown = 0; 307 1.1 nonaka h->memalloc = 0; 308 1.1 nonaka h->ioalloc = 0; 309 1.1 nonaka 310 1.1 nonaka /* now, config one pcmcia device per socket */ 311 1.1 nonaka paa.paa_busname = "pcmcia"; 312 1.1 nonaka paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct; 313 1.1 nonaka paa.pch = (pcmcia_chipset_handle_t)h; 314 1.1 nonaka 315 1.6 thorpej h->pcmcia = 316 1.7 thorpej config_found(h->sc->sc_dev, &paa, shpcmcia_print, CFARGS_NONE); 317 1.1 nonaka 318 1.1 nonaka /* if there's actually a pcmcia device attached, initialize the slot */ 319 1.1 nonaka if (h->pcmcia) 320 1.1 nonaka shpcmcia_init_socket(h); 321 1.1 nonaka } 322 1.1 nonaka 323 1.1 nonaka /*ARGSUSED*/ 324 1.1 nonaka static int 325 1.1 nonaka shpcmcia_print(void *arg, const char *pnp) 326 1.1 nonaka { 327 1.1 nonaka 328 1.1 nonaka if (pnp) 329 1.1 nonaka aprint_normal("pcmcia at %s", pnp); 330 1.1 nonaka return UNCONF; 331 1.1 nonaka } 332 1.1 nonaka 333 1.1 nonaka static void 334 1.1 nonaka shpcmcia_init_socket(struct shpcmcia_handle *h) 335 1.1 nonaka { 336 1.1 nonaka uint16_t reg; 337 1.1 nonaka 338 1.1 nonaka /* 339 1.1 nonaka * queue creation of a kernel thread to handle insert/removal events. 340 1.1 nonaka */ 341 1.1 nonaka #ifdef DIAGNOSTIC 342 1.1 nonaka if (h->event_thread != NULL) 343 1.1 nonaka panic("shpcmcia_attach_socket: event thread"); 344 1.1 nonaka #endif 345 1.1 nonaka 346 1.1 nonaka /* if there's a card there, then attach it. */ 347 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 348 1.1 nonaka if (!(reg & (1 << GPIO_PIN_CARD_CD))) { 349 1.1 nonaka shpcmcia_attach_card(h); 350 1.1 nonaka h->laststate = SHPCMCIA_LASTSTATE_PRESENT; 351 1.1 nonaka } else { 352 1.1 nonaka h->laststate = SHPCMCIA_LASTSTATE_EMPTY; 353 1.1 nonaka } 354 1.1 nonaka 355 1.1 nonaka if (kthread_create(PRI_NONE, 0, NULL, shpcmcia_event_thread, h, 356 1.1 nonaka &h->event_thread, "%s", device_xname(h->sc->sc_dev))) { 357 1.1 nonaka aprint_error_dev(h->sc->sc_dev, 358 1.1 nonaka "unable to create event thread\n"); 359 1.1 nonaka panic("shpcmcia_create_event_thread"); 360 1.1 nonaka } 361 1.1 nonaka } 362 1.1 nonaka 363 1.1 nonaka /* 364 1.1 nonaka * event thread 365 1.1 nonaka */ 366 1.1 nonaka static void 367 1.1 nonaka shpcmcia_event_thread(void *arg) 368 1.1 nonaka { 369 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)arg; 370 1.1 nonaka struct shpcmcia_event *pe; 371 1.1 nonaka int s; 372 1.1 nonaka 373 1.1 nonaka while (h->shutdown == 0) { 374 1.1 nonaka s = splhigh(); 375 1.1 nonaka if ((pe = SIMPLEQ_FIRST(&h->events)) == NULL) { 376 1.1 nonaka splx(s); 377 1.1 nonaka (void) tsleep(&h->events, PWAIT, "waitev", 0); 378 1.1 nonaka continue; 379 1.1 nonaka } else { 380 1.1 nonaka splx(s); 381 1.1 nonaka /* sleep .25s to be enqueued chatterling interrupts */ 382 1.1 nonaka (void) tsleep((void *)shpcmcia_event_thread, 383 1.1 nonaka PWAIT, "waitss", hz / 4); 384 1.1 nonaka } 385 1.1 nonaka s = splhigh(); 386 1.1 nonaka SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 387 1.1 nonaka splx(s); 388 1.1 nonaka 389 1.1 nonaka switch (pe->pe_type) { 390 1.1 nonaka case SHPCMCIA_EVENT_INSERT: 391 1.1 nonaka s = splhigh(); 392 1.1 nonaka for (;;) { 393 1.1 nonaka struct shpcmcia_event *pe1, *pe2; 394 1.1 nonaka 395 1.1 nonaka if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) 396 1.1 nonaka break; 397 1.1 nonaka if (pe1->pe_type != SHPCMCIA_EVENT_REMOVE) 398 1.1 nonaka break; 399 1.1 nonaka if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) 400 1.1 nonaka break; 401 1.1 nonaka if (pe2->pe_type == SHPCMCIA_EVENT_INSERT) { 402 1.1 nonaka SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 403 1.5 thorpej kmem_free(pe1, sizeof(*pe1)); 404 1.1 nonaka SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 405 1.5 thorpej kmem_free(pe2, sizeof(*pe2)); 406 1.1 nonaka } 407 1.1 nonaka } 408 1.1 nonaka splx(s); 409 1.1 nonaka 410 1.1 nonaka DPRINTF(("%s: insertion event\n", 411 1.1 nonaka device_xname(h->sc->sc_dev))); 412 1.1 nonaka shpcmcia_attach_card(h); 413 1.1 nonaka break; 414 1.1 nonaka 415 1.1 nonaka case SHPCMCIA_EVENT_REMOVE: 416 1.1 nonaka s = splhigh(); 417 1.1 nonaka for (;;) { 418 1.1 nonaka struct shpcmcia_event *pe1, *pe2; 419 1.1 nonaka 420 1.1 nonaka if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) 421 1.1 nonaka break; 422 1.1 nonaka if (pe1->pe_type != SHPCMCIA_EVENT_INSERT) 423 1.1 nonaka break; 424 1.1 nonaka if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) 425 1.1 nonaka break; 426 1.1 nonaka if (pe2->pe_type == SHPCMCIA_EVENT_REMOVE) { 427 1.1 nonaka SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 428 1.5 thorpej kmem_free(pe1, sizeof(*pe1)); 429 1.1 nonaka SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 430 1.5 thorpej kmem_free(pe2, sizeof(*pe2)); 431 1.1 nonaka } 432 1.1 nonaka } 433 1.1 nonaka splx(s); 434 1.1 nonaka 435 1.1 nonaka DPRINTF(("%s: removal event\n", 436 1.1 nonaka device_xname(h->sc->sc_dev))); 437 1.1 nonaka shpcmcia_detach_card(h, DETACH_FORCE); 438 1.1 nonaka break; 439 1.1 nonaka 440 1.1 nonaka default: 441 1.1 nonaka panic("shpcmcia_event_thread: unknown event %d", 442 1.1 nonaka pe->pe_type); 443 1.1 nonaka } 444 1.5 thorpej kmem_free(pe, sizeof(*pe)); 445 1.1 nonaka } 446 1.1 nonaka 447 1.1 nonaka h->event_thread = NULL; 448 1.1 nonaka 449 1.1 nonaka /* In case parent is waiting for us to exit. */ 450 1.1 nonaka wakeup(h->sc); 451 1.1 nonaka 452 1.1 nonaka kthread_exit(0); 453 1.1 nonaka } 454 1.1 nonaka 455 1.1 nonaka static void 456 1.1 nonaka shpcmcia_queue_event(struct shpcmcia_handle *h, int event) 457 1.1 nonaka { 458 1.1 nonaka struct shpcmcia_event *pe; 459 1.1 nonaka int s; 460 1.1 nonaka 461 1.5 thorpej pe = kmem_intr_alloc(sizeof(*pe), KM_NOSLEEP); 462 1.1 nonaka if (pe == NULL) 463 1.1 nonaka panic("shpcmcia_queue_event: can't allocate event"); 464 1.1 nonaka 465 1.1 nonaka pe->pe_type = event; 466 1.1 nonaka s = splhigh(); 467 1.1 nonaka SIMPLEQ_INSERT_TAIL(&h->events, pe, pe_q); 468 1.1 nonaka splx(s); 469 1.1 nonaka wakeup(&h->events); 470 1.1 nonaka } 471 1.1 nonaka 472 1.1 nonaka static void 473 1.1 nonaka shpcmcia_attach_card(struct shpcmcia_handle *h) 474 1.1 nonaka { 475 1.1 nonaka 476 1.1 nonaka DPRINTF(("%s\n", __func__)); 477 1.1 nonaka 478 1.1 nonaka if (!(h->flags & SHPCMCIA_FLAG_CARDP)) { 479 1.1 nonaka /* call the MI attach function */ 480 1.1 nonaka pcmcia_card_attach(h->pcmcia); 481 1.1 nonaka 482 1.1 nonaka h->flags |= SHPCMCIA_FLAG_CARDP; 483 1.1 nonaka } else { 484 1.1 nonaka DPRINTF(("shpcmcia_attach_card: already attached")); 485 1.1 nonaka } 486 1.1 nonaka } 487 1.1 nonaka 488 1.1 nonaka static void 489 1.1 nonaka shpcmcia_detach_card(struct shpcmcia_handle *h, int flags) 490 1.1 nonaka { 491 1.1 nonaka 492 1.1 nonaka DPRINTF(("%s\n", __func__)); 493 1.1 nonaka 494 1.1 nonaka if (h->flags & SHPCMCIA_FLAG_CARDP) { 495 1.1 nonaka h->flags &= ~SHPCMCIA_FLAG_CARDP; 496 1.1 nonaka 497 1.1 nonaka /* call the MI detach function */ 498 1.1 nonaka pcmcia_card_detach(h->pcmcia, flags); 499 1.1 nonaka } else { 500 1.1 nonaka DPRINTF(("shpcmcia_detach_card: already detached")); 501 1.1 nonaka } 502 1.1 nonaka } 503 1.1 nonaka 504 1.1 nonaka static void 505 1.1 nonaka shpcmcia_deactivate_card(struct shpcmcia_handle *h) 506 1.1 nonaka { 507 1.1 nonaka 508 1.1 nonaka DPRINTF(("%s\n", __func__)); 509 1.1 nonaka 510 1.1 nonaka /* call the MI deactivate function */ 511 1.1 nonaka pcmcia_card_deactivate(h->pcmcia); 512 1.1 nonaka 513 1.1 nonaka shpcmcia_chip_socket_disable(h); 514 1.1 nonaka } 515 1.1 nonaka 516 1.1 nonaka #if 0 517 1.1 nonaka /* 518 1.1 nonaka * interrupt 519 1.1 nonaka */ 520 1.1 nonaka static int 521 1.1 nonaka shpcmcia_card_detect_intr(void *arg) 522 1.1 nonaka { 523 1.1 nonaka struct shpcmcia_softc *sc = (struct shpcmcia_softc *)arg; 524 1.1 nonaka struct shpcmcia_handle *h = &sc->sc_handle[0]; 525 1.1 nonaka uint16_t reg; 526 1.1 nonaka 527 1.1 nonaka DPRINTF(("%s\n", __func__)); 528 1.1 nonaka 529 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 530 1.1 nonaka if (reg & (1 << GPIO_PIN_CARD_CD)) { 531 1.1 nonaka /* remove */ 532 1.1 nonaka if (h->laststate == SHPCMCIA_LASTSTATE_PRESENT) { 533 1.1 nonaka /* Deactivate the card now. */ 534 1.1 nonaka shpcmcia_deactivate_card(h); 535 1.1 nonaka shpcmcia_queue_event(h, SHPCMCIA_EVENT_REMOVE); 536 1.1 nonaka } 537 1.1 nonaka h->laststate = SHPCMCIA_LASTSTATE_EMPTY; 538 1.1 nonaka } else { 539 1.1 nonaka /* insert */ 540 1.1 nonaka if (h->laststate != SHPCMCIA_LASTSTATE_PRESENT) { 541 1.1 nonaka shpcmcia_queue_event(h, SHPCMCIA_EVENT_INSERT); 542 1.1 nonaka } 543 1.1 nonaka h->laststate = SHPCMCIA_LASTSTATE_PRESENT; 544 1.1 nonaka } 545 1.1 nonaka return 1; 546 1.1 nonaka } 547 1.1 nonaka #else 548 1.1 nonaka /* 549 1.1 nonaka * card polling 550 1.1 nonaka */ 551 1.1 nonaka static void 552 1.1 nonaka shpcmcia_card_detect_poll(void *arg) 553 1.1 nonaka { 554 1.1 nonaka struct shpcmcia_softc *sc = (struct shpcmcia_softc *)arg; 555 1.1 nonaka struct shpcmcia_handle *h = &sc->sc_handle[0]; 556 1.1 nonaka uint16_t reg; 557 1.1 nonaka 558 1.1 nonaka DPRINTF(("%s\n", __func__)); 559 1.1 nonaka 560 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 561 1.1 nonaka if (reg & (1 << GPIO_PIN_CARD_CD)) { 562 1.1 nonaka /* remove */ 563 1.1 nonaka if (h->laststate == SHPCMCIA_LASTSTATE_PRESENT) { 564 1.1 nonaka /* Deactivate the card now. */ 565 1.1 nonaka shpcmcia_deactivate_card(h); 566 1.1 nonaka shpcmcia_queue_event(h, SHPCMCIA_EVENT_REMOVE); 567 1.1 nonaka } 568 1.1 nonaka h->laststate = SHPCMCIA_LASTSTATE_EMPTY; 569 1.1 nonaka } else { 570 1.1 nonaka /* insert */ 571 1.1 nonaka if (h->laststate != SHPCMCIA_LASTSTATE_PRESENT) { 572 1.1 nonaka shpcmcia_queue_event(h, SHPCMCIA_EVENT_INSERT); 573 1.1 nonaka } 574 1.1 nonaka h->laststate = SHPCMCIA_LASTSTATE_PRESENT; 575 1.1 nonaka } 576 1.1 nonaka 577 1.1 nonaka callout_schedule(&sc->sc_detect_ch, hz); 578 1.1 nonaka } 579 1.1 nonaka #endif 580 1.1 nonaka 581 1.1 nonaka /* 582 1.1 nonaka * pcmcia chip functions 583 1.1 nonaka */ 584 1.1 nonaka /* Memory space functions. */ 585 1.1 nonaka static int 586 1.1 nonaka shpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 587 1.1 nonaka struct pcmcia_mem_handle *pmhp) 588 1.1 nonaka { 589 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 590 1.1 nonaka struct shpcmcia_softc *sc = h->sc; 591 1.1 nonaka 592 1.1 nonaka DPRINTF(("%s: size=%d\n", __func__, (unsigned)size)); 593 1.1 nonaka 594 1.1 nonaka memset(pmhp, 0, sizeof(*pmhp)); 595 1.1 nonaka pmhp->memt = sc->sc_memt; 596 1.1 nonaka pmhp->memh = sc->sc_memh; 597 1.1 nonaka pmhp->addr = 0; 598 1.1 nonaka pmhp->size = size; 599 1.1 nonaka pmhp->realsize = size; 600 1.1 nonaka 601 1.1 nonaka return 0; 602 1.1 nonaka } 603 1.1 nonaka 604 1.1 nonaka /*ARGSUSED*/ 605 1.1 nonaka static void 606 1.1 nonaka shpcmcia_chip_mem_free(pcmcia_chipset_handle_t pch, 607 1.1 nonaka struct pcmcia_mem_handle *pmhp) 608 1.1 nonaka { 609 1.1 nonaka 610 1.1 nonaka DPRINTF(("%s\n", __func__)); 611 1.1 nonaka } 612 1.1 nonaka 613 1.1 nonaka static int 614 1.1 nonaka shpcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind, 615 1.1 nonaka bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pmhp, 616 1.1 nonaka bus_size_t *offsetp, int *windowp) 617 1.1 nonaka { 618 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 619 1.1 nonaka struct shpcmcia_softc *sc = h->sc; 620 1.1 nonaka int win; 621 1.1 nonaka int i; 622 1.1 nonaka int s; 623 1.1 nonaka 624 1.1 nonaka DPRINTF(("%s: kind=%#x, card_addr=%#x, size=%d\n", 625 1.1 nonaka __func__, kind, (unsigned)card_addr, (unsigned)size)); 626 1.1 nonaka 627 1.1 nonaka s = splbio(); 628 1.1 nonaka win = -1; 629 1.1 nonaka for (i = 0; i < SHPCMCIA_MEM_WINS; i++) { 630 1.1 nonaka if ((h->memalloc & (1 << i)) == 0) { 631 1.1 nonaka win = i; 632 1.1 nonaka h->memalloc |= (1 << i); 633 1.1 nonaka break; 634 1.1 nonaka } 635 1.1 nonaka } 636 1.1 nonaka splx(s); 637 1.1 nonaka if (win == -1) 638 1.1 nonaka return 1; 639 1.1 nonaka 640 1.1 nonaka *windowp = win; 641 1.1 nonaka *offsetp = 0; 642 1.1 nonaka 643 1.1 nonaka h->mem[win].addr = pmhp->addr; 644 1.1 nonaka h->mem[win].size = size; 645 1.1 nonaka h->mem[win].offset = (((long)card_addr) - ((long)pmhp->addr)); 646 1.1 nonaka h->mem[win].kind = kind; 647 1.1 nonaka 648 1.1 nonaka switch (kind) { 649 1.1 nonaka case PCMCIA_MEM_ATTR: 650 1.1 nonaka DPRINTF(("%s:PCMCIA_MEM_ATTR\n",device_xname(sc->sc_dev))); 651 1.1 nonaka pmhp->memh = sc->sc_atth + card_addr; 652 1.1 nonaka break; 653 1.1 nonaka 654 1.1 nonaka default: 655 1.1 nonaka pmhp->memh = sc->sc_memh + card_addr; 656 1.1 nonaka break; 657 1.1 nonaka } 658 1.1 nonaka 659 1.1 nonaka return 0; 660 1.1 nonaka } 661 1.1 nonaka 662 1.1 nonaka /*ARGSUSED*/ 663 1.1 nonaka static void 664 1.1 nonaka shpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window) 665 1.1 nonaka { 666 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 667 1.1 nonaka int s; 668 1.1 nonaka 669 1.1 nonaka DPRINTF(("%s\n", __func__)); 670 1.1 nonaka 671 1.1 nonaka s = splbio(); 672 1.1 nonaka h->memalloc &= ~(1 << window); 673 1.1 nonaka splx(s); 674 1.1 nonaka } 675 1.1 nonaka 676 1.1 nonaka /* I/O space functions. */ 677 1.1 nonaka static int 678 1.1 nonaka shpcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, 679 1.1 nonaka bus_addr_t start, bus_size_t size, bus_size_t align, 680 1.1 nonaka struct pcmcia_io_handle *pihp) 681 1.1 nonaka { 682 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 683 1.1 nonaka struct shpcmcia_softc *sc = h->sc; 684 1.1 nonaka 685 1.1 nonaka DPRINTF(("%s\n", __func__)); 686 1.1 nonaka 687 1.1 nonaka memset(pihp, 0, sizeof(*pihp)); 688 1.1 nonaka pihp->iot = sc->sc_iot; 689 1.1 nonaka pihp->ioh = sc->sc_ioh; 690 1.1 nonaka pihp->addr = start; 691 1.1 nonaka pihp->size = size; 692 1.1 nonaka pihp->flags |= PCMCIA_IO_ALLOCATED; 693 1.1 nonaka 694 1.1 nonaka return 0; 695 1.1 nonaka } 696 1.1 nonaka 697 1.1 nonaka /*ARGSUSED*/ 698 1.1 nonaka static void 699 1.1 nonaka shpcmcia_chip_io_free(pcmcia_chipset_handle_t pch, 700 1.1 nonaka struct pcmcia_io_handle *pih) 701 1.1 nonaka { 702 1.1 nonaka 703 1.1 nonaka DPRINTF(("%s\n", __func__)); 704 1.1 nonaka } 705 1.1 nonaka 706 1.1 nonaka /*ARGSUSED*/ 707 1.1 nonaka static int 708 1.1 nonaka shpcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width, 709 1.1 nonaka bus_addr_t card_addr, bus_size_t size, struct pcmcia_io_handle *pihp, 710 1.1 nonaka int *windowp) 711 1.1 nonaka { 712 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 713 1.1 nonaka struct shpcmcia_softc *sc = h->sc; 714 1.1 nonaka bus_addr_t ioaddr = pihp->addr + card_addr; 715 1.1 nonaka int win; 716 1.1 nonaka int i; 717 1.1 nonaka int s; 718 1.1 nonaka 719 1.1 nonaka DPRINTF(("%s\n", __func__)); 720 1.1 nonaka 721 1.1 nonaka s = splbio(); 722 1.1 nonaka win = -1; 723 1.1 nonaka for (i = 0; i < SHPCMCIA_IO_WINS; i++) { 724 1.1 nonaka if ((h->ioalloc & (1 << i)) == 0) { 725 1.1 nonaka win = i; 726 1.1 nonaka h->ioalloc |= (1 << i); 727 1.1 nonaka break; 728 1.1 nonaka } 729 1.1 nonaka } 730 1.1 nonaka splx(s); 731 1.1 nonaka if (win == -1) 732 1.1 nonaka return 1; 733 1.1 nonaka 734 1.1 nonaka *windowp = win; 735 1.1 nonaka 736 1.1 nonaka /* XXX: IOS16 */ 737 1.1 nonaka 738 1.1 nonaka aprint_normal_dev(sc->sc_dev, "port 0x%0lx", (u_long)ioaddr); 739 1.1 nonaka if (size > 1) 740 1.1 nonaka aprint_normal("-0x%lx", (u_long) ioaddr + (u_long) size - 1); 741 1.1 nonaka aprint_normal("\n"); 742 1.1 nonaka 743 1.1 nonaka h->io[win].addr = ioaddr; 744 1.1 nonaka h->io[win].size = size; 745 1.1 nonaka h->io[win].width = width; 746 1.1 nonaka 747 1.1 nonaka return 0; 748 1.1 nonaka } 749 1.1 nonaka 750 1.1 nonaka /*ARGSUSED*/ 751 1.1 nonaka static void 752 1.1 nonaka shpcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window) 753 1.1 nonaka { 754 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 755 1.1 nonaka int s; 756 1.1 nonaka 757 1.1 nonaka DPRINTF(("%s\n", __func__)); 758 1.1 nonaka 759 1.1 nonaka s = splbio(); 760 1.1 nonaka h->ioalloc &= ~(1 << window); 761 1.1 nonaka splx(s); 762 1.1 nonaka } 763 1.1 nonaka 764 1.1 nonaka /* Interrupt functions. */ 765 1.1 nonaka static void * 766 1.1 nonaka shpcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch, 767 1.1 nonaka struct pcmcia_function *pf, int ipl, int (*ih_func)(void *), void *ih_arg) 768 1.1 nonaka { 769 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 770 1.1 nonaka struct shpcmcia_softc *sc = h->sc; 771 1.1 nonaka int s; 772 1.1 nonaka 773 1.1 nonaka KASSERT(sc->sc_ih == NULL); 774 1.1 nonaka DPRINTF(("%s\n", __func__)); 775 1.1 nonaka 776 1.1 nonaka s = splhigh(); 777 1.1 nonaka sc->sc_ih = extintr_establish(EXTINTR_INTR_CFIREQ, IST_LEVEL, ipl, 778 1.1 nonaka ih_func, ih_arg); 779 1.1 nonaka if (sc->sc_ih == NULL) { 780 1.1 nonaka aprint_error_dev(sc->sc_dev, 781 1.1 nonaka "couldn't establish card interrupt\n"); 782 1.1 nonaka } 783 1.1 nonaka splx(s); 784 1.1 nonaka 785 1.1 nonaka return sc->sc_ih; 786 1.1 nonaka } 787 1.1 nonaka 788 1.1 nonaka static void 789 1.1 nonaka shpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *cookie) 790 1.1 nonaka { 791 1.1 nonaka struct shpcmcia_handle *h = (struct shpcmcia_handle *)pch; 792 1.1 nonaka struct shpcmcia_softc *sc = h->sc; 793 1.1 nonaka int s; 794 1.1 nonaka 795 1.1 nonaka KASSERT(sc->sc_ih != NULL); 796 1.1 nonaka DPRINTF(("%s\n", __func__)); 797 1.1 nonaka 798 1.1 nonaka s = splhigh(); 799 1.1 nonaka extintr_disestablish(sc->sc_ih); 800 1.1 nonaka sc->sc_ih = NULL; 801 1.1 nonaka splx(s); 802 1.1 nonaka } 803 1.1 nonaka 804 1.1 nonaka /* Socket functions. */ 805 1.1 nonaka static void 806 1.1 nonaka shpcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch) 807 1.1 nonaka { 808 1.1 nonaka uint16_t reg; 809 1.1 nonaka 810 1.1 nonaka DPRINTF(("%s\n", __func__)); 811 1.1 nonaka 812 1.1 nonaka /* power on the card */ 813 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 814 1.1 nonaka reg &= ~(1 << GPIO_PIN_CARD_PON); 815 1.1 nonaka _reg_write_2(SH4_PDTRA, reg); 816 1.1 nonaka 817 1.1 nonaka /* wait for card ready */ 818 1.1 nonaka while (_reg_read_1(EXTINTR_STAT1) & MASK1_INT12) 819 1.1 nonaka continue; 820 1.1 nonaka 821 1.1 nonaka /* enable bus buffer */ 822 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 823 1.1 nonaka reg &= ~(1 << GPIO_PIN_CARD_ENABLE); 824 1.1 nonaka _reg_write_2(SH4_PDTRA, reg); 825 1.1 nonaka 826 1.1 nonaka /* reset the card */ 827 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 828 1.1 nonaka reg &= ~(1 << GPIO_PIN_CARD_RESET); 829 1.1 nonaka _reg_write_2(SH4_PDTRA, reg); 830 1.1 nonaka delay(100 * 1000); 831 1.1 nonaka } 832 1.1 nonaka 833 1.1 nonaka /*ARGSUSED*/ 834 1.1 nonaka static void 835 1.1 nonaka shpcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch) 836 1.1 nonaka { 837 1.1 nonaka uint16_t reg; 838 1.1 nonaka 839 1.1 nonaka DPRINTF(("%s\n", __func__)); 840 1.1 nonaka 841 1.1 nonaka /* reset the card */ 842 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 843 1.1 nonaka reg |= (1 << GPIO_PIN_CARD_RESET); 844 1.1 nonaka _reg_write_2(SH4_PDTRA, reg); 845 1.1 nonaka 846 1.1 nonaka /* power off the card */ 847 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 848 1.1 nonaka reg |= (1 << GPIO_PIN_CARD_PON); 849 1.1 nonaka _reg_write_2(SH4_PDTRA, reg); 850 1.1 nonaka 851 1.1 nonaka /* disable bus buffer */ 852 1.1 nonaka reg = _reg_read_2(SH4_PDTRA); 853 1.1 nonaka reg |= (1 << GPIO_PIN_CARD_ENABLE); 854 1.1 nonaka _reg_write_2(SH4_PDTRA, reg); 855 1.1 nonaka } 856 1.1 nonaka 857 1.1 nonaka /*ARGSUSED*/ 858 1.1 nonaka static void 859 1.1 nonaka shpcmcia_chip_socket_settype(pcmcia_chipset_handle_t pch, int type) 860 1.1 nonaka { 861 1.1 nonaka 862 1.1 nonaka DPRINTF(("%s\n", __func__)); 863 1.1 nonaka } 864