1/* $NetBSD: mmeyepcmcia.c,v 1.27 2024/02/13 21:39:02 andvar 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/* 33 * PCMCIA I/F for MMEYE 34 * 35 * T.Horiuichi 36 * Brains Corp. 1998.8.25 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: mmeyepcmcia.c,v 1.27 2024/02/13 21:39:02 andvar Exp $"); 41 42#include <sys/types.h> 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/kernel.h> 46#include <sys/proc.h> 47#include <sys/device.h> 48#include <sys/extent.h> 49#include <sys/kmem.h> 50#include <sys/kthread.h> 51#include <sys/bus.h> 52 53#include <uvm/uvm_extern.h> 54 55#include <machine/autoconf.h> 56#include <machine/intr.h> 57#include <machine/mmeye.h> 58 59#include <dev/pcmcia/pcmciareg.h> 60#include <dev/pcmcia/pcmciavar.h> 61#include <dev/pcmcia/pcmciachip.h> 62 63#include <mmeye/dev/mmeyepcmciareg.h> 64 65#include "locators.h" 66 67#ifdef MMEYEPCMCIADEBUG 68int mmeyepcmcia_debug = 1; 69#define DPRINTF(arg) if (mmeyepcmcia_debug) printf arg; 70#else 71#define DPRINTF(arg) 72#endif 73 74struct mmeyepcmcia_event { 75 SIMPLEQ_ENTRY(mmeyepcmcia_event) pe_q; 76 int pe_type; 77}; 78 79/* pe_type */ 80#define MMEYEPCMCIA_EVENT_INSERTION 0 81#define MMEYEPCMCIA_EVENT_REMOVAL 1 82 83struct mmeyepcmcia_handle { 84 struct mmeyepcmcia_softc *sc; 85 int flags; 86 int laststate; 87 int memalloc; 88 struct { 89 bus_addr_t addr; 90 bus_size_t size; 91 int kind; 92 bus_space_tag_t memt; 93 bus_space_handle_t memh; 94 } mem[MMEYEPCMCIA_MEM_WINS]; 95 int ioalloc; 96 struct { 97 bus_addr_t addr; 98 bus_size_t size; 99 int width; 100 bus_space_tag_t iot; 101 bus_space_handle_t ioh; 102 } io[MMEYEPCMCIA_IO_WINS]; 103 int ih_irq; 104 device_t pcmcia; 105 106 int shutdown; 107 lwp_t *event_thread; 108 SIMPLEQ_HEAD(, mmeyepcmcia_event) events; 109}; 110 111#define MMEYEPCMCIA_FLAG_CARDP 0x0002 112#define MMEYEPCMCIA_FLAG_SOCKETP 0x0001 113 114#define MMEYEPCMCIA_LASTSTATE_PRESENT 0x0002 115#define MMEYEPCMCIA_LASTSTATE_HALF 0x0001 116#define MMEYEPCMCIA_LASTSTATE_EMPTY 0x0000 117 118/* 119 * This is sort of arbitrary. It merely needs to be "enough". It can be 120 * overridden in the conf file, anyway. 121 */ 122 123#define MMEYEPCMCIA_MEM_PAGES 4 124 125#define MMEYEPCMCIA_NSLOTS 1 126 127#define MMEYEPCMCIA_WINS 5 128#define MMEYEPCMCIA_IOWINS 2 129 130struct mmeyepcmcia_softc { 131 device_t dev; 132 133 bus_space_tag_t iot; /* mmeyepcmcia registers */ 134 bus_space_handle_t ioh; 135 int controller_irq; 136 137 bus_space_tag_t memt; /* PCMCIA spaces */ 138 bus_space_handle_t memh; 139 int card_irq; 140 141 pcmcia_chipset_tag_t pct; 142 143 /* this needs to be large enough to hold PCIC_MEM_PAGES bits */ 144 int subregionmask; 145#define MMEYEPCMCIA_MAX_MEM_PAGES (8 * sizeof(int)) 146 147 /* 148 * used by io/mem window mapping functions. These can actually overlap 149 * with another pcic, since the underlying extent mapper will deal 150 * with individual allocations. This is here to deal with the fact 151 * that different busses have different real widths (different pc 152 * hardware seems to use 10 or 12 bits for the I/O bus). 153 */ 154 bus_addr_t iobase; 155 bus_addr_t iosize; 156 157 struct mmeyepcmcia_handle handle[MMEYEPCMCIA_NSLOTS]; 158}; 159 160static void mmeyepcmcia_attach_sockets(struct mmeyepcmcia_softc *); 161static int mmeyepcmcia_intr(void *arg); 162 163static inline int mmeyepcmcia_read(struct mmeyepcmcia_handle *, int); 164static inline void mmeyepcmcia_write(struct mmeyepcmcia_handle *, int, int); 165 166static int mmeyepcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 167 struct pcmcia_mem_handle *); 168static void mmeyepcmcia_chip_mem_free(pcmcia_chipset_handle_t, 169 struct pcmcia_mem_handle *); 170static int mmeyepcmcia_chip_mem_map(pcmcia_chipset_handle_t, int, 171 bus_addr_t, bus_size_t, struct pcmcia_mem_handle *, 172 bus_size_t *, int *); 173static void mmeyepcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int); 174 175static int mmeyepcmcia_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, 176 bus_size_t, bus_size_t, struct pcmcia_io_handle *); 177static void mmeyepcmcia_chip_io_free(pcmcia_chipset_handle_t, 178 struct pcmcia_io_handle *); 179static int mmeyepcmcia_chip_io_map(pcmcia_chipset_handle_t, int, 180 bus_addr_t, bus_size_t, struct pcmcia_io_handle *, int *); 181static void mmeyepcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int); 182 183static void mmeyepcmcia_chip_socket_enable(pcmcia_chipset_handle_t); 184static void mmeyepcmcia_chip_socket_disable(pcmcia_chipset_handle_t); 185static void mmeyepcmcia_chip_socket_settype(pcmcia_chipset_handle_t, int); 186 187static inline int mmeyepcmcia_read(struct mmeyepcmcia_handle *, int); 188static inline int 189mmeyepcmcia_read(struct mmeyepcmcia_handle *h, int idx) 190{ 191 static int prev_idx = 0; 192 193 if (idx == -1){ 194 idx = prev_idx; 195 } 196 prev_idx = idx; 197 return bus_space_read_stream_2(h->sc->iot, h->sc->ioh, idx); 198} 199 200static inline void mmeyepcmcia_write(struct mmeyepcmcia_handle *, int, int); 201static inline void 202mmeyepcmcia_write(struct mmeyepcmcia_handle *h, int idx, int data) 203{ 204 static int prev_idx; 205 if (idx == -1){ 206 idx = prev_idx; 207 } 208 prev_idx = idx; 209 bus_space_write_stream_2(h->sc->iot, h->sc->ioh, idx, (data)); 210} 211 212static void *mmeyepcmcia_chip_intr_establish(pcmcia_chipset_handle_t, 213 struct pcmcia_function *, int, int (*) (void *), void *); 214static void mmeyepcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, 215 void *); 216static void *mmeyepcmcia_chip_intr_establish(pcmcia_chipset_handle_t, 217 struct pcmcia_function *, int, int (*) (void *), void *); 218static void mmeyepcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, 219 void *); 220 221static void mmeyepcmcia_attach_socket(struct mmeyepcmcia_handle *); 222static void mmeyepcmcia_init_socket(struct mmeyepcmcia_handle *); 223static int mmeyepcmcia_print (void *, const char *); 224static int mmeyepcmcia_intr_socket(struct mmeyepcmcia_handle *); 225static void mmeyepcmcia_attach_card(struct mmeyepcmcia_handle *); 226static void mmeyepcmcia_detach_card(struct mmeyepcmcia_handle *, int); 227static void mmeyepcmcia_deactivate_card(struct mmeyepcmcia_handle *); 228static void mmeyepcmcia_event_thread(void *); 229static void mmeyepcmcia_queue_event(struct mmeyepcmcia_handle *, int); 230 231static int mmeyepcmcia_match(device_t, cfdata_t, void *); 232static void mmeyepcmcia_attach(device_t, device_t, void *); 233 234CFATTACH_DECL_NEW(mmeyepcmcia, sizeof(struct mmeyepcmcia_softc), 235 mmeyepcmcia_match, mmeyepcmcia_attach, NULL, NULL); 236 237static struct pcmcia_chip_functions mmeyepcmcia_functions = { 238 mmeyepcmcia_chip_mem_alloc, 239 mmeyepcmcia_chip_mem_free, 240 mmeyepcmcia_chip_mem_map, 241 mmeyepcmcia_chip_mem_unmap, 242 243 mmeyepcmcia_chip_io_alloc, 244 mmeyepcmcia_chip_io_free, 245 mmeyepcmcia_chip_io_map, 246 mmeyepcmcia_chip_io_unmap, 247 248 mmeyepcmcia_chip_intr_establish, 249 mmeyepcmcia_chip_intr_disestablish, 250 251 mmeyepcmcia_chip_socket_enable, 252 mmeyepcmcia_chip_socket_disable, 253 mmeyepcmcia_chip_socket_settype, 254 NULL, 255}; 256 257static int 258mmeyepcmcia_match(device_t parent, cfdata_t match, void *aux) 259{ 260 struct mainbus_attach_args *ma = aux; 261 262 if (strcmp(ma->ma_name, match->cf_name) != 0) 263 return 0; 264 265 /* Disallow wildcarded values. */ 266 if (ma->ma_addr1 == MAINBUSCF_ADDR1_DEFAULT || 267 ma->ma_addr2 == MAINBUSCF_ADDR2_DEFAULT || 268 ma->ma_irq2 == MAINBUSCF_IRQ2_DEFAULT) 269 return 0; 270 271 return 1; 272} 273 274static void 275mmeyepcmcia_attach(device_t parent, device_t self, void *aux) 276{ 277 struct mainbus_attach_args *ma = aux; 278 struct mmeyepcmcia_softc *sc = device_private(self); 279 280 aprint_naive("\n"); 281 282 sc->dev = self; 283 sc->subregionmask = 1; /* 1999.05.17 T.Horiuchi for R1.4 */ 284 285 sc->pct = (pcmcia_chipset_tag_t)&mmeyepcmcia_functions; 286 sc->iot = 0; 287 /* Map i/o space. */ 288 if (bus_space_map(sc->iot, ma->ma_addr1, MMEYEPCMCIA_IOSIZE, 289 0, &sc->ioh)) { 290 aprint_error(": can't map i/o space\n"); 291 return; 292 } 293 sc->memt = 0; 294 sc->iobase = ma->ma_addr2; 295 sc->controller_irq = ma->ma_irq1; 296 sc->card_irq = ma->ma_irq2; 297 298 sc->handle[0].sc = sc; 299 sc->handle[0].flags = MMEYEPCMCIA_FLAG_SOCKETP; 300 sc->handle[0].laststate = MMEYEPCMCIA_LASTSTATE_EMPTY; 301 302 SIMPLEQ_INIT(&sc->handle[0].events); 303 304 if (sc->controller_irq != MAINBUSCF_IRQ1_DEFAULT) { 305 aprint_normal(": using MMTA irq %d\n", sc->controller_irq); 306 mmeye_intr_establish(sc->controller_irq, 307 IST_LEVEL, IPL_TTY, mmeyepcmcia_intr, sc); 308 } else 309 aprint_normal("\n"); 310 311 mmeyepcmcia_attach_sockets(sc); 312} 313 314static void * 315mmeyepcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch, 316 struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg) 317{ 318 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 319 int irq = h->sc->card_irq; 320 void *ih; 321 322 ih = mmeye_intr_establish(irq, IST_LEVEL, ipl, fct, arg); 323 h->ih_irq = irq; 324 325 printf("%s: card irq %d\n", device_xname(h->pcmcia), irq); 326 327 return ih; 328} 329 330static void 331mmeyepcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 332{ 333 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 334 335 h->ih_irq = 0; 336 mmeye_intr_disestablish(ih); 337} 338 339 340static void 341mmeyepcmcia_attach_sockets(struct mmeyepcmcia_softc *sc) 342{ 343 344 mmeyepcmcia_attach_socket(&sc->handle[0]); 345} 346 347static void 348mmeyepcmcia_attach_socket(struct mmeyepcmcia_handle *h) 349{ 350 struct pcmciabus_attach_args paa; 351 352 /* initialize the rest of the handle */ 353 354 h->shutdown = 0; 355 h->memalloc = 0; 356 h->ioalloc = 0; 357 h->ih_irq = 0; 358 359 /* now, config one pcmcia device per socket */ 360 361 paa.paa_busname = "pcmcia"; 362 paa.pct = (pcmcia_chipset_tag_t) h->sc->pct; 363 paa.pch = (pcmcia_chipset_handle_t) h; 364 365 h->pcmcia = 366 config_found(h->sc->dev, &paa, mmeyepcmcia_print, CFARGS_NONE); 367 368 /* if there's actually a pcmcia device attached, initialize the slot */ 369 370 if (h->pcmcia) 371 mmeyepcmcia_init_socket(h); 372} 373 374static void 375mmeyepcmcia_event_thread(void *arg) 376{ 377 struct mmeyepcmcia_handle *h = arg; 378 struct mmeyepcmcia_event *pe; 379 int s; 380 381 while (h->shutdown == 0) { 382 s = splhigh(); 383 if ((pe = SIMPLEQ_FIRST(&h->events)) == NULL) { 384 splx(s); 385 (void) tsleep(&h->events, PWAIT, "mmeyepcmciaev", 0); 386 continue; 387 } else { 388 splx(s); 389 /* sleep .25s to be enqueued chatterling interrupts */ 390 (void) tsleep((void *)mmeyepcmcia_event_thread, PWAIT, 391 "mmeyepcmciass", hz/4); 392 } 393 s = splhigh(); 394 SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 395 splx(s); 396 397 switch (pe->pe_type) { 398 case MMEYEPCMCIA_EVENT_INSERTION: 399 s = splhigh(); 400 while (1) { 401 struct mmeyepcmcia_event *pe1, *pe2; 402 403 if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) 404 break; 405 if (pe1->pe_type != MMEYEPCMCIA_EVENT_REMOVAL) 406 break; 407 if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) 408 break; 409 if (pe2->pe_type == MMEYEPCMCIA_EVENT_INSERTION) { 410 SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 411 kmem_free(pe1, sizeof(*pe1)); 412 SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 413 kmem_free(pe2, sizeof(*pe2)); 414 } 415 } 416 splx(s); 417 418 DPRINTF(("%s: insertion event\n", device_xname(h->sc->dev))); 419 mmeyepcmcia_attach_card(h); 420 break; 421 422 case MMEYEPCMCIA_EVENT_REMOVAL: 423 s = splhigh(); 424 while (1) { 425 struct mmeyepcmcia_event *pe1, *pe2; 426 427 if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL) 428 break; 429 if (pe1->pe_type != MMEYEPCMCIA_EVENT_INSERTION) 430 break; 431 if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL) 432 break; 433 if (pe2->pe_type == MMEYEPCMCIA_EVENT_REMOVAL) { 434 SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 435 kmem_free(pe1, sizeof(*pe1)); 436 SIMPLEQ_REMOVE_HEAD(&h->events, pe_q); 437 kmem_free(pe2, sizeof(*pe2)); 438 } 439 } 440 splx(s); 441 442 DPRINTF(("%s: removal event\n", device_xname(h->sc->dev))); 443 mmeyepcmcia_detach_card(h, DETACH_FORCE); 444 break; 445 446 default: 447 panic("mmeyepcmcia_event_thread: unknown event %d", 448 pe->pe_type); 449 } 450 kmem_free(pe, sizeof(*pe)); 451 } 452 453 h->event_thread = NULL; 454 455 /* In case parent is waiting for us to exit. */ 456 wakeup(h->sc); 457 458 kthread_exit(0); 459} 460 461static void 462mmeyepcmcia_init_socket(struct mmeyepcmcia_handle *h) 463{ 464 int reg; 465 466 /* 467 * queue creation of a kernel thread to handle insert/removal events. 468 */ 469#ifdef DIAGNOSTIC 470 if (h->event_thread != NULL) 471 panic("mmeyepcmcia_attach_socket: event thread"); 472#endif 473 474 /* if there's a card there, then attach it. */ 475 476 reg = mmeyepcmcia_read(h, MMEYEPCMCIA_IF_STATUS); 477 reg &= ~MMEYEPCMCIA_IF_STATUS_BUSWIDTH; /* Set bus width to 16bit */ 478 479 if ((reg & MMEYEPCMCIA_IF_STATUS_CARDDETECT_MASK) == 480 MMEYEPCMCIA_IF_STATUS_CARDDETECT_PRESENT) { 481 int i; 482 483 /* reset the card */ 484 mmeyepcmcia_write(h, MMEYEPCMCIA_IF_STATUS, reg|MMEYEPCMCIA_IF_STATUS_RESET); 485 delay(1000); /* wait 1000 uSec */ 486 mmeyepcmcia_write(h, MMEYEPCMCIA_IF_STATUS, 487 reg & ~MMEYEPCMCIA_IF_STATUS_RESET); 488 for (i = 0; i < 10000; i++) 489 delay(1000); /* wait 1 mSec */ 490 491 mmeyepcmcia_attach_card(h); 492 h->laststate = MMEYEPCMCIA_LASTSTATE_PRESENT; 493 } else { 494 h->laststate = MMEYEPCMCIA_LASTSTATE_EMPTY; 495 } 496 497 if (kthread_create(PRI_NONE, 0, NULL, mmeyepcmcia_event_thread, h, 498 &h->event_thread, "%s", device_xname(h->sc->dev))) { 499 printf("%s: unable to create event thread\n", 500 device_xname(h->sc->dev)); 501 panic("mmeyepcmcia_create_event_thread"); 502 } 503} 504 505static int 506mmeyepcmcia_print(void *arg, const char *pnp) 507{ 508 509 if (pnp) 510 aprint_normal("pcmcia at %s", pnp); 511 512 return UNCONF; 513} 514 515static int 516mmeyepcmcia_intr(void *arg) 517{ 518 struct mmeyepcmcia_softc *sc = arg; 519 520 DPRINTF(("%s: intr\n", device_xname(sc->dev))); 521 522 mmeyepcmcia_intr_socket(&sc->handle[0]); 523 524 return 0; 525} 526 527static int 528mmeyepcmcia_intr_socket(struct mmeyepcmcia_handle *h) 529{ 530 int cscreg; 531 532 cscreg = mmeyepcmcia_read(h, MMEYEPCMCIA_CSC); 533 534 cscreg &= (MMEYEPCMCIA_CSC_GPI | 535 MMEYEPCMCIA_CSC_CD | 536 MMEYEPCMCIA_CSC_READY | 537 MMEYEPCMCIA_CSC_BATTWARN | 538 MMEYEPCMCIA_CSC_BATTDEAD); 539 540 if (cscreg & MMEYEPCMCIA_CSC_GPI) { 541 DPRINTF(("%s: GPI\n", device_xname(h->sc->dev))); 542 } 543 if (cscreg & MMEYEPCMCIA_CSC_CD) { 544 int statreg; 545 546 statreg = mmeyepcmcia_read(h, MMEYEPCMCIA_IF_STATUS); 547 548 DPRINTF(("%s: CD %x\n", device_xname(h->sc->dev), statreg)); 549 550 if ((statreg & MMEYEPCMCIA_IF_STATUS_CARDDETECT_MASK) == 551 MMEYEPCMCIA_IF_STATUS_CARDDETECT_PRESENT) { 552 if (h->laststate != MMEYEPCMCIA_LASTSTATE_PRESENT) { 553 DPRINTF(("%s: enqueuing INSERTION event\n", 554 device_xname(h->sc->dev))); 555 mmeyepcmcia_queue_event(h, MMEYEPCMCIA_EVENT_INSERTION); 556 } 557 h->laststate = MMEYEPCMCIA_LASTSTATE_PRESENT; 558 } else { 559 if (h->laststate == MMEYEPCMCIA_LASTSTATE_PRESENT) { 560 /* Deactivate the card now. */ 561 DPRINTF(("%s: deactivating card\n", 562 device_xname(h->sc->dev))); 563 mmeyepcmcia_deactivate_card(h); 564 565 DPRINTF(("%s: enqueuing REMOVAL event\n", 566 device_xname(h->sc->dev))); 567 mmeyepcmcia_queue_event(h, MMEYEPCMCIA_EVENT_REMOVAL); 568 } 569 h->laststate = ((statreg & MMEYEPCMCIA_IF_STATUS_CARDDETECT_MASK) == 0) 570 ? MMEYEPCMCIA_LASTSTATE_EMPTY : MMEYEPCMCIA_LASTSTATE_HALF; 571 } 572 } 573 if (cscreg & MMEYEPCMCIA_CSC_READY) { 574 DPRINTF(("%s: READY\n", device_xname(h->sc->dev))); 575 /* shouldn't happen */ 576 } 577 if (cscreg & MMEYEPCMCIA_CSC_BATTWARN) { 578 DPRINTF(("%s: BATTWARN\n", device_xname(h->sc->dev))); 579 } 580 if (cscreg & MMEYEPCMCIA_CSC_BATTDEAD) { 581 DPRINTF(("%s: BATTDEAD\n", device_xname(h->sc->dev))); 582 } 583 return cscreg ? 1 : 0; 584} 585 586static void 587mmeyepcmcia_queue_event(struct mmeyepcmcia_handle *h, int event) 588{ 589 struct mmeyepcmcia_event *pe; 590 int s; 591 592 pe = kmem_intr_alloc(sizeof(*pe), KM_NOSLEEP); 593 if (pe == NULL) 594 panic("mmeyepcmcia_queue_event: can't allocate event"); 595 596 pe->pe_type = event; 597 s = splhigh(); 598 SIMPLEQ_INSERT_TAIL(&h->events, pe, pe_q); 599 splx(s); 600 wakeup(&h->events); 601} 602 603static void 604mmeyepcmcia_attach_card(struct mmeyepcmcia_handle *h) 605{ 606 607 if (!(h->flags & MMEYEPCMCIA_FLAG_CARDP)) { 608 /* call the MI attach function */ 609 pcmcia_card_attach(h->pcmcia); 610 611 h->flags |= MMEYEPCMCIA_FLAG_CARDP; 612 } else { 613 DPRINTF(("mmeyepcmcia_attach_card: already attached")); 614 } 615} 616 617static void 618mmeyepcmcia_detach_card(struct mmeyepcmcia_handle *h, int flags) 619{ 620 621 if (h->flags & MMEYEPCMCIA_FLAG_CARDP) { 622 h->flags &= ~MMEYEPCMCIA_FLAG_CARDP; 623 624 /* call the MI detach function */ 625 pcmcia_card_detach(h->pcmcia, flags); 626 } else { 627 DPRINTF(("mmeyepcmcia_detach_card: already detached")); 628 } 629} 630 631static void 632mmeyepcmcia_deactivate_card(struct mmeyepcmcia_handle *h) 633{ 634 635 /* call the MI deactivate function */ 636 pcmcia_card_deactivate(h->pcmcia); 637 638 /* Power down and reset XXX notyet */ 639} 640 641static int 642mmeyepcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 643 struct pcmcia_mem_handle *pcmhp) 644{ 645 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 646 bus_addr_t addr; 647 bus_size_t sizepg; 648 int i, mask, mhandle; 649 650 /* out of sc->memh, allocate as many pages as necessary */ 651#define MMEYEPCMCIA_MEM_ALIGN MMEYEPCMCIA_MEM_PAGESIZE 652 /* convert size to PCIC pages */ 653 sizepg = (size + (MMEYEPCMCIA_MEM_ALIGN - 1)) / MMEYEPCMCIA_MEM_ALIGN; 654 if (sizepg > MMEYEPCMCIA_MAX_MEM_PAGES) 655 return 1; 656 657 mask = (1 << sizepg) - 1; 658 659 addr = 0; /* XXX gcc -Wuninitialized */ 660 mhandle = 0; /* XXX gcc -Wuninitialized */ 661 662 for (i = 0; i <= MMEYEPCMCIA_MAX_MEM_PAGES - sizepg; i++) { 663 if ((h->sc->subregionmask & (mask << i)) == (mask << i)) { 664 mhandle = mask << i; 665 addr = h->sc->iobase + (i * MMEYEPCMCIA_MEM_PAGESIZE); 666 h->sc->subregionmask &= ~(mhandle); 667 pcmhp->memt = h->sc->memt; 668 pcmhp->memh = 0; 669 pcmhp->addr = addr; 670 pcmhp->size = size; 671 pcmhp->mhandle = mhandle; 672 pcmhp->realsize = sizepg * MMEYEPCMCIA_MEM_PAGESIZE; 673 return 0; 674 } 675 } 676 677 return 1; 678} 679 680static void 681mmeyepcmcia_chip_mem_free(pcmcia_chipset_handle_t pch, 682 struct pcmcia_mem_handle *pcmhp) 683{ 684 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 685 686 h->sc->subregionmask |= pcmhp->mhandle; 687} 688 689static int 690mmeyepcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind, 691 bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp, 692 bus_size_t *offsetp, int *windowp) 693{ 694 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 695 bus_addr_t busaddr; 696 int i, win; 697 698 win = -1; 699 for (i = 0; i < MMEYEPCMCIA_WINS; i++) { 700 if ((h->memalloc & (1 << i)) == 0) { 701 win = i; 702 h->memalloc |= (1 << i); 703 break; 704 } 705 } 706 707 if (win == -1) 708 return 1; 709 710 *windowp = win; 711 712 /* XXX this is pretty gross */ 713 714 busaddr = pcmhp->addr + card_addr; 715 716#if defined(SH7750R) 717 switch (kind) { 718 case PCMCIA_MEM_ATTR: 719 case PCMCIA_MEM_ATTR | PCMCIA_WIDTH_MEM16: 720 pcmhp->memt = SH3_BUS_SPACE_PCMCIA_ATT; 721 break; 722 723 case PCMCIA_MEM_ATTR | PCMCIA_WIDTH_MEM8: 724 pcmhp->memt = SH3_BUS_SPACE_PCMCIA_ATT8; 725 break; 726 727 case PCMCIA_MEM_COMMON: 728 case PCMCIA_MEM_COMMON | PCMCIA_WIDTH_MEM16: 729 pcmhp->memt = SH3_BUS_SPACE_PCMCIA_MEM; 730 break; 731 732 case PCMCIA_MEM_COMMON | PCMCIA_WIDTH_MEM8: 733 pcmhp->memt = SH3_BUS_SPACE_PCMCIA_MEM8; 734 break; 735 736 default: 737 panic("mmeyepcmcia_chip_mem_map kind is bogus: 0x%x", kind); 738 } 739#else 740 if (!bus_space_is_equal(h->sc->memt, pcmhp->memt)) 741 panic("mmeyepcmcia_chip_mem_map memt is bogus"); 742 if (kind != PCMCIA_MEM_ATTR) 743 busaddr += MMEYEPCMCIA_ATTRMEM_SIZE; 744#endif 745 if (bus_space_map(pcmhp->memt, busaddr, pcmhp->size, 0, &pcmhp->memh)) 746 return 1; 747 748 /* 749 * compute the address offset to the pcmcia address space for the 750 * pcic. this is intentionally signed. The masks and shifts below 751 * will cause TRT to happen in the pcic registers. Deal with making 752 * sure the address is aligned, and return the alignment offset. 753 */ 754 755 *offsetp = 0; 756 757 DPRINTF(("mmeyepcmcia_chip_mem_map window %d bus %lx+%lx+%lx at card addr " 758 "%lx\n", win, (u_long) busaddr, (u_long) * offsetp, (u_long) size, 759 (u_long) card_addr)); 760 761 /* 762 * include the offset in the size, and decrement size by one, since 763 * the hw wants start/stop 764 */ 765 h->mem[win].addr = busaddr; 766 h->mem[win].size = size - 1; 767 h->mem[win].kind = kind; 768 h->mem[win].memt = pcmhp->memt; 769 h->mem[win].memh = pcmhp->memh; 770 771 return 0; 772} 773 774static void 775mmeyepcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window) 776{ 777 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 778 779 if (window >= MMEYEPCMCIA_WINS) 780 panic("mmeyepcmcia_chip_mem_unmap: window out of range"); 781 782 h->memalloc &= ~(1 << window); 783 784 bus_space_unmap(h->mem[window].memt, h->mem[window].memh, 785 h->mem[window].size); 786} 787 788static int 789mmeyepcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 790 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp) 791{ 792 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 793 bus_addr_t ioaddr; 794 795 /* 796 * Allocate some arbitrary I/O space. 797 */ 798 ioaddr = h->sc->iobase + start; 799 DPRINTF(("mmeyepcmcia_chip_io_alloc alloc port %lx+%lx\n", 800 ioaddr, size)); 801 802 pcihp->iot = h->sc->memt; 803 pcihp->ioh = 0; 804 pcihp->addr = ioaddr; 805 pcihp->size = size; 806 807 return 0; 808} 809 810static void 811mmeyepcmcia_chip_io_free(pcmcia_chipset_handle_t pch, 812 struct pcmcia_io_handle *pcihp) 813{ 814} 815 816static int 817mmeyepcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width, 818 bus_addr_t offset, bus_size_t size, struct pcmcia_io_handle *pcihp, 819 int *windowp) 820{ 821 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 822 bus_addr_t busaddr; 823 int i, win; 824#ifdef MMEYEPCMCIADEBUG 825 static const char *width_names[] = { "auto", "io8", "io16" }; 826#endif 827 828 /* I/O width is hardwired to 16bit mode on mmeye. */ 829 width = PCMCIA_WIDTH_IO16; 830 831 win = -1; 832 for (i = 0; i < MMEYEPCMCIA_IOWINS; i++) { 833 if ((h->ioalloc & (1 << i)) == 0) { 834 win = i; 835 h->ioalloc |= (1 << i); 836 break; 837 } 838 } 839 840 if (win == -1) 841 return 1; 842 843 *windowp = win; 844 845 /* XXX this is pretty gross */ 846 847 busaddr = pcihp->addr + offset; 848 849#if defined(SH7750R) 850 switch (width) { 851 case PCMCIA_WIDTH_IO8: 852 pcihp->iot = SH3_BUS_SPACE_PCMCIA_IO8; 853 break; 854 855 case PCMCIA_WIDTH_IO16: 856 pcihp->iot = SH3_BUS_SPACE_PCMCIA_IO; 857 break; 858 859 case PCMCIA_WIDTH_AUTO: 860 default: 861 panic("mmeyepcmcia_chip_io_map width is bogus: 0x%x", width); 862 } 863#else 864 if (!bus_space_is_equal(h->sc->iot, pcihp->iot)) 865 panic("mmeyepcmcia_chip_io_map iot is bogus"); 866 busaddr += MMEYEPCMCIA_ATTRMEM_SIZE; 867#endif 868 if (bus_space_map(pcihp->iot, busaddr, pcihp->size, 0, &pcihp->ioh)) 869 return 1; 870 871 DPRINTF(("mmeyepcmcia_chip_io_map window %d %s port %lx+%lx\n", 872 win, width_names[width], (u_long) offset, (u_long) size)); 873 874 /* XXX wtf is this doing here? */ 875 876 h->io[win].addr = busaddr; 877 h->io[win].size = size; 878 h->io[win].width = width; 879 h->io[win].iot = pcihp->iot; 880 h->io[win].ioh = pcihp->ioh; 881 882 return 0; 883} 884 885static void 886mmeyepcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window) 887{ 888 struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch; 889 890 if (window >= MMEYEPCMCIA_IOWINS) 891 panic("mmeyepcmcia_chip_io_unmap: window out of range"); 892 893 h->ioalloc &= ~(1 << window); 894 895 bus_space_unmap(h->io[window].iot, h->io[window].ioh, 896 h->io[window].size); 897} 898 899static void 900mmeyepcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch) 901{ 902} 903 904static void 905mmeyepcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch) 906{ 907} 908 909static void 910mmeyepcmcia_chip_socket_settype(pcmcia_chipset_handle_t pch, int type) 911{ 912} 913