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