1 /* $NetBSD: maple.c,v 1.58 2025/11/24 08:17:29 nia Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by ITOH Yasufumi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /*- 33 * Copyright (c) 2001 Marcus Comstedt 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of The NetBSD Foundation nor the names of its 45 * contributors may be used to endorse or promote products derived 46 * from this software without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 58 * POSSIBILITY OF SUCH DAMAGE. 59 */ 60 61 #include <sys/cdefs.h> 62 __KERNEL_RCSID(0, "$NetBSD: maple.c,v 1.58 2025/11/24 08:17:29 nia Exp $"); 63 64 #include <sys/param.h> 65 #include <sys/device.h> 66 #include <sys/device_impl.h> /* XXX autoconf abuse */ 67 #include <sys/fcntl.h> 68 #include <sys/kernel.h> 69 #include <sys/kthread.h> 70 #include <sys/poll.h> 71 #include <sys/select.h> 72 #include <sys/proc.h> 73 #include <sys/signalvar.h> 74 #include <sys/systm.h> 75 #include <sys/conf.h> 76 #include <sys/bus.h> 77 #include <sys/mutex.h> 78 #include <sys/condvar.h> 79 80 #include <uvm/uvm.h> 81 82 #include <machine/cpu.h> 83 #include <machine/sysasicvar.h> 84 #include <sh3/pmap.h> 85 86 #include <dreamcast/dev/maple/maple.h> 87 #include <dreamcast/dev/maple/mapleconf.h> 88 #include <dreamcast/dev/maple/maplevar.h> 89 #include <dreamcast/dev/maple/maplereg.h> 90 #include <dreamcast/dev/maple/mapleio.h> 91 92 #include "ioconf.h" 93 #include "locators.h" 94 95 /* Internal macros, functions, and variables. */ 96 97 #define MAPLE_CALLOUT_TICKS 2 98 99 #define MAPLEBUSUNIT(dev) (minor(dev)>>5) 100 #define MAPLEPORT(dev) ((minor(dev) & 0x18) >> 3) 101 #define MAPLESUBUNIT(dev) (minor(dev) & 0x7) 102 103 /* interrupt priority level */ 104 #define IPL_MAPLE IPL_BIO 105 #define splmaple() splbio() 106 #define IRL_MAPLE SYSASIC_IRL9 107 108 /* 109 * Function declarations. 110 */ 111 static int maplematch(device_t, cfdata_t, void *); 112 static void mapleattach(device_t, device_t, void *); 113 static void maple_scanbus(struct maple_softc *); 114 static char * maple_unit_name(char *, size_t, int port, int subunit); 115 static void maple_begin_txbuf(struct maple_softc *); 116 static int maple_end_txbuf(struct maple_softc *); 117 static void maple_queue_command(struct maple_softc *, struct maple_unit *, 118 int command, int datalen, const void *dataaddr); 119 static void maple_write_command(struct maple_softc *, struct maple_unit *, 120 int, int, const void *); 121 static void maple_start(struct maple_softc *sc); 122 static void maple_start_poll(struct maple_softc *); 123 static void maple_check_subunit_change(struct maple_softc *, 124 struct maple_unit *); 125 static void maple_check_unit_change(struct maple_softc *, 126 struct maple_unit *); 127 static void maple_print_unit(void *, const char *); 128 static int maplesubmatch(device_t, cfdata_t, const int *, void *); 129 static int mapleprint(void *, const char *); 130 static void maple_attach_unit(struct maple_softc *, struct maple_unit *); 131 static void maple_detach_unit_nofix(struct maple_softc *, 132 struct maple_unit *); 133 static void maple_detach_unit(struct maple_softc *, struct maple_unit *); 134 static void maple_queue_cmds(struct maple_softc *, 135 struct maple_cmdq_head *); 136 static void maple_unit_probe(struct maple_softc *); 137 static void maple_unit_ping(struct maple_softc *); 138 static int maple_send_defered_periodic(struct maple_softc *); 139 static void maple_send_periodic(struct maple_softc *); 140 static void maple_remove_from_queues(struct maple_softc *, 141 struct maple_unit *); 142 static int maple_retry(struct maple_softc *, struct maple_unit *, 143 enum maple_dma_stat); 144 static void maple_queue_retry(struct maple_softc *); 145 static void maple_check_responses(struct maple_softc *); 146 static void maple_event_thread(void *); 147 static int maple_intr(void *); 148 static void maple_callout(void *); 149 150 int maple_alloc_dma(size_t, vaddr_t *, paddr_t *); 151 #if 0 152 void maple_free_dma(paddr_t, size_t); 153 #endif 154 155 /* 156 * Global variables. 157 */ 158 int maple_polling; /* Are we polling? (Debugger mode) */ 159 160 CFATTACH_DECL_NEW(maple, sizeof(struct maple_softc), 161 maplematch, mapleattach, NULL, NULL); 162 163 dev_type_open(mapleopen); 164 dev_type_close(mapleclose); 165 dev_type_ioctl(mapleioctl); 166 167 const struct cdevsw maple_cdevsw = { 168 .d_open = mapleopen, 169 .d_close = mapleclose, 170 .d_read = noread, 171 .d_write = nowrite, 172 .d_ioctl = mapleioctl, 173 .d_stop = nostop, 174 .d_tty = notty, 175 .d_poll = nopoll, 176 .d_mmap = nommap, 177 .d_kqfilter = nokqfilter, 178 .d_discard = nodiscard, 179 .d_flag = 0 180 }; 181 182 static int 183 maplematch(device_t parent, cfdata_t cf, void *aux) 184 { 185 186 return 1; 187 } 188 189 static void 190 mapleattach(device_t parent, device_t self, void *aux) 191 { 192 struct maple_softc *sc; 193 struct maple_unit *u; 194 vaddr_t dmabuffer; 195 paddr_t dmabuffer_phys; 196 uint32_t *p; 197 int port, subunit, f; 198 199 sc = device_private(self); 200 sc->sc_dev = self; 201 202 printf(": %s\n", sysasic_intr_string(IRL_MAPLE)); 203 204 if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) { 205 printf("%s: unable to allocate DMA buffers.\n", 206 device_xname(self)); 207 return; 208 } 209 210 p = (uint32_t *)dmabuffer; 211 212 for (port = 0; port < MAPLE_PORTS; port++) { 213 for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) { 214 u = &sc->sc_unit[port][subunit]; 215 u->port = port; 216 u->subunit = subunit; 217 u->u_dma_stat = MAPLE_DMA_IDLE; 218 u->u_rxbuf = p; 219 u->u_rxbuf_phys = SH3_P2SEG_TO_PHYS(p); 220 p += 256; 221 222 for (f = 0; f < MAPLE_NFUNC; f++) { 223 u->u_func[f].f_funcno = f; 224 u->u_func[f].f_unit = u; 225 } 226 } 227 } 228 229 sc->sc_txbuf = p; 230 sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p); 231 232 SIMPLEQ_INIT(&sc->sc_retryq); 233 TAILQ_INIT(&sc->sc_probeq); 234 TAILQ_INIT(&sc->sc_pingq); 235 TAILQ_INIT(&sc->sc_periodicq); 236 TAILQ_INIT(&sc->sc_periodicdeferq); 237 TAILQ_INIT(&sc->sc_acmdq); 238 TAILQ_INIT(&sc->sc_pcmdq); 239 240 MAPLE_RESET = RESET_MAGIC; 241 MAPLE_RESET2 = 0; 242 243 MAPLE_SPEED = SPEED_2MBPS | TIMEOUT(50000); 244 245 MAPLE_ENABLE = 1; 246 247 mutex_init(&sc->sc_dma_lock, MUTEX_DEFAULT, IPL_MAPLE); 248 cv_init(&sc->sc_dma_cv, device_xname(self)); 249 mutex_init(&sc->sc_event_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK); 250 cv_init(&sc->sc_event_cv, device_xname(self)); 251 252 maple_polling = 1; 253 maple_scanbus(sc); 254 255 callout_init(&sc->maple_callout_ch, 0); 256 257 sc->sc_intrhand = sysasic_intr_establish(SYSASIC_EVENT_MAPLE_DMADONE, 258 IPL_MAPLE, IRL_MAPLE, maple_intr, sc); 259 260 config_pending_incr(self); /* create thread before mounting root */ 261 262 if (kthread_create(PRI_NONE, 0, NULL, maple_event_thread, sc, 263 &sc->event_thread, "%s", device_xname(self)) == 0) 264 return; 265 266 panic("%s: unable to create event thread", device_xname(self)); 267 } 268 269 /* 270 * initial device attach 271 */ 272 static void 273 maple_scanbus(struct maple_softc *sc) 274 { 275 struct maple_unit *u; 276 int port; 277 int last_port, last_subunit; 278 int i; 279 280 KASSERT(cold && maple_polling); 281 282 /* probe all ports */ 283 for (port = 0; port < MAPLE_PORTS; port++) { 284 u = &sc->sc_unit[port][0]; 285 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 286 { 287 char buf[16]; 288 printf("%s: queued to probe 1\n", 289 maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 290 } 291 #endif 292 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 293 u->u_queuestat = MAPLE_QUEUE_PROBE; 294 } 295 296 last_port = last_subunit = -1; 297 maple_begin_txbuf(sc); 298 while ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 299 /* 300 * Check wrap condition 301 */ 302 if (u->port < last_port || u->subunit <= last_subunit) 303 break; 304 last_port = u->port; 305 if (u->port == MAPLE_PORTS - 1) 306 last_subunit = u->subunit; 307 308 maple_unit_probe(sc); 309 for (i = 10 /* just not forever */; maple_end_txbuf(sc); i--) { 310 maple_start_poll(sc); 311 maple_check_responses(sc); 312 if (i == 0) 313 break; 314 /* attach may issue cmds */ 315 maple_queue_cmds(sc, &sc->sc_acmdq); 316 } 317 } 318 } 319 320 void 321 maple_run_polling(device_t dev) 322 { 323 struct maple_softc *sc; 324 int port, subunit; 325 int i; 326 327 sc = device_private(dev); 328 329 /* 330 * first, make sure polling works 331 */ 332 while (MAPLE_STATE != 0) /* XXX may lost a DMA cycle */ 333 ; 334 335 /* XXX this will break internal state */ 336 for (port = 0; port < MAPLE_PORTS; port++) 337 for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) 338 sc->sc_unit[port][subunit].u_dma_stat = MAPLE_DMA_IDLE; 339 SIMPLEQ_INIT(&sc->sc_retryq); /* XXX discard current retries */ 340 341 /* 342 * do polling (periodic status check only) 343 */ 344 maple_begin_txbuf(sc); 345 maple_send_defered_periodic(sc); 346 maple_send_periodic(sc); 347 for (i = 10 /* just not forever */; maple_end_txbuf(sc); i--) { 348 maple_start_poll(sc); 349 maple_check_responses(sc); 350 if (i == 0) 351 break; 352 353 /* maple_check_responses() has executed maple_begin_txbuf() */ 354 maple_queue_retry(sc); 355 maple_send_defered_periodic(sc); 356 } 357 } 358 359 static char * 360 maple_unit_name(char *buf, size_t len, int port, int subunit) 361 { 362 size_t l = snprintf(buf, len, "maple%c", port + 'A'); 363 if (l > len) 364 l = len; 365 if (subunit) 366 snprintf(buf + l, len - l, "%d", subunit); 367 368 return buf; 369 } 370 371 int 372 maple_alloc_dma(size_t size, vaddr_t *vap, paddr_t *pap) 373 { 374 extern paddr_t avail_start, avail_end; /* from pmap.c */ 375 struct pglist mlist; 376 struct vm_page *m; 377 int error; 378 379 size = round_page(size); 380 381 error = uvm_pglistalloc(size, avail_start, avail_end - PAGE_SIZE, 382 0, 0, &mlist, 1, 0); 383 if (error) 384 return error; 385 386 m = TAILQ_FIRST(&mlist); 387 *pap = VM_PAGE_TO_PHYS(m); 388 *vap = SH3_PHYS_TO_P2SEG(VM_PAGE_TO_PHYS(m)); 389 390 return 0; 391 } 392 393 #if 0 /* currently unused */ 394 void 395 maple_free_dma(paddr_t paddr, size_t size) 396 { 397 struct pglist mlist; 398 struct vm_page *m; 399 bus_addr_t addr; 400 401 TAILQ_INIT(&mlist); 402 for (addr = paddr; addr < paddr + size; addr += PAGE_SIZE) { 403 m = PHYS_TO_VM_PAGE(addr); 404 TAILQ_INSERT_TAIL(&mlist, m, pageq.queue); 405 } 406 uvm_pglistfree(&mlist); 407 } 408 #endif 409 410 static void 411 maple_begin_txbuf(struct maple_softc *sc) 412 { 413 414 sc->sc_txlink = sc->sc_txpos = sc->sc_txbuf; 415 SIMPLEQ_INIT(&sc->sc_dmaq); 416 } 417 418 static int 419 maple_end_txbuf(struct maple_softc *sc) 420 { 421 422 /* if no frame have been written, we can't mark the 423 list end, and so the DMA must not be activated */ 424 if (sc->sc_txpos == sc->sc_txbuf) 425 return 0; 426 427 *sc->sc_txlink |= 0x80000000; 428 429 return 1; 430 } 431 432 static const int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 }; 433 434 static void 435 maple_queue_command(struct maple_softc *sc, struct maple_unit *u, 436 int command, int datalen, const void *dataaddr) 437 { 438 int to, from; 439 uint32_t *p = sc->sc_txpos; 440 441 /* Max data length = 255 longs = 1020 bytes */ 442 KASSERT(datalen >= 0 && datalen <= 255); 443 444 /* Compute sender and recipient address */ 445 from = u->port << 6; 446 to = from | subunit_code[u->subunit]; 447 448 sc->sc_txlink = p; 449 450 /* Set length of packet and destination port (A-D) */ 451 *p++ = datalen | (u->port << 16); 452 453 /* Write address to receive buffer where the response 454 frame should be put */ 455 *p++ = u->u_rxbuf_phys; 456 457 /* Create the frame header. The fields are assembled "backwards" 458 because of the Maple Bus big-endianness. */ 459 *p++ = (command & 0xff) | (to << 8) | (from << 16) | (datalen << 24); 460 461 /* Copy parameter data, if any */ 462 if (datalen > 0) { 463 const uint32_t *param = dataaddr; 464 int i; 465 for (i = 0; i < datalen; i++) 466 *p++ = *param++; 467 } 468 469 sc->sc_txpos = p; 470 471 SIMPLEQ_INSERT_TAIL(&sc->sc_dmaq, u, u_dmaq); 472 } 473 474 static void 475 maple_write_command(struct maple_softc *sc, struct maple_unit *u, int command, 476 int datalen, const void *dataaddr) 477 { 478 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 479 char buf[16]; 480 481 if (u->u_retrycnt) 482 printf("%s: retrycnt %d\n", maple_unit_name(buf, sizeof(buf), 483 u->port, u->subunit), u->u_retrycnt); 484 #endif 485 u->u_retrycnt = 0; 486 u->u_command = command; 487 u->u_datalen = datalen; 488 u->u_dataaddr = dataaddr; 489 490 maple_queue_command(sc, u, command, datalen, dataaddr); 491 } 492 493 /* start DMA */ 494 static void 495 maple_start(struct maple_softc *sc) 496 { 497 498 MAPLE_DMAADDR = sc->sc_txbuf_phys; 499 MAPLE_STATE = 1; 500 } 501 502 /* start DMA -- wait until DMA done */ 503 static void 504 maple_start_poll(struct maple_softc *sc) 505 { 506 507 MAPLE_DMAADDR = sc->sc_txbuf_phys; 508 MAPLE_STATE = 1; 509 while (MAPLE_STATE != 0) 510 ; 511 } 512 513 static void 514 maple_check_subunit_change(struct maple_softc *sc, struct maple_unit *u) 515 { 516 struct maple_unit *u1; 517 int port; 518 int8_t unit_map; 519 int units, un; 520 int i; 521 522 KASSERT(u->subunit == 0); 523 524 port = u->port; 525 unit_map = ((int8_t *) u->u_rxbuf)[2]; 526 if (sc->sc_port_unit_map[port] == unit_map) 527 return; 528 529 units = ((unit_map & 0x1f) << 1) | 1; 530 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 531 { 532 char buf[16]; 533 printf("%s: unit_map 0x%x -> 0x%x (units 0x%x)\n", 534 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 535 sc->sc_port_unit_map[port], unit_map, units); 536 } 537 #endif 538 #if 0 /* this detects unit removal rapidly but is not reliable */ 539 /* check for unit change */ 540 un = sc->sc_port_units[port] & ~units; 541 542 /* detach removed devices */ 543 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 544 if (un & (1 << i)) 545 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 546 #endif 547 548 sc->sc_port_unit_map[port] = unit_map; 549 550 /* schedule scanning child devices */ 551 un = units & ~sc->sc_port_units[port]; 552 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 553 if (un & (1 << i)) { 554 u1 = &sc->sc_unit[port][i]; 555 maple_remove_from_queues(sc, u1); 556 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 557 { 558 char buf[16]; 559 printf("%s: queued to probe 2\n", 560 maple_unit_name(buf, sizeof(buf), 561 u1->port, u1->subunit)); 562 } 563 #endif 564 TAILQ_INSERT_HEAD(&sc->sc_probeq, u1, u_q); 565 u1->u_queuestat = MAPLE_QUEUE_PROBE; 566 u1->u_proberetry = 0; 567 } 568 } 569 570 static void 571 maple_check_unit_change(struct maple_softc *sc, struct maple_unit *u) 572 { 573 struct maple_devinfo *newinfo = (void *) (u->u_rxbuf + 1); 574 575 if (memcmp(&u->devinfo, newinfo, sizeof(struct maple_devinfo)) == 0) 576 goto out; /* no change */ 577 578 /* unit inserted */ 579 580 /* attach this device */ 581 u->devinfo = *newinfo; 582 maple_attach_unit(sc, u); 583 584 out: 585 maple_remove_from_queues(sc, u); 586 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 587 { 588 char buf[16]; 589 printf("%s: queued to ping\n", 590 maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 591 } 592 #endif 593 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 594 u->u_queuestat = MAPLE_QUEUE_PING; 595 } 596 597 static void 598 maple_print_unit(void *aux, const char *pnp) 599 { 600 struct maple_attach_args *ma = aux; 601 int port, subunit; 602 char buf[16]; 603 char *prod, *p, oc; 604 605 port = ma->ma_unit->port; 606 subunit = ma->ma_unit->subunit; 607 608 if (pnp != NULL) 609 printf("%s at %s", maple_unit_name(buf, sizeof(buf), port, 610 subunit), pnp); 611 612 printf(" port %d", port); 613 614 if (subunit != 0) 615 printf(" subunit %d", subunit); 616 617 #ifdef MAPLE_DEBUG 618 printf(": a %#x c %#x fn %#x d %#x,%#x,%#x", 619 ma->ma_devinfo->di_area_code, 620 ma->ma_devinfo->di_connector_direction, 621 be32toh(ma->ma_devinfo->di_func), 622 be32toh(ma->ma_devinfo->di_function_data[0]), 623 be32toh(ma->ma_devinfo->di_function_data[1]), 624 be32toh(ma->ma_devinfo->di_function_data[2])); 625 #endif 626 627 /* nul termination */ 628 prod = ma->ma_devinfo->di_product_name; 629 for (p = prod + sizeof ma->ma_devinfo->di_product_name; p >= prod; p--) 630 if (p[-1] != '\0' && p[-1] != ' ') 631 break; 632 oc = *p; 633 *p = '\0'; 634 635 printf(": %s", prod); 636 637 *p = oc; /* restore */ 638 } 639 640 static int 641 maplesubmatch(device_t parent, cfdata_t match, const int *ldesc, void *aux) 642 { 643 struct maple_attach_args *ma = aux; 644 645 if (match->cf_loc[MAPLECF_PORT] != MAPLECF_PORT_DEFAULT && 646 match->cf_loc[MAPLECF_PORT] != ma->ma_unit->port) 647 return 0; 648 649 if (match->cf_loc[MAPLECF_SUBUNIT] != MAPLECF_SUBUNIT_DEFAULT && 650 match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_unit->subunit) 651 return 0; 652 653 return config_match(parent, match, aux); 654 } 655 656 static int 657 mapleprint(void *aux, const char *str) 658 { 659 struct maple_attach_args *ma = aux; 660 661 #ifdef MAPLE_DEBUG 662 if (str) 663 aprint_normal("%s", str); 664 aprint_normal(" function %d", ma->ma_function); 665 666 return UNCONF; 667 #else /* quiet */ 668 if (!str) 669 aprint_normal(" function %d", ma->ma_function); 670 671 return QUIET; 672 #endif 673 } 674 675 static void 676 maple_attach_unit(struct maple_softc *sc, struct maple_unit *u) 677 { 678 struct maple_attach_args ma; 679 uint32_t func; 680 int f; 681 char oldxname[16]; 682 683 ma.ma_unit = u; 684 ma.ma_devinfo = &u->devinfo; 685 ma.ma_basedevinfo = &sc->sc_unit[u->port][0].devinfo; 686 func = be32toh(ma.ma_devinfo->di_func); 687 688 maple_print_unit(&ma, device_xname(sc->sc_dev)); 689 printf("\n"); 690 strcpy(oldxname, device_xname(sc->sc_dev)); 691 maple_unit_name(sc->sc_dev->dv_xname, sizeof(sc->sc_dev->dv_xname), 692 u->port, u->subunit); 693 694 for (f = 0; f < MAPLE_NFUNC; f++) { 695 u->u_func[f].f_callback = NULL; 696 u->u_func[f].f_arg = NULL; 697 u->u_func[f].f_cmdstat = MAPLE_CMDSTAT_NONE; 698 u->u_func[f].f_dev = NULL; 699 if (func & MAPLE_FUNC(f)) { 700 ma.ma_function = f; 701 u->u_func[f].f_dev = 702 config_found(sc->sc_dev, &ma, mapleprint, 703 CFARGS(.submatch = maplesubmatch)); 704 u->u_ping_func = f; /* XXX using largest func */ 705 } 706 } 707 #ifdef MAPLE_MEMCARD_PING_HACK 708 /* 709 * Some 3rd party memory card pretend to be Visual Memory, 710 * but need special handling for ping. 711 */ 712 if (func == (MAPLE_FUNC(MAPLE_FN_MEMCARD) | MAPLE_FUNC(MAPLE_FN_LCD) | 713 MAPLE_FUNC(MAPLE_FN_CLOCK))) { 714 u->u_ping_func = MAPLE_FN_MEMCARD; 715 u->u_ping_stat = MAPLE_PING_MEMCARD; 716 } else { 717 u->u_ping_stat = MAPLE_PING_NORMAL; 718 } 719 #endif 720 strcpy(sc->sc_dev->dv_xname, oldxname); 721 722 sc->sc_port_units[u->port] |= 1 << u->subunit; 723 } 724 725 static void 726 maple_detach_unit_nofix(struct maple_softc *sc, struct maple_unit *u) 727 { 728 struct maple_func *fn; 729 device_t dev; 730 struct maple_unit *u1; 731 int port; 732 int error; 733 int i; 734 char buf[16]; 735 736 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 737 printf("%s: remove\n", maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 738 #endif 739 maple_remove_from_queues(sc, u); 740 port = u->port; 741 sc->sc_port_units[port] &= ~(1 << u->subunit); 742 743 if (u->subunit == 0) { 744 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 745 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 746 } 747 748 for (fn = u->u_func; fn < &u->u_func[MAPLE_NFUNC]; fn++) { 749 if ((dev = fn->f_dev) != NULL) { 750 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 751 printf("%s: detaching func %d\n", 752 maple_unit_name(buf, sizeof(buf), port, u->subunit), 753 fn->f_funcno); 754 #endif 755 756 /* 757 * Remove functions from command queue. 758 */ 759 switch (fn->f_cmdstat) { 760 case MAPLE_CMDSTAT_ASYNC: 761 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 762 TAILQ_REMOVE(&sc->sc_acmdq, fn, f_cmdq); 763 break; 764 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 765 case MAPLE_CMDSTAT_PERIODIC: 766 TAILQ_REMOVE(&sc->sc_pcmdq, fn, f_cmdq); 767 break; 768 default: 769 break; 770 } 771 772 /* 773 * Detach devices. 774 */ 775 if ((error = config_detach(fn->f_dev, DETACH_FORCE))) { 776 printf("%s: failed to detach %s (func %d), errno %d\n", 777 maple_unit_name(buf, sizeof(buf), port, u->subunit), 778 device_xname(fn->f_dev), fn->f_funcno, error); 779 } 780 } 781 782 maple_enable_periodic(sc->sc_dev, u, fn->f_funcno, 0); 783 784 fn->f_dev = NULL; 785 fn->f_callback = NULL; 786 fn->f_arg = NULL; 787 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 788 } 789 if (u->u_dma_stat == MAPLE_DMA_RETRY) { 790 /* XXX expensive? */ 791 SIMPLEQ_FOREACH(u1, &sc->sc_retryq, u_dmaq) { 792 if (u1 == u) { 793 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 794 printf("%s: abort retry\n", 795 maple_unit_name(buf, sizeof(buf), port, u->subunit)); 796 #endif 797 SIMPLEQ_REMOVE(&sc->sc_retryq, u, maple_unit, 798 u_dmaq); 799 break; 800 } 801 } 802 } 803 u->u_dma_stat = MAPLE_DMA_IDLE; 804 u->u_noping = 0; 805 /* u->u_dma_func = uninitialized; */ 806 KASSERT(u->getcond_func_set == 0); 807 memset(&u->devinfo, 0, sizeof(struct maple_devinfo)); 808 809 if (u->subunit == 0) { 810 sc->sc_port_unit_map[port] = 0; 811 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 812 { 813 char buf2[16]; 814 printf("%s: queued to probe 3\n", 815 maple_unit_name(buf2, sizeof(buf2), port, u->subunit)); 816 } 817 #endif 818 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 819 u->u_queuestat = MAPLE_QUEUE_PROBE; 820 } 821 } 822 823 static void 824 maple_detach_unit(struct maple_softc *sc, struct maple_unit *u) 825 { 826 827 maple_detach_unit_nofix(sc, u); 828 if (u->subunit != 0) 829 sc->sc_port_unit_map[u->port] &= ~(1 << (u->subunit - 1)); 830 } 831 832 /* 833 * Send a command (called by drivers) 834 * 835 * The "cataaddr" must not point at temporary storage like stack. 836 * Only one command (per function) is valid at a time. 837 */ 838 void 839 maple_command(device_t dev, struct maple_unit *u, int func, 840 int command, int datalen, const void *dataaddr, int flags) 841 { 842 struct maple_softc *sc = device_private(dev); 843 struct maple_func *fn; 844 845 KASSERT(func >= 0 && func < 32); 846 KASSERT(command); 847 KASSERT((flags & ~MAPLE_FLAG_CMD_PERIODIC_TIMING) == 0); 848 849 mutex_enter(&sc->sc_event_lock); 850 851 fn = &u->u_func[func]; 852 #if 1 /*def DIAGNOSTIC*/ 853 {char buf[16]; 854 if (fn->f_cmdstat != MAPLE_CMDSTAT_NONE) 855 panic("maple_command: %s func %d: requesting more than one commands", 856 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), func); 857 } 858 #endif 859 fn->f_command = command; 860 fn->f_datalen = datalen; 861 fn->f_dataaddr = dataaddr; 862 if (flags & MAPLE_FLAG_CMD_PERIODIC_TIMING) { 863 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 864 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 865 } else { 866 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 867 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 868 cv_broadcast(&sc->sc_event_cv); /* wake for async event */ 869 } 870 mutex_exit(&sc->sc_event_lock); 871 } 872 873 static void 874 maple_queue_cmds(struct maple_softc *sc, 875 struct maple_cmdq_head *head) 876 { 877 struct maple_func *fn, *nextfn; 878 struct maple_unit *u; 879 880 /* 881 * Note: since the queue element may be queued immediately, 882 * we can't use TAILQ_FOREACH. 883 */ 884 fn = TAILQ_FIRST(head); 885 TAILQ_INIT(head); 886 for ( ; fn; fn = nextfn) { 887 nextfn = TAILQ_NEXT(fn, f_cmdq); 888 889 KASSERT(fn->f_cmdstat != MAPLE_CMDSTAT_NONE); 890 u = fn->f_unit; 891 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 892 maple_write_command(sc, u, 893 fn->f_command, fn->f_datalen, fn->f_dataaddr); 894 u->u_dma_stat = (fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC || 895 fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC_PERIODICQ) ? 896 MAPLE_DMA_ACMD : MAPLE_DMA_PCMD; 897 u->u_dma_func = fn->f_funcno; 898 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 899 } else if (u->u_dma_stat == MAPLE_DMA_RETRY) { 900 /* unit is busy --- try again */ 901 /* 902 * always add to periodic command queue 903 * (wait until the next periodic timing), 904 * since the unit will never be freed until the 905 * next periodic timing. 906 */ 907 switch (fn->f_cmdstat) { 908 case MAPLE_CMDSTAT_ASYNC: 909 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC_PERIODICQ; 910 break; 911 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 912 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 913 break; 914 default: 915 break; 916 } 917 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 918 } else { 919 /* unit is busy --- try again */ 920 /* 921 * always add to async command queue 922 * (process immediately) 923 */ 924 switch (fn->f_cmdstat) { 925 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 926 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 927 break; 928 case MAPLE_CMDSTAT_PERIODIC: 929 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC_DEFERED; 930 break; 931 default: 932 break; 933 } 934 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 935 } 936 } 937 } 938 939 /* schedule probing a device */ 940 static void 941 maple_unit_probe(struct maple_softc *sc) 942 { 943 struct maple_unit *u; 944 945 if ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 946 KASSERT(u->u_dma_stat == MAPLE_DMA_IDLE); 947 KASSERT(u->u_queuestat == MAPLE_QUEUE_PROBE); 948 maple_remove_from_queues(sc, u); 949 maple_write_command(sc, u, MAPLE_COMMAND_DEVINFO, 0, NULL); 950 u->u_dma_stat = MAPLE_DMA_PROBE; 951 /* u->u_dma_func = ignored; */ 952 } 953 } 954 955 /* 956 * Enable/disable unit pinging (called by drivers) 957 */ 958 /* ARGSUSED */ 959 void 960 maple_enable_unit_ping(device_t dev, struct maple_unit *u, int func, int enable) 961 { 962 #if 0 /* currently unused */ 963 struct maple_softc *sc = device_private(dev); 964 #endif 965 966 if (enable) 967 u->u_noping &= ~MAPLE_FUNC(func); 968 else 969 u->u_noping |= MAPLE_FUNC(func); 970 } 971 972 /* schedule pinging a device */ 973 static void 974 maple_unit_ping(struct maple_softc *sc) 975 { 976 struct maple_unit *u; 977 struct maple_func *fn; 978 #ifdef MAPLE_MEMCARD_PING_HACK 979 static const uint32_t memcard_ping_arg[2] = { 980 0x02000000, /* htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD)) */ 981 0 /* pt (1 byte) and unused 3 bytes */ 982 }; 983 #endif 984 985 if ((u = TAILQ_FIRST(&sc->sc_pingq)) != NULL) { 986 KASSERT(u->u_queuestat == MAPLE_QUEUE_PING); 987 maple_remove_from_queues(sc, u); 988 if (u->u_dma_stat == MAPLE_DMA_IDLE && u->u_noping == 0) { 989 #ifdef MAPLE_MEMCARD_PING_HACK 990 if (u->u_ping_stat == MAPLE_PING_MINFO) { 991 /* use MINFO for some memory cards */ 992 maple_write_command(sc, u, 993 MAPLE_COMMAND_GETMINFO, 994 2, memcard_ping_arg); 995 } else 996 #endif 997 { 998 fn = &u->u_func[u->u_ping_func]; 999 fn->f_work = htobe32(MAPLE_FUNC(u->u_ping_func)); 1000 maple_write_command(sc, u, 1001 MAPLE_COMMAND_GETCOND, 1002 1, &fn->f_work); 1003 } 1004 u->u_dma_stat = MAPLE_DMA_PING; 1005 /* u->u_dma_func = XXX; */ 1006 } else { 1007 /* no need if periodic */ 1008 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1009 u->u_queuestat = MAPLE_QUEUE_PING; 1010 } 1011 } 1012 } 1013 1014 /* 1015 * Enable/disable periodic GETCOND (called by drivers) 1016 */ 1017 void 1018 maple_enable_periodic(device_t dev, struct maple_unit *u, int func, int on) 1019 { 1020 struct maple_softc *sc = device_private(dev); 1021 struct maple_func *fn; 1022 1023 KASSERT(func >= 0 && func < 32); 1024 1025 fn = &u->u_func[func]; 1026 1027 if (on) { 1028 if (fn->f_periodic_stat == MAPLE_PERIODIC_NONE) { 1029 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1030 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1031 u->getcond_func_set |= MAPLE_FUNC(func); 1032 } 1033 } else { 1034 if (fn->f_periodic_stat == MAPLE_PERIODIC_INQ) 1035 TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq); 1036 else if (fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED) 1037 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1038 fn->f_periodic_stat = MAPLE_PERIODIC_NONE; 1039 u->getcond_func_set &= ~MAPLE_FUNC(func); 1040 } 1041 } 1042 1043 /* 1044 * queue periodic GETCOND 1045 */ 1046 static int 1047 maple_send_defered_periodic(struct maple_softc *sc) 1048 { 1049 struct maple_unit *u; 1050 struct maple_func *fn, *nextfn; 1051 int defer_remain = 0; 1052 1053 for (fn = TAILQ_FIRST(&sc->sc_periodicdeferq); fn; fn = nextfn) { 1054 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED); 1055 1056 nextfn = TAILQ_NEXT(fn, f_periodicq); 1057 1058 u = fn->f_unit; 1059 if (u->u_dma_stat == MAPLE_DMA_IDLE || 1060 u->u_dma_stat == MAPLE_DMA_RETRY) { 1061 /* 1062 * if IDLE -> queue this request 1063 * if RETRY -> the unit never be freed until the next 1064 * periodic timing, so just restore to 1065 * the normal periodic queue. 1066 */ 1067 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1068 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1069 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1070 1071 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 1072 /* 1073 * queue periodic command 1074 */ 1075 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1076 maple_write_command(sc, u, 1077 MAPLE_COMMAND_GETCOND, 1, &fn->f_work); 1078 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1079 u->u_dma_func = fn->f_funcno; 1080 } 1081 } else { 1082 defer_remain = 1; 1083 } 1084 } 1085 1086 return defer_remain; 1087 } 1088 1089 static void 1090 maple_send_periodic(struct maple_softc *sc) 1091 { 1092 struct maple_unit *u; 1093 struct maple_func *fn, *nextfn; 1094 1095 for (fn = TAILQ_FIRST(&sc->sc_periodicq); fn; fn = nextfn) { 1096 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_INQ); 1097 1098 nextfn = TAILQ_NEXT(fn, f_periodicq); 1099 1100 u = fn->f_unit; 1101 if (u->u_dma_stat != MAPLE_DMA_IDLE) { 1102 if (u->u_dma_stat != MAPLE_DMA_RETRY) { 1103 /* 1104 * can't be queued --- move to defered queue 1105 */ 1106 TAILQ_REMOVE(&sc->sc_periodicq, fn, 1107 f_periodicq); 1108 TAILQ_INSERT_TAIL(&sc->sc_periodicdeferq, fn, 1109 f_periodicq); 1110 fn->f_periodic_stat = MAPLE_PERIODIC_DEFERED; 1111 } 1112 } else { 1113 /* 1114 * queue periodic command 1115 */ 1116 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1117 maple_write_command(sc, u, MAPLE_COMMAND_GETCOND, 1118 1, &fn->f_work); 1119 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1120 u->u_dma_func = fn->f_funcno; 1121 } 1122 } 1123 } 1124 1125 static void 1126 maple_remove_from_queues(struct maple_softc *sc, struct maple_unit *u) 1127 { 1128 1129 /* remove from queues */ 1130 if (u->u_queuestat == MAPLE_QUEUE_PROBE) 1131 TAILQ_REMOVE(&sc->sc_probeq, u, u_q); 1132 else if (u->u_queuestat == MAPLE_QUEUE_PING) 1133 TAILQ_REMOVE(&sc->sc_pingq, u, u_q); 1134 #ifdef DIAGNOSTIC 1135 else if (u->u_queuestat != MAPLE_QUEUE_NONE) 1136 panic("maple_remove_from_queues: queuestat %d", u->u_queuestat); 1137 #endif 1138 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1139 if (u->u_queuestat != MAPLE_QUEUE_NONE) { 1140 char buf[16]; 1141 printf("%s: dequeued\n", 1142 maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 1143 } 1144 #endif 1145 1146 u->u_queuestat = MAPLE_QUEUE_NONE; 1147 } 1148 1149 /* 1150 * retry current command at next periodic timing 1151 */ 1152 static int 1153 maple_retry(struct maple_softc *sc, struct maple_unit *u, 1154 enum maple_dma_stat st) 1155 { 1156 1157 KASSERT(st != MAPLE_DMA_IDLE && st != MAPLE_DMA_RETRY); 1158 1159 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1160 if (u->u_retrycnt == 0) { 1161 char buf[16]; 1162 printf("%s: retrying: %#x, %#x, %p\n", 1163 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 1164 u->u_command, u->u_datalen, u->u_dataaddr); 1165 } 1166 #endif 1167 if (u->u_retrycnt >= MAPLE_RETRY_MAX) 1168 return 1; 1169 1170 u->u_retrycnt++; 1171 1172 u->u_saved_dma_stat = st; 1173 u->u_dma_stat = MAPLE_DMA_RETRY; /* no new command before retry done */ 1174 SIMPLEQ_INSERT_TAIL(&sc->sc_retryq, u, u_dmaq); 1175 1176 return 0; 1177 } 1178 1179 static void 1180 maple_queue_retry(struct maple_softc *sc) 1181 { 1182 struct maple_unit *u, *nextu; 1183 1184 /* 1185 * Note: since the queue element is queued immediately 1186 * in maple_queue_command, we can't use SIMPLEQ_FOREACH. 1187 */ 1188 for (u = SIMPLEQ_FIRST(&sc->sc_retryq); u; u = nextu) { 1189 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1190 1191 /* 1192 * Retrying is in the highest priority, and the unit shall 1193 * always be free. 1194 */ 1195 KASSERT(u->u_dma_stat == MAPLE_DMA_RETRY); 1196 maple_queue_command(sc, u, u->u_command, u->u_datalen, 1197 u->u_dataaddr); 1198 u->u_dma_stat = u->u_saved_dma_stat; 1199 1200 #ifdef DIAGNOSTIC 1201 KASSERT(u->u_saved_dma_stat != MAPLE_DMA_IDLE); 1202 u->u_saved_dma_stat = MAPLE_DMA_IDLE; 1203 #endif 1204 } 1205 SIMPLEQ_INIT(&sc->sc_retryq); 1206 } 1207 1208 /* 1209 * Process DMA results. 1210 * Requires kernel context. 1211 */ 1212 static void 1213 maple_check_responses(struct maple_softc *sc) 1214 { 1215 struct maple_unit *u, *nextu; 1216 struct maple_func *fn; 1217 maple_response_t response; 1218 int func_code, len; 1219 int flags; 1220 char buf[16]; 1221 1222 /* 1223 * Note: since the queue element may be queued immediately, 1224 * we can't use SIMPLEQ_FOREACH. 1225 */ 1226 for (u = SIMPLEQ_FIRST(&sc->sc_dmaq), maple_begin_txbuf(sc); 1227 u; u = nextu) { 1228 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1229 1230 if (u->u_dma_stat == MAPLE_DMA_IDLE) 1231 continue; /* just detached or DDB was active */ 1232 1233 /* 1234 * check for retransmission 1235 */ 1236 if ((response = u->u_rxbuf[0]) == MAPLE_RESPONSE_AGAIN) { 1237 if (maple_retry(sc, u, u->u_dma_stat) == 0) 1238 continue; 1239 /* else pass error to upper layer */ 1240 } 1241 1242 len = (u->u_rxbuf[0] >> 24); /* length in long */ 1243 len <<= 2; /* length in byte */ 1244 1245 /* 1246 * call handler 1247 */ 1248 if (u->u_dma_stat == MAPLE_DMA_PERIODIC) { 1249 /* 1250 * periodic GETCOND 1251 */ 1252 u->u_dma_stat = MAPLE_DMA_IDLE; 1253 func_code = u->u_dma_func; 1254 if (response == MAPLE_RESPONSE_DATATRF && len > 0 && 1255 be32toh(u->u_rxbuf[1]) == MAPLE_FUNC(func_code)) { 1256 fn = &u->u_func[func_code]; 1257 if (fn->f_dev) 1258 (*fn->f_callback)(fn->f_arg, 1259 (void *)u->u_rxbuf, len, 1260 MAPLE_FLAG_PERIODIC); 1261 } else if (response == MAPLE_RESPONSE_NONE) { 1262 /* XXX OK? */ 1263 /* detach */ 1264 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1265 printf("%s: func: %d: periodic response %d\n", 1266 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 1267 u->u_dma_func, 1268 response); 1269 #endif 1270 /* 1271 * Some 3rd party devices sometimes 1272 * do not respond. 1273 */ 1274 if (maple_retry(sc, u, MAPLE_DMA_PERIODIC)) 1275 maple_detach_unit(sc, u); 1276 } 1277 /* XXX check unexpected conditions? */ 1278 1279 } else if (u->u_dma_stat == MAPLE_DMA_PROBE) { 1280 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1281 u->u_dma_stat = MAPLE_DMA_IDLE; 1282 switch (response) { 1283 default: 1284 case MAPLE_RESPONSE_NONE: 1285 /* 1286 * Do not use maple_retry(), which conflicts 1287 * with probe structure. 1288 */ 1289 if (u->subunit != 0 && 1290 ++u->u_proberetry > MAPLE_PROBERETRY_MAX) { 1291 printf("%s: no response\n", 1292 maple_unit_name(buf, sizeof(buf), 1293 u->port, u->subunit)); 1294 } else { 1295 /* probe again */ 1296 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1297 printf("%s: queued to probe 4\n", 1298 maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 1299 #endif 1300 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, 1301 u_q); 1302 u->u_queuestat = MAPLE_QUEUE_PROBE; 1303 } 1304 break; 1305 case MAPLE_RESPONSE_DEVINFO: 1306 /* check if the unit is changed */ 1307 maple_check_unit_change(sc, u); 1308 break; 1309 } 1310 1311 } else if (u->u_dma_stat == MAPLE_DMA_PING) { 1312 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1313 u->u_dma_stat = MAPLE_DMA_IDLE; 1314 switch (response) { 1315 default: 1316 case MAPLE_RESPONSE_NONE: 1317 /* 1318 * Some 3rd party devices sometimes 1319 * do not respond. 1320 */ 1321 if (maple_retry(sc, u, MAPLE_DMA_PING)) { 1322 /* detach */ 1323 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1324 printf("%s: ping response %d\n", 1325 maple_unit_name(buf, sizeof(buf), u->port, 1326 u->subunit), 1327 response); 1328 #endif 1329 #ifdef MAPLE_MEMCARD_PING_HACK 1330 if (u->u_ping_stat 1331 == MAPLE_PING_MEMCARD) { 1332 /* 1333 * The unit claims itself to be 1334 * a Visual Memory, and has 1335 * never responded to GETCOND. 1336 * Try again using MINFO, in 1337 * case it is a poorly 1338 * implemented 3rd party card. 1339 */ 1340 #ifdef MAPLE_DEBUG 1341 printf("%s: switching ping method\n", 1342 maple_unit_name(buf, sizeof(buf), 1343 u->port, u->subunit)); 1344 #endif 1345 u->u_ping_stat 1346 = MAPLE_PING_MINFO; 1347 TAILQ_INSERT_TAIL(&sc->sc_pingq, 1348 u, u_q); 1349 u->u_queuestat 1350 = MAPLE_QUEUE_PING; 1351 } else 1352 #endif /* MAPLE_MEMCARD_PING_HACK */ 1353 maple_detach_unit(sc, u); 1354 } 1355 break; 1356 case MAPLE_RESPONSE_BADCMD: 1357 case MAPLE_RESPONSE_BADFUNC: 1358 case MAPLE_RESPONSE_DATATRF: 1359 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1360 u->u_queuestat = MAPLE_QUEUE_PING; 1361 #ifdef MAPLE_MEMCARD_PING_HACK 1362 /* 1363 * If the unit responds to GETCOND, it is a 1364 * normal implementation. 1365 */ 1366 if (u->u_ping_stat == MAPLE_PING_MEMCARD) 1367 u->u_ping_stat = MAPLE_PING_NORMAL; 1368 #endif 1369 break; 1370 } 1371 1372 } else { 1373 /* 1374 * Note: Do not rely on the consistency of responses. 1375 */ 1376 1377 if (response == MAPLE_RESPONSE_NONE) { 1378 if (maple_retry(sc, u, u->u_dma_stat)) { 1379 /* detach */ 1380 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1381 printf("%s: command response %d\n", 1382 maple_unit_name(buf, sizeof(buf), u->port, 1383 u->subunit), 1384 response); 1385 #endif 1386 maple_detach_unit(sc, u); 1387 } 1388 continue; 1389 } 1390 1391 flags = (u->u_dma_stat == MAPLE_DMA_PCMD) ? 1392 MAPLE_FLAG_CMD_PERIODIC_TIMING : 0; 1393 u->u_dma_stat = MAPLE_DMA_IDLE; 1394 1395 func_code = u->u_dma_func; 1396 fn = &u->u_func[func_code]; 1397 if (fn->f_dev == NULL) { 1398 /* detached right now */ 1399 #ifdef MAPLE_DEBUG 1400 printf("%s: unknown function: function %d, response %d\n", 1401 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 1402 func_code, response); 1403 #endif 1404 continue; 1405 } 1406 if (fn->f_callback != NULL) { 1407 (*fn->f_callback)(fn->f_arg, 1408 (void *)u->u_rxbuf, len, flags); 1409 } 1410 } 1411 1412 /* 1413 * check for subunit change and schedule probing subunits 1414 */ 1415 if (u->subunit == 0 && response != MAPLE_RESPONSE_NONE && 1416 response != MAPLE_RESPONSE_AGAIN && 1417 ((int8_t *) u->u_rxbuf)[2] != sc->sc_port_unit_map[u->port]) 1418 maple_check_subunit_change(sc, u); 1419 } 1420 } 1421 1422 /* 1423 * Main Maple Bus thread 1424 */ 1425 static void 1426 maple_event_thread(void *arg) 1427 { 1428 struct maple_softc *sc = arg; 1429 unsigned cnt = 1; /* timing counter */ 1430 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1431 int noreq = 0; 1432 #endif 1433 1434 #ifdef MAPLE_DEBUG 1435 printf("%s: forked event thread, pid %d\n", 1436 device_xname(sc->sc_dev), sc->event_thread->l_proc->p_pid); 1437 #endif 1438 1439 /* begin first DMA cycle */ 1440 maple_begin_txbuf(sc); 1441 1442 sc->sc_event = 1; 1443 1444 /* OK, continue booting system */ 1445 maple_polling = 0; 1446 config_pending_decr(sc->sc_dev); 1447 1448 for (;;) { 1449 /* 1450 * queue requests 1451 */ 1452 1453 /* queue async commands */ 1454 if (!TAILQ_EMPTY(&sc->sc_acmdq)) 1455 maple_queue_cmds(sc, &sc->sc_acmdq); 1456 1457 /* send defered periodic command */ 1458 if (!TAILQ_EMPTY(&sc->sc_periodicdeferq)) 1459 maple_send_defered_periodic(sc); 1460 1461 /* queue periodic commands */ 1462 if (sc->sc_event) { 1463 /* queue commands on periodic timing */ 1464 if (!TAILQ_EMPTY(&sc->sc_pcmdq)) 1465 maple_queue_cmds(sc, &sc->sc_pcmdq); 1466 1467 /* retry */ 1468 if (!SIMPLEQ_EMPTY(&sc->sc_retryq)) 1469 maple_queue_retry(sc); 1470 1471 if ((cnt & 31) == 0) /* XXX */ 1472 maple_unit_probe(sc); 1473 cnt++; 1474 1475 maple_send_periodic(sc); 1476 if ((cnt & 7) == 0) /* XXX */ 1477 maple_unit_ping(sc); 1478 1479 /* 1480 * schedule periodic event 1481 */ 1482 sc->sc_event = 0; 1483 callout_reset(&sc->maple_callout_ch, 1484 MAPLE_CALLOUT_TICKS, maple_callout, sc); 1485 } 1486 1487 if (maple_end_txbuf(sc)) { 1488 1489 /* 1490 * start DMA 1491 */ 1492 mutex_enter(&sc->sc_dma_lock); 1493 maple_start(sc); 1494 1495 /* 1496 * wait until DMA done 1497 */ 1498 if (cv_timedwait(&sc->sc_dma_cv, &sc->sc_dma_lock, hz) 1499 == EWOULDBLOCK) { 1500 /* was DDB active? */ 1501 printf("%s: timed out\n", 1502 device_xname(sc->sc_dev)); 1503 } 1504 mutex_exit(&sc->sc_dma_lock); 1505 1506 /* 1507 * call handlers 1508 */ 1509 maple_check_responses(sc); 1510 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1511 noreq = 0; 1512 #endif 1513 } 1514 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1515 else { 1516 /* weird if occurs in succession */ 1517 #if MAPLE_DEBUG <= 2 1518 if (noreq) /* ignore first time */ 1519 #endif 1520 printf("%s: no request %d\n", 1521 device_xname(sc->sc_dev), noreq); 1522 noreq++; 1523 } 1524 #endif 1525 1526 /* 1527 * wait for an event 1528 */ 1529 mutex_enter(&sc->sc_event_lock); 1530 if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 && 1531 TAILQ_EMPTY(&sc->sc_periodicdeferq)) { 1532 if (cv_timedwait(&sc->sc_event_cv, &sc->sc_event_lock, 1533 hz) == EWOULDBLOCK) { 1534 printf("%s: event timed out\n", 1535 device_xname(sc->sc_dev)); 1536 } 1537 1538 } 1539 mutex_exit(&sc->sc_event_lock); 1540 1541 } 1542 1543 #if 0 /* maple root device can't be detached */ 1544 kthread_exit(0); 1545 /* NOTREACHED */ 1546 #endif 1547 } 1548 1549 static int 1550 maple_intr(void *arg) 1551 { 1552 struct maple_softc *sc = arg; 1553 1554 mutex_enter(&sc->sc_dma_lock); 1555 cv_broadcast(&sc->sc_dma_cv); 1556 mutex_exit(&sc->sc_dma_lock); 1557 1558 return 1; 1559 } 1560 1561 static void 1562 maple_callout(void *ctx) 1563 { 1564 struct maple_softc *sc = ctx; 1565 1566 mutex_enter(&sc->sc_event_lock); 1567 sc->sc_event = 1; /* mark as periodic event */ 1568 cv_broadcast(&sc->sc_event_cv); 1569 mutex_exit(&sc->sc_event_lock); 1570 } 1571 1572 /* 1573 * Install callback handler (called by drivers) 1574 */ 1575 /* ARGSUSED */ 1576 void 1577 maple_set_callback(device_t dev, struct maple_unit *u, int func, 1578 void (*callback)(void *, struct maple_response *, int, int), void *arg) 1579 { 1580 #if 0 /* currently unused */ 1581 struct maple_softc *sc = device_private(dev); 1582 #endif 1583 struct maple_func *fn; 1584 1585 KASSERT(func >= 0 && func < MAPLE_NFUNC); 1586 1587 fn = &u->u_func[func]; 1588 1589 fn->f_callback = callback; 1590 fn->f_arg = arg; 1591 } 1592 1593 /* 1594 * Return function definition data (called by drivers) 1595 */ 1596 uint32_t 1597 maple_get_function_data(struct maple_devinfo *devinfo, int function_code) 1598 { 1599 int i, p = 0; 1600 uint32_t func; 1601 1602 func = be32toh(devinfo->di_func); 1603 for (i = 31; i >= 0; --i) 1604 if (func & MAPLE_FUNC(i)) { 1605 if (function_code == i) 1606 return be32toh(devinfo->di_function_data[p]); 1607 else 1608 if (++p >= 3) 1609 break; 1610 } 1611 1612 return 0; 1613 } 1614 1615 /* Generic maple device interface */ 1616 1617 int 1618 mapleopen(dev_t dev, int flag, int mode, struct lwp *l) 1619 { 1620 struct maple_softc *sc; 1621 1622 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1623 if (sc == NULL) /* make sure it was attached */ 1624 return ENXIO; 1625 1626 if (MAPLEPORT(dev) >= MAPLE_PORTS) 1627 return ENXIO; 1628 1629 if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS) 1630 return ENXIO; 1631 1632 if (!(sc->sc_port_units[MAPLEPORT(dev)] & (1 << MAPLESUBUNIT(dev)))) 1633 return ENXIO; 1634 1635 sc->sc_port_units_open[MAPLEPORT(dev)] |= 1 << MAPLESUBUNIT(dev); 1636 1637 return 0; 1638 } 1639 1640 int 1641 mapleclose(dev_t dev, int flag, int mode, struct lwp *l) 1642 { 1643 struct maple_softc *sc; 1644 1645 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1646 1647 sc->sc_port_units_open[MAPLEPORT(dev)] &= ~(1 << MAPLESUBUNIT(dev)); 1648 1649 return 0; 1650 } 1651 1652 int 1653 maple_unit_ioctl(device_t dev, struct maple_unit *u, u_long cmd, 1654 void *data, int flag, struct lwp *l) 1655 { 1656 struct maple_softc *sc = device_private(dev); 1657 1658 if (!(sc->sc_port_units[u->port] & (1 << u->subunit))) 1659 return ENXIO; 1660 1661 switch(cmd) { 1662 case MAPLEIO_GDEVINFO: 1663 memcpy(data, &u->devinfo, sizeof(struct maple_devinfo)); 1664 break; 1665 default: 1666 return EPASSTHROUGH; 1667 } 1668 1669 return 0; 1670 } 1671 1672 int 1673 mapleioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1674 { 1675 struct maple_softc *sc; 1676 struct maple_unit *u; 1677 1678 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1679 u = &sc->sc_unit[MAPLEPORT(dev)][MAPLESUBUNIT(dev)]; 1680 1681 return maple_unit_ioctl(sc->sc_dev, u, cmd, data, flag, l); 1682 } 1683