1 /* $NetBSD: maple.c,v 1.52 2015/12/06 02:04:10 tsutsui 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.52 2015/12/06 02:04:10 tsutsui 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 maple_polling = 1; 250 maple_scanbus(sc); 251 252 mutex_init(&sc->sc_dma_lock, MUTEX_DEFAULT, IPL_MAPLE); 253 cv_init(&sc->sc_dma_cv, device_xname(self)); 254 mutex_init(&sc->sc_event_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK); 255 cv_init(&sc->sc_event_cv, device_xname(self)); 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 = config_found_sm_loc(sc->sc_dev, 704 "maple", NULL, &ma, mapleprint, maplesubmatch); 705 u->u_ping_func = f; /* XXX using largest func */ 706 } 707 } 708 #ifdef MAPLE_MEMCARD_PING_HACK 709 /* 710 * Some 3rd party memory card pretend to be Visual Memory, 711 * but need special handling for ping. 712 */ 713 if (func == (MAPLE_FUNC(MAPLE_FN_MEMCARD) | MAPLE_FUNC(MAPLE_FN_LCD) | 714 MAPLE_FUNC(MAPLE_FN_CLOCK))) { 715 u->u_ping_func = MAPLE_FN_MEMCARD; 716 u->u_ping_stat = MAPLE_PING_MEMCARD; 717 } else { 718 u->u_ping_stat = MAPLE_PING_NORMAL; 719 } 720 #endif 721 strcpy(sc->sc_dev->dv_xname, oldxname); 722 723 sc->sc_port_units[u->port] |= 1 << u->subunit; 724 } 725 726 static void 727 maple_detach_unit_nofix(struct maple_softc *sc, struct maple_unit *u) 728 { 729 struct maple_func *fn; 730 device_t dev; 731 struct maple_unit *u1; 732 int port; 733 int error; 734 int i; 735 char buf[16]; 736 737 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 738 printf("%s: remove\n", maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 739 #endif 740 maple_remove_from_queues(sc, u); 741 port = u->port; 742 sc->sc_port_units[port] &= ~(1 << u->subunit); 743 744 if (u->subunit == 0) { 745 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 746 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 747 } 748 749 for (fn = u->u_func; fn < &u->u_func[MAPLE_NFUNC]; fn++) { 750 if ((dev = fn->f_dev) != NULL) { 751 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 752 printf("%s: detaching func %d\n", 753 maple_unit_name(buf, sizeof(buf), port, u->subunit), 754 fn->f_funcno); 755 #endif 756 757 /* 758 * Remove functions from command queue. 759 */ 760 switch (fn->f_cmdstat) { 761 case MAPLE_CMDSTAT_ASYNC: 762 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 763 TAILQ_REMOVE(&sc->sc_acmdq, fn, f_cmdq); 764 break; 765 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 766 case MAPLE_CMDSTAT_PERIODIC: 767 TAILQ_REMOVE(&sc->sc_pcmdq, fn, f_cmdq); 768 break; 769 default: 770 break; 771 } 772 773 /* 774 * Detach devices. 775 */ 776 if ((error = config_detach(fn->f_dev, DETACH_FORCE))) { 777 printf("%s: failed to detach %s (func %d), errno %d\n", 778 maple_unit_name(buf, sizeof(buf), port, u->subunit), 779 device_xname(fn->f_dev), fn->f_funcno, error); 780 } 781 } 782 783 maple_enable_periodic(sc->sc_dev, u, fn->f_funcno, 0); 784 785 fn->f_dev = NULL; 786 fn->f_callback = NULL; 787 fn->f_arg = NULL; 788 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 789 } 790 if (u->u_dma_stat == MAPLE_DMA_RETRY) { 791 /* XXX expensive? */ 792 SIMPLEQ_FOREACH(u1, &sc->sc_retryq, u_dmaq) { 793 if (u1 == u) { 794 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 795 printf("%s: abort retry\n", 796 maple_unit_name(buf, sizeof(buf), port, u->subunit)); 797 #endif 798 SIMPLEQ_REMOVE(&sc->sc_retryq, u, maple_unit, 799 u_dmaq); 800 break; 801 } 802 } 803 } 804 u->u_dma_stat = MAPLE_DMA_IDLE; 805 u->u_noping = 0; 806 /* u->u_dma_func = uninitialized; */ 807 KASSERT(u->getcond_func_set == 0); 808 memset(&u->devinfo, 0, sizeof(struct maple_devinfo)); 809 810 if (u->subunit == 0) { 811 sc->sc_port_unit_map[port] = 0; 812 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 813 { 814 char buf2[16]; 815 printf("%s: queued to probe 3\n", 816 maple_unit_name(buf2, sizeof(buf2), port, u->subunit)); 817 } 818 #endif 819 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 820 u->u_queuestat = MAPLE_QUEUE_PROBE; 821 } 822 } 823 824 static void 825 maple_detach_unit(struct maple_softc *sc, struct maple_unit *u) 826 { 827 828 maple_detach_unit_nofix(sc, u); 829 if (u->subunit != 0) 830 sc->sc_port_unit_map[u->port] &= ~(1 << (u->subunit - 1)); 831 } 832 833 /* 834 * Send a command (called by drivers) 835 * 836 * The "cataaddr" must not point at temporary storage like stack. 837 * Only one command (per function) is valid at a time. 838 */ 839 void 840 maple_command(device_t dev, struct maple_unit *u, int func, 841 int command, int datalen, const void *dataaddr, int flags) 842 { 843 struct maple_softc *sc = device_private(dev); 844 struct maple_func *fn; 845 846 KASSERT(func >= 0 && func < 32); 847 KASSERT(command); 848 KASSERT((flags & ~MAPLE_FLAG_CMD_PERIODIC_TIMING) == 0); 849 850 mutex_enter(&sc->sc_event_lock); 851 852 fn = &u->u_func[func]; 853 #if 1 /*def DIAGNOSTIC*/ 854 {char buf[16]; 855 if (fn->f_cmdstat != MAPLE_CMDSTAT_NONE) 856 panic("maple_command: %s func %d: requesting more than one commands", 857 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), func); 858 } 859 #endif 860 fn->f_command = command; 861 fn->f_datalen = datalen; 862 fn->f_dataaddr = dataaddr; 863 if (flags & MAPLE_FLAG_CMD_PERIODIC_TIMING) { 864 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 865 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 866 } else { 867 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 868 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 869 cv_broadcast(&sc->sc_event_cv); /* wake for async event */ 870 } 871 mutex_exit(&sc->sc_event_lock); 872 } 873 874 static void 875 maple_queue_cmds(struct maple_softc *sc, 876 struct maple_cmdq_head *head) 877 { 878 struct maple_func *fn, *nextfn; 879 struct maple_unit *u; 880 881 /* 882 * Note: since the queue element may be queued immediately, 883 * we can't use TAILQ_FOREACH. 884 */ 885 fn = TAILQ_FIRST(head); 886 TAILQ_INIT(head); 887 for ( ; fn; fn = nextfn) { 888 nextfn = TAILQ_NEXT(fn, f_cmdq); 889 890 KASSERT(fn->f_cmdstat != MAPLE_CMDSTAT_NONE); 891 u = fn->f_unit; 892 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 893 maple_write_command(sc, u, 894 fn->f_command, fn->f_datalen, fn->f_dataaddr); 895 u->u_dma_stat = (fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC || 896 fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC_PERIODICQ) ? 897 MAPLE_DMA_ACMD : MAPLE_DMA_PCMD; 898 u->u_dma_func = fn->f_funcno; 899 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 900 } else if (u->u_dma_stat == MAPLE_DMA_RETRY) { 901 /* unit is busy --- try again */ 902 /* 903 * always add to periodic command queue 904 * (wait until the next periodic timing), 905 * since the unit will never be freed until the 906 * next periodic timing. 907 */ 908 switch (fn->f_cmdstat) { 909 case MAPLE_CMDSTAT_ASYNC: 910 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC_PERIODICQ; 911 break; 912 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 913 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 914 break; 915 default: 916 break; 917 } 918 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 919 } else { 920 /* unit is busy --- try again */ 921 /* 922 * always add to async command queue 923 * (process immediately) 924 */ 925 switch (fn->f_cmdstat) { 926 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 927 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 928 break; 929 case MAPLE_CMDSTAT_PERIODIC: 930 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC_DEFERED; 931 break; 932 default: 933 break; 934 } 935 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 936 } 937 } 938 } 939 940 /* schedule probing a device */ 941 static void 942 maple_unit_probe(struct maple_softc *sc) 943 { 944 struct maple_unit *u; 945 946 if ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 947 KASSERT(u->u_dma_stat == MAPLE_DMA_IDLE); 948 KASSERT(u->u_queuestat == MAPLE_QUEUE_PROBE); 949 maple_remove_from_queues(sc, u); 950 maple_write_command(sc, u, MAPLE_COMMAND_DEVINFO, 0, NULL); 951 u->u_dma_stat = MAPLE_DMA_PROBE; 952 /* u->u_dma_func = ignored; */ 953 } 954 } 955 956 /* 957 * Enable/disable unit pinging (called by drivers) 958 */ 959 /* ARGSUSED */ 960 void 961 maple_enable_unit_ping(device_t dev, struct maple_unit *u, int func, int enable) 962 { 963 #if 0 /* currently unused */ 964 struct maple_softc *sc = device_private(dev); 965 #endif 966 967 if (enable) 968 u->u_noping &= ~MAPLE_FUNC(func); 969 else 970 u->u_noping |= MAPLE_FUNC(func); 971 } 972 973 /* schedule pinging a device */ 974 static void 975 maple_unit_ping(struct maple_softc *sc) 976 { 977 struct maple_unit *u; 978 struct maple_func *fn; 979 #ifdef MAPLE_MEMCARD_PING_HACK 980 static const uint32_t memcard_ping_arg[2] = { 981 0x02000000, /* htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD)) */ 982 0 /* pt (1 byte) and unused 3 bytes */ 983 }; 984 #endif 985 986 if ((u = TAILQ_FIRST(&sc->sc_pingq)) != NULL) { 987 KASSERT(u->u_queuestat == MAPLE_QUEUE_PING); 988 maple_remove_from_queues(sc, u); 989 if (u->u_dma_stat == MAPLE_DMA_IDLE && u->u_noping == 0) { 990 #ifdef MAPLE_MEMCARD_PING_HACK 991 if (u->u_ping_stat == MAPLE_PING_MINFO) { 992 /* use MINFO for some memory cards */ 993 maple_write_command(sc, u, 994 MAPLE_COMMAND_GETMINFO, 995 2, memcard_ping_arg); 996 } else 997 #endif 998 { 999 fn = &u->u_func[u->u_ping_func]; 1000 fn->f_work = htobe32(MAPLE_FUNC(u->u_ping_func)); 1001 maple_write_command(sc, u, 1002 MAPLE_COMMAND_GETCOND, 1003 1, &fn->f_work); 1004 } 1005 u->u_dma_stat = MAPLE_DMA_PING; 1006 /* u->u_dma_func = XXX; */ 1007 } else { 1008 /* no need if periodic */ 1009 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1010 u->u_queuestat = MAPLE_QUEUE_PING; 1011 } 1012 } 1013 } 1014 1015 /* 1016 * Enable/disable periodic GETCOND (called by drivers) 1017 */ 1018 void 1019 maple_enable_periodic(device_t dev, struct maple_unit *u, int func, int on) 1020 { 1021 struct maple_softc *sc = device_private(dev); 1022 struct maple_func *fn; 1023 1024 KASSERT(func >= 0 && func < 32); 1025 1026 fn = &u->u_func[func]; 1027 1028 if (on) { 1029 if (fn->f_periodic_stat == MAPLE_PERIODIC_NONE) { 1030 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1031 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1032 u->getcond_func_set |= MAPLE_FUNC(func); 1033 } 1034 } else { 1035 if (fn->f_periodic_stat == MAPLE_PERIODIC_INQ) 1036 TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq); 1037 else if (fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED) 1038 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1039 fn->f_periodic_stat = MAPLE_PERIODIC_NONE; 1040 u->getcond_func_set &= ~MAPLE_FUNC(func); 1041 } 1042 } 1043 1044 /* 1045 * queue periodic GETCOND 1046 */ 1047 static int 1048 maple_send_defered_periodic(struct maple_softc *sc) 1049 { 1050 struct maple_unit *u; 1051 struct maple_func *fn, *nextfn; 1052 int defer_remain = 0; 1053 1054 for (fn = TAILQ_FIRST(&sc->sc_periodicdeferq); fn; fn = nextfn) { 1055 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED); 1056 1057 nextfn = TAILQ_NEXT(fn, f_periodicq); 1058 1059 u = fn->f_unit; 1060 if (u->u_dma_stat == MAPLE_DMA_IDLE || 1061 u->u_dma_stat == MAPLE_DMA_RETRY) { 1062 /* 1063 * if IDLE -> queue this request 1064 * if RETRY -> the unit never be freed until the next 1065 * periodic timing, so just restore to 1066 * the normal periodic queue. 1067 */ 1068 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1069 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1070 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1071 1072 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 1073 /* 1074 * queue periodic command 1075 */ 1076 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1077 maple_write_command(sc, u, 1078 MAPLE_COMMAND_GETCOND, 1, &fn->f_work); 1079 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1080 u->u_dma_func = fn->f_funcno; 1081 } 1082 } else { 1083 defer_remain = 1; 1084 } 1085 } 1086 1087 return defer_remain; 1088 } 1089 1090 static void 1091 maple_send_periodic(struct maple_softc *sc) 1092 { 1093 struct maple_unit *u; 1094 struct maple_func *fn, *nextfn; 1095 1096 for (fn = TAILQ_FIRST(&sc->sc_periodicq); fn; fn = nextfn) { 1097 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_INQ); 1098 1099 nextfn = TAILQ_NEXT(fn, f_periodicq); 1100 1101 u = fn->f_unit; 1102 if (u->u_dma_stat != MAPLE_DMA_IDLE) { 1103 if (u->u_dma_stat != MAPLE_DMA_RETRY) { 1104 /* 1105 * can't be queued --- move to defered queue 1106 */ 1107 TAILQ_REMOVE(&sc->sc_periodicq, fn, 1108 f_periodicq); 1109 TAILQ_INSERT_TAIL(&sc->sc_periodicdeferq, fn, 1110 f_periodicq); 1111 fn->f_periodic_stat = MAPLE_PERIODIC_DEFERED; 1112 } 1113 } else { 1114 /* 1115 * queue periodic command 1116 */ 1117 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1118 maple_write_command(sc, u, MAPLE_COMMAND_GETCOND, 1119 1, &fn->f_work); 1120 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1121 u->u_dma_func = fn->f_funcno; 1122 } 1123 } 1124 } 1125 1126 static void 1127 maple_remove_from_queues(struct maple_softc *sc, struct maple_unit *u) 1128 { 1129 1130 /* remove from queues */ 1131 if (u->u_queuestat == MAPLE_QUEUE_PROBE) 1132 TAILQ_REMOVE(&sc->sc_probeq, u, u_q); 1133 else if (u->u_queuestat == MAPLE_QUEUE_PING) 1134 TAILQ_REMOVE(&sc->sc_pingq, u, u_q); 1135 #ifdef DIAGNOSTIC 1136 else if (u->u_queuestat != MAPLE_QUEUE_NONE) 1137 panic("maple_remove_from_queues: queuestat %d", u->u_queuestat); 1138 #endif 1139 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1140 if (u->u_queuestat != MAPLE_QUEUE_NONE) { 1141 char buf[16]; 1142 printf("%s: dequeued\n", 1143 maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 1144 } 1145 #endif 1146 1147 u->u_queuestat = MAPLE_QUEUE_NONE; 1148 } 1149 1150 /* 1151 * retry current command at next periodic timing 1152 */ 1153 static int 1154 maple_retry(struct maple_softc *sc, struct maple_unit *u, 1155 enum maple_dma_stat st) 1156 { 1157 1158 KASSERT(st != MAPLE_DMA_IDLE && st != MAPLE_DMA_RETRY); 1159 1160 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1161 if (u->u_retrycnt == 0) { 1162 char buf[16]; 1163 printf("%s: retrying: %#x, %#x, %p\n", 1164 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 1165 u->u_command, u->u_datalen, u->u_dataaddr); 1166 } 1167 #endif 1168 if (u->u_retrycnt >= MAPLE_RETRY_MAX) 1169 return 1; 1170 1171 u->u_retrycnt++; 1172 1173 u->u_saved_dma_stat = st; 1174 u->u_dma_stat = MAPLE_DMA_RETRY; /* no new command before retry done */ 1175 SIMPLEQ_INSERT_TAIL(&sc->sc_retryq, u, u_dmaq); 1176 1177 return 0; 1178 } 1179 1180 static void 1181 maple_queue_retry(struct maple_softc *sc) 1182 { 1183 struct maple_unit *u, *nextu; 1184 1185 /* 1186 * Note: since the queue element is queued immediately 1187 * in maple_queue_command, we can't use SIMPLEQ_FOREACH. 1188 */ 1189 for (u = SIMPLEQ_FIRST(&sc->sc_retryq); u; u = nextu) { 1190 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1191 1192 /* 1193 * Retrying is in the highest priority, and the unit shall 1194 * always be free. 1195 */ 1196 KASSERT(u->u_dma_stat == MAPLE_DMA_RETRY); 1197 maple_queue_command(sc, u, u->u_command, u->u_datalen, 1198 u->u_dataaddr); 1199 u->u_dma_stat = u->u_saved_dma_stat; 1200 1201 #ifdef DIAGNOSTIC 1202 KASSERT(u->u_saved_dma_stat != MAPLE_DMA_IDLE); 1203 u->u_saved_dma_stat = MAPLE_DMA_IDLE; 1204 #endif 1205 } 1206 SIMPLEQ_INIT(&sc->sc_retryq); 1207 } 1208 1209 /* 1210 * Process DMA results. 1211 * Requires kernel context. 1212 */ 1213 static void 1214 maple_check_responses(struct maple_softc *sc) 1215 { 1216 struct maple_unit *u, *nextu; 1217 struct maple_func *fn; 1218 maple_response_t response; 1219 int func_code, len; 1220 int flags; 1221 char buf[16]; 1222 1223 /* 1224 * Note: since the queue element may be queued immediately, 1225 * we can't use SIMPLEQ_FOREACH. 1226 */ 1227 for (u = SIMPLEQ_FIRST(&sc->sc_dmaq), maple_begin_txbuf(sc); 1228 u; u = nextu) { 1229 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1230 1231 if (u->u_dma_stat == MAPLE_DMA_IDLE) 1232 continue; /* just detached or DDB was active */ 1233 1234 /* 1235 * check for retransmission 1236 */ 1237 if ((response = u->u_rxbuf[0]) == MAPLE_RESPONSE_AGAIN) { 1238 if (maple_retry(sc, u, u->u_dma_stat) == 0) 1239 continue; 1240 /* else pass error to upper layer */ 1241 } 1242 1243 len = (u->u_rxbuf[0] >> 24); /* length in long */ 1244 len <<= 2; /* length in byte */ 1245 1246 /* 1247 * call handler 1248 */ 1249 if (u->u_dma_stat == MAPLE_DMA_PERIODIC) { 1250 /* 1251 * periodic GETCOND 1252 */ 1253 u->u_dma_stat = MAPLE_DMA_IDLE; 1254 func_code = u->u_dma_func; 1255 if (response == MAPLE_RESPONSE_DATATRF && len > 0 && 1256 be32toh(u->u_rxbuf[1]) == MAPLE_FUNC(func_code)) { 1257 fn = &u->u_func[func_code]; 1258 if (fn->f_dev) 1259 (*fn->f_callback)(fn->f_arg, 1260 (void *)u->u_rxbuf, len, 1261 MAPLE_FLAG_PERIODIC); 1262 } else if (response == MAPLE_RESPONSE_NONE) { 1263 /* XXX OK? */ 1264 /* detach */ 1265 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1266 printf("%s: func: %d: periodic response %d\n", 1267 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 1268 u->u_dma_func, 1269 response); 1270 #endif 1271 /* 1272 * Some 3rd party devices sometimes 1273 * do not respond. 1274 */ 1275 if (maple_retry(sc, u, MAPLE_DMA_PERIODIC)) 1276 maple_detach_unit(sc, u); 1277 } 1278 /* XXX check unexpected conditions? */ 1279 1280 } else if (u->u_dma_stat == MAPLE_DMA_PROBE) { 1281 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1282 u->u_dma_stat = MAPLE_DMA_IDLE; 1283 switch (response) { 1284 default: 1285 case MAPLE_RESPONSE_NONE: 1286 /* 1287 * Do not use maple_retry(), which conflicts 1288 * with probe structure. 1289 */ 1290 if (u->subunit != 0 && 1291 ++u->u_proberetry > MAPLE_PROBERETRY_MAX) { 1292 printf("%s: no response\n", 1293 maple_unit_name(buf, sizeof(buf), 1294 u->port, u->subunit)); 1295 } else { 1296 /* probe again */ 1297 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1298 printf("%s: queued to probe 4\n", 1299 maple_unit_name(buf, sizeof(buf), u->port, u->subunit)); 1300 #endif 1301 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, 1302 u_q); 1303 u->u_queuestat = MAPLE_QUEUE_PROBE; 1304 } 1305 break; 1306 case MAPLE_RESPONSE_DEVINFO: 1307 /* check if the unit is changed */ 1308 maple_check_unit_change(sc, u); 1309 break; 1310 } 1311 1312 } else if (u->u_dma_stat == MAPLE_DMA_PING) { 1313 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1314 u->u_dma_stat = MAPLE_DMA_IDLE; 1315 switch (response) { 1316 default: 1317 case MAPLE_RESPONSE_NONE: 1318 /* 1319 * Some 3rd party devices sometimes 1320 * do not respond. 1321 */ 1322 if (maple_retry(sc, u, MAPLE_DMA_PING)) { 1323 /* detach */ 1324 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1325 printf("%s: ping response %d\n", 1326 maple_unit_name(buf, sizeof(buf), u->port, 1327 u->subunit), 1328 response); 1329 #endif 1330 #ifdef MAPLE_MEMCARD_PING_HACK 1331 if (u->u_ping_stat 1332 == MAPLE_PING_MEMCARD) { 1333 /* 1334 * The unit claims itself to be 1335 * a Visual Memory, and has 1336 * never responded to GETCOND. 1337 * Try again using MINFO, in 1338 * case it is a poorly 1339 * implemented 3rd party card. 1340 */ 1341 #ifdef MAPLE_DEBUG 1342 printf("%s: switching ping method\n", 1343 maple_unit_name(buf, sizeof(buf), 1344 u->port, u->subunit)); 1345 #endif 1346 u->u_ping_stat 1347 = MAPLE_PING_MINFO; 1348 TAILQ_INSERT_TAIL(&sc->sc_pingq, 1349 u, u_q); 1350 u->u_queuestat 1351 = MAPLE_QUEUE_PING; 1352 } else 1353 #endif /* MAPLE_MEMCARD_PING_HACK */ 1354 maple_detach_unit(sc, u); 1355 } 1356 break; 1357 case MAPLE_RESPONSE_BADCMD: 1358 case MAPLE_RESPONSE_BADFUNC: 1359 case MAPLE_RESPONSE_DATATRF: 1360 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1361 u->u_queuestat = MAPLE_QUEUE_PING; 1362 #ifdef MAPLE_MEMCARD_PING_HACK 1363 /* 1364 * If the unit responds to GETCOND, it is a 1365 * normal implementation. 1366 */ 1367 if (u->u_ping_stat == MAPLE_PING_MEMCARD) 1368 u->u_ping_stat = MAPLE_PING_NORMAL; 1369 #endif 1370 break; 1371 } 1372 1373 } else { 1374 /* 1375 * Note: Do not rely on the consistency of responses. 1376 */ 1377 1378 if (response == MAPLE_RESPONSE_NONE) { 1379 if (maple_retry(sc, u, u->u_dma_stat)) { 1380 /* detach */ 1381 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1382 printf("%s: command response %d\n", 1383 maple_unit_name(buf, sizeof(buf), u->port, 1384 u->subunit), 1385 response); 1386 #endif 1387 maple_detach_unit(sc, u); 1388 } 1389 continue; 1390 } 1391 1392 flags = (u->u_dma_stat == MAPLE_DMA_PCMD) ? 1393 MAPLE_FLAG_CMD_PERIODIC_TIMING : 0; 1394 u->u_dma_stat = MAPLE_DMA_IDLE; 1395 1396 func_code = u->u_dma_func; 1397 fn = &u->u_func[func_code]; 1398 if (fn->f_dev == NULL) { 1399 /* detached right now */ 1400 #ifdef MAPLE_DEBUG 1401 printf("%s: unknown function: function %d, response %d\n", 1402 maple_unit_name(buf, sizeof(buf), u->port, u->subunit), 1403 func_code, response); 1404 #endif 1405 continue; 1406 } 1407 if (fn->f_callback != NULL) { 1408 (*fn->f_callback)(fn->f_arg, 1409 (void *)u->u_rxbuf, len, flags); 1410 } 1411 } 1412 1413 /* 1414 * check for subunit change and schedule probing subunits 1415 */ 1416 if (u->subunit == 0 && response != MAPLE_RESPONSE_NONE && 1417 response != MAPLE_RESPONSE_AGAIN && 1418 ((int8_t *) u->u_rxbuf)[2] != sc->sc_port_unit_map[u->port]) 1419 maple_check_subunit_change(sc, u); 1420 } 1421 } 1422 1423 /* 1424 * Main Maple Bus thread 1425 */ 1426 static void 1427 maple_event_thread(void *arg) 1428 { 1429 struct maple_softc *sc = arg; 1430 unsigned cnt = 1; /* timing counter */ 1431 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1432 int noreq = 0; 1433 #endif 1434 1435 #ifdef MAPLE_DEBUG 1436 printf("%s: forked event thread, pid %d\n", 1437 device_xname(sc->sc_dev), sc->event_thread->l_proc->p_pid); 1438 #endif 1439 1440 /* begin first DMA cycle */ 1441 maple_begin_txbuf(sc); 1442 1443 sc->sc_event = 1; 1444 1445 /* OK, continue booting system */ 1446 maple_polling = 0; 1447 config_pending_decr(sc->sc_dev); 1448 1449 for (;;) { 1450 /* 1451 * queue requests 1452 */ 1453 1454 /* queue async commands */ 1455 if (!TAILQ_EMPTY(&sc->sc_acmdq)) 1456 maple_queue_cmds(sc, &sc->sc_acmdq); 1457 1458 /* send defered periodic command */ 1459 if (!TAILQ_EMPTY(&sc->sc_periodicdeferq)) 1460 maple_send_defered_periodic(sc); 1461 1462 /* queue periodic commands */ 1463 if (sc->sc_event) { 1464 /* queue commands on periodic timing */ 1465 if (!TAILQ_EMPTY(&sc->sc_pcmdq)) 1466 maple_queue_cmds(sc, &sc->sc_pcmdq); 1467 1468 /* retry */ 1469 if (!SIMPLEQ_EMPTY(&sc->sc_retryq)) 1470 maple_queue_retry(sc); 1471 1472 if ((cnt & 31) == 0) /* XXX */ 1473 maple_unit_probe(sc); 1474 cnt++; 1475 1476 maple_send_periodic(sc); 1477 if ((cnt & 7) == 0) /* XXX */ 1478 maple_unit_ping(sc); 1479 1480 /* 1481 * schedule periodic event 1482 */ 1483 sc->sc_event = 0; 1484 callout_reset(&sc->maple_callout_ch, 1485 MAPLE_CALLOUT_TICKS, maple_callout, sc); 1486 } 1487 1488 if (maple_end_txbuf(sc)) { 1489 1490 /* 1491 * start DMA 1492 */ 1493 mutex_enter(&sc->sc_dma_lock); 1494 maple_start(sc); 1495 1496 /* 1497 * wait until DMA done 1498 */ 1499 if (cv_timedwait(&sc->sc_dma_cv, &sc->sc_dma_lock, hz) 1500 == EWOULDBLOCK) { 1501 /* was DDB active? */ 1502 printf("%s: timed out\n", 1503 device_xname(sc->sc_dev)); 1504 } 1505 mutex_exit(&sc->sc_dma_lock); 1506 1507 /* 1508 * call handlers 1509 */ 1510 maple_check_responses(sc); 1511 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1512 noreq = 0; 1513 #endif 1514 } 1515 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1516 else { 1517 /* weird if occurs in succession */ 1518 #if MAPLE_DEBUG <= 2 1519 if (noreq) /* ignore first time */ 1520 #endif 1521 printf("%s: no request %d\n", 1522 device_xname(sc->sc_dev), noreq); 1523 noreq++; 1524 } 1525 #endif 1526 1527 /* 1528 * wait for an event 1529 */ 1530 mutex_enter(&sc->sc_event_lock); 1531 if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 && 1532 TAILQ_EMPTY(&sc->sc_periodicdeferq)) { 1533 if (cv_timedwait(&sc->sc_event_cv, &sc->sc_event_lock, 1534 hz) == EWOULDBLOCK) { 1535 printf("%s: event timed out\n", 1536 device_xname(sc->sc_dev)); 1537 } 1538 1539 } 1540 mutex_exit(&sc->sc_event_lock); 1541 1542 } 1543 1544 #if 0 /* maple root device can't be detached */ 1545 kthread_exit(0); 1546 /* NOTREACHED */ 1547 #endif 1548 } 1549 1550 static int 1551 maple_intr(void *arg) 1552 { 1553 struct maple_softc *sc = arg; 1554 1555 mutex_enter(&sc->sc_dma_lock); 1556 cv_broadcast(&sc->sc_dma_cv); 1557 mutex_exit(&sc->sc_dma_lock); 1558 1559 return 1; 1560 } 1561 1562 static void 1563 maple_callout(void *ctx) 1564 { 1565 struct maple_softc *sc = ctx; 1566 1567 mutex_enter(&sc->sc_event_lock); 1568 sc->sc_event = 1; /* mark as periodic event */ 1569 cv_broadcast(&sc->sc_event_cv); 1570 mutex_exit(&sc->sc_event_lock); 1571 } 1572 1573 /* 1574 * Install callback handler (called by drivers) 1575 */ 1576 /* ARGSUSED */ 1577 void 1578 maple_set_callback(device_t dev, struct maple_unit *u, int func, 1579 void (*callback)(void *, struct maple_response *, int, int), void *arg) 1580 { 1581 #if 0 /* currently unused */ 1582 struct maple_softc *sc = device_private(dev); 1583 #endif 1584 struct maple_func *fn; 1585 1586 KASSERT(func >= 0 && func < MAPLE_NFUNC); 1587 1588 fn = &u->u_func[func]; 1589 1590 fn->f_callback = callback; 1591 fn->f_arg = arg; 1592 } 1593 1594 /* 1595 * Return function definition data (called by drivers) 1596 */ 1597 uint32_t 1598 maple_get_function_data(struct maple_devinfo *devinfo, int function_code) 1599 { 1600 int i, p = 0; 1601 uint32_t func; 1602 1603 func = be32toh(devinfo->di_func); 1604 for (i = 31; i >= 0; --i) 1605 if (func & MAPLE_FUNC(i)) { 1606 if (function_code == i) 1607 return be32toh(devinfo->di_function_data[p]); 1608 else 1609 if (++p >= 3) 1610 break; 1611 } 1612 1613 return 0; 1614 } 1615 1616 /* Generic maple device interface */ 1617 1618 int 1619 mapleopen(dev_t dev, int flag, int mode, struct lwp *l) 1620 { 1621 struct maple_softc *sc; 1622 1623 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1624 if (sc == NULL) /* make sure it was attached */ 1625 return ENXIO; 1626 1627 if (MAPLEPORT(dev) >= MAPLE_PORTS) 1628 return ENXIO; 1629 1630 if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS) 1631 return ENXIO; 1632 1633 if (!(sc->sc_port_units[MAPLEPORT(dev)] & (1 << MAPLESUBUNIT(dev)))) 1634 return ENXIO; 1635 1636 sc->sc_port_units_open[MAPLEPORT(dev)] |= 1 << MAPLESUBUNIT(dev); 1637 1638 return 0; 1639 } 1640 1641 int 1642 mapleclose(dev_t dev, int flag, int mode, struct lwp *l) 1643 { 1644 struct maple_softc *sc; 1645 1646 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1647 1648 sc->sc_port_units_open[MAPLEPORT(dev)] &= ~(1 << MAPLESUBUNIT(dev)); 1649 1650 return 0; 1651 } 1652 1653 int 1654 maple_unit_ioctl(device_t dev, struct maple_unit *u, u_long cmd, 1655 void *data, int flag, struct lwp *l) 1656 { 1657 struct maple_softc *sc = device_private(dev); 1658 1659 if (!(sc->sc_port_units[u->port] & (1 << u->subunit))) 1660 return ENXIO; 1661 1662 switch(cmd) { 1663 case MAPLEIO_GDEVINFO: 1664 memcpy(data, &u->devinfo, sizeof(struct maple_devinfo)); 1665 break; 1666 default: 1667 return EPASSTHROUGH; 1668 } 1669 1670 return 0; 1671 } 1672 1673 int 1674 mapleioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1675 { 1676 struct maple_softc *sc; 1677 struct maple_unit *u; 1678 1679 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1680 u = &sc->sc_unit[MAPLEPORT(dev)][MAPLESUBUNIT(dev)]; 1681 1682 return maple_unit_ioctl(sc->sc_dev, u, cmd, data, flag, l); 1683 } 1684