1 /* $NetBSD: maple.c,v 1.31 2005/12/11 12:17:06 christos 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 2001 Marcus Comstedt 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by Marcus Comstedt. 54 * 4. Neither the name of The NetBSD Foundation nor the names of its 55 * contributors may be used to endorse or promote products derived 56 * from this software without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 59 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 60 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 61 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 62 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 64 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 65 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 66 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 67 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 68 * POSSIBILITY OF SUCH DAMAGE. 69 */ 70 71 #include <sys/cdefs.h> 72 __KERNEL_RCSID(0, "$NetBSD: maple.c,v 1.31 2005/12/11 12:17:06 christos Exp $"); 73 74 #include <sys/param.h> 75 #include <sys/device.h> 76 #include <sys/fcntl.h> 77 #include <sys/kernel.h> 78 #include <sys/kthread.h> 79 #include <sys/poll.h> 80 #include <sys/select.h> 81 #include <sys/proc.h> 82 #include <sys/signalvar.h> 83 #include <sys/systm.h> 84 #include <sys/conf.h> 85 86 #include <uvm/uvm_extern.h> 87 88 #include <machine/cpu.h> 89 #include <machine/bus.h> 90 #include <machine/sysasicvar.h> 91 #include <sh3/pmap.h> 92 93 #include <dreamcast/dev/maple/maple.h> 94 #include <dreamcast/dev/maple/mapleconf.h> 95 #include <dreamcast/dev/maple/maplevar.h> 96 #include <dreamcast/dev/maple/maplereg.h> 97 #include <dreamcast/dev/maple/mapleio.h> 98 99 #include "locators.h" 100 101 /* Internal macros, functions, and variables. */ 102 103 #define MAPLE_CALLOUT_TICKS 2 104 105 #define MAPLEBUSUNIT(dev) (minor(dev)>>5) 106 #define MAPLEPORT(dev) ((minor(dev) & 0x18) >> 3) 107 #define MAPLESUBUNIT(dev) (minor(dev) & 0x7) 108 109 /* interrupt priority level */ 110 #define IPL_MAPLE IPL_BIO 111 #define splmaple() splbio() 112 113 /* 114 * Function declarations. 115 */ 116 static int maplematch(struct device *, struct cfdata *, void *); 117 static void mapleattach(struct device *, struct device *, void *); 118 static void maple_create_event_thread(void *); 119 static void maple_scanbus(struct maple_softc *); 120 static char * maple_unit_name(char *, int port, int subunit); 121 static void maple_begin_txbuf(struct maple_softc *); 122 static int maple_end_txbuf(struct maple_softc *); 123 static void maple_queue_command(struct maple_softc *, struct maple_unit *, 124 int command, int datalen, const void *dataaddr); 125 static void maple_write_command(struct maple_softc *, struct maple_unit *, 126 int, int, const void *); 127 static void maple_start(struct maple_softc *sc); 128 static void maple_start_poll(struct maple_softc *); 129 static void maple_check_subunit_change(struct maple_softc *, 130 struct maple_unit *); 131 static void maple_check_unit_change(struct maple_softc *, 132 struct maple_unit *); 133 static void maple_print_unit(void *, const char *); 134 static int maplesubmatch(struct device *, struct cfdata *, 135 const int *, void *); 136 static int mapleprint(void *, const char *); 137 static void maple_attach_unit(struct maple_softc *, struct maple_unit *); 138 static void maple_detach_unit_nofix(struct maple_softc *, 139 struct maple_unit *); 140 static void maple_detach_unit(struct maple_softc *, struct maple_unit *); 141 static void maple_queue_cmds(struct maple_softc *, 142 struct maple_cmdq_head *); 143 static void maple_unit_probe(struct maple_softc *); 144 static void maple_unit_ping(struct maple_softc *); 145 static int maple_send_defered_periodic(struct maple_softc *); 146 static void maple_send_periodic(struct maple_softc *); 147 static void maple_remove_from_queues(struct maple_softc *, 148 struct maple_unit *); 149 static int maple_retry(struct maple_softc *, struct maple_unit *, 150 enum maple_dma_stat); 151 static void maple_queue_retry(struct maple_softc *); 152 static void maple_check_responses(struct maple_softc *); 153 static void maple_event_thread(void *); 154 static int maple_intr(void *); 155 static void maple_callout(void *); 156 157 int maple_alloc_dma(size_t, vaddr_t *, paddr_t *); 158 #if 0 159 void maple_free_dma(paddr_t, size_t); 160 #endif 161 162 /* 163 * Global variables. 164 */ 165 int maple_polling; /* Are we polling? (Debugger mode) */ 166 167 CFATTACH_DECL(maple, sizeof(struct maple_softc), 168 maplematch, mapleattach, NULL, NULL); 169 170 extern struct cfdriver maple_cd; 171 172 dev_type_open(mapleopen); 173 dev_type_close(mapleclose); 174 dev_type_ioctl(mapleioctl); 175 176 const struct cdevsw maple_cdevsw = { 177 mapleopen, mapleclose, noread, nowrite, mapleioctl, 178 nostop, notty, nopoll, nommap, nokqfilter, 179 }; 180 181 static int 182 maplematch(struct device *parent, struct cfdata *cf, void *aux) 183 { 184 185 return 1; 186 } 187 188 static void 189 mapleattach(struct device *parent, struct device *self, void *aux) 190 { 191 struct maple_softc *sc; 192 struct maple_unit *u; 193 vaddr_t dmabuffer; 194 paddr_t dmabuffer_phys; 195 uint32_t *p; 196 int port, subunit, f; 197 198 sc = (struct maple_softc *)self; 199 200 printf(": %s\n", sysasic_intr_string(IPL_MAPLE)); 201 202 if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) { 203 printf("%s: unable to allocate DMA buffers.\n", 204 sc->sc_dev.dv_xname); 205 return; 206 } 207 208 p = (uint32_t *)dmabuffer; 209 210 for (port = 0; port < MAPLE_PORTS; port++) { 211 for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) { 212 u = &sc->sc_unit[port][subunit]; 213 u->port = port; 214 u->subunit = subunit; 215 u->u_dma_stat = MAPLE_DMA_IDLE; 216 u->u_rxbuf = p; 217 u->u_rxbuf_phys = SH3_P2SEG_TO_PHYS(p); 218 p += 256; 219 220 for (f = 0; f < MAPLE_NFUNC; f++) { 221 u->u_func[f].f_funcno = f; 222 u->u_func[f].f_unit = u; 223 } 224 } 225 } 226 227 sc->sc_txbuf = p; 228 sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p); 229 230 SIMPLEQ_INIT(&sc->sc_retryq); 231 TAILQ_INIT(&sc->sc_probeq); 232 TAILQ_INIT(&sc->sc_pingq); 233 TAILQ_INIT(&sc->sc_periodicq); 234 TAILQ_INIT(&sc->sc_periodicdeferq); 235 TAILQ_INIT(&sc->sc_acmdq); 236 TAILQ_INIT(&sc->sc_pcmdq); 237 238 MAPLE_RESET = RESET_MAGIC; 239 MAPLE_RESET2 = 0; 240 241 MAPLE_SPEED = SPEED_2MBPS | TIMEOUT(50000); 242 243 MAPLE_ENABLE = 1; 244 245 maple_polling = 1; 246 maple_scanbus(sc); 247 248 callout_init(&sc->maple_callout_ch); 249 250 sc->sc_intrhand = sysasic_intr_establish(SYSASIC_EVENT_MAPLE_DMADONE, 251 IPL_MAPLE, maple_intr, sc); 252 253 config_pending_incr(); /* create thread before mounting root */ 254 kthread_create(maple_create_event_thread, sc); 255 } 256 257 static void 258 maple_create_event_thread(void *arg) 259 { 260 struct maple_softc *sc = arg; 261 262 if (kthread_create1(maple_event_thread, sc, &sc->event_thread, 263 "%s", sc->sc_dev.dv_xname) == 0) 264 return; 265 266 panic("%s: unable to create event thread", sc->sc_dev.dv_xname); 267 } 268 269 /* 270 * initial device attach 271 */ 272 static void 273 maple_scanbus(struct maple_softc *sc) 274 { 275 struct maple_unit *u; 276 int port; 277 int last_port, last_subunit; 278 int i; 279 280 KASSERT(cold && maple_polling); 281 282 /* probe all ports */ 283 for (port = 0; port < MAPLE_PORTS; port++) { 284 u = &sc->sc_unit[port][0]; 285 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 286 { 287 char buf[16]; 288 printf("%s: queued to probe 1\n", 289 maple_unit_name(buf, u->port, u->subunit)); 290 } 291 #endif 292 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 293 u->u_queuestat = MAPLE_QUEUE_PROBE; 294 } 295 296 last_port = last_subunit = -1; 297 maple_begin_txbuf(sc); 298 while ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 299 /* 300 * Check wrap condition 301 */ 302 if (u->port < last_port || u->subunit <= last_subunit) 303 break; 304 last_port = u->port; 305 if (u->port == MAPLE_PORTS - 1) 306 last_subunit = u->subunit; 307 308 maple_unit_probe(sc); 309 for (i = 10 /* just not forever */; maple_end_txbuf(sc); i--) { 310 maple_start_poll(sc); 311 maple_check_responses(sc); 312 if (i == 0) 313 break; 314 /* attach may issue cmds */ 315 maple_queue_cmds(sc, &sc->sc_acmdq); 316 } 317 } 318 } 319 320 void 321 maple_run_polling(struct device *dev) 322 { 323 struct maple_softc *sc; 324 int port, subunit; 325 int i; 326 327 sc = (struct maple_softc *)dev; 328 329 /* 330 * first, make sure polling works 331 */ 332 while (MAPLE_STATE != 0) /* XXX may lost a DMA cycle */ 333 ; 334 335 /* XXX this will break internal state */ 336 for (port = 0; port < MAPLE_PORTS; port++) 337 for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) 338 sc->sc_unit[port][subunit].u_dma_stat = MAPLE_DMA_IDLE; 339 SIMPLEQ_INIT(&sc->sc_retryq); /* XXX discard current retrys */ 340 341 /* 342 * do polling (periodic status check only) 343 */ 344 maple_begin_txbuf(sc); 345 maple_send_defered_periodic(sc); 346 maple_send_periodic(sc); 347 for (i = 10 /* just not forever */; maple_end_txbuf(sc); i--) { 348 maple_start_poll(sc); 349 maple_check_responses(sc); 350 if (i == 0) 351 break; 352 353 /* maple_check_responses() has executed maple_begin_txbuf() */ 354 maple_queue_retry(sc); 355 maple_send_defered_periodic(sc); 356 } 357 } 358 359 static char * 360 maple_unit_name(char *buf, int port, int subunit) 361 { 362 363 sprintf(buf, "maple%c", port + 'A'); 364 if (subunit) 365 sprintf(buf+6, "%d", subunit); 366 367 return buf; 368 } 369 370 int 371 maple_alloc_dma(size_t size, vaddr_t *vap, paddr_t *pap) 372 { 373 extern paddr_t avail_start, avail_end; /* from pmap.c */ 374 struct pglist mlist; 375 struct vm_page *m; 376 int error; 377 378 size = round_page(size); 379 380 error = uvm_pglistalloc(size, avail_start, avail_end - PAGE_SIZE, 381 0, 0, &mlist, 1, 0); 382 if (error) 383 return error; 384 385 m = TAILQ_FIRST(&mlist); 386 *pap = VM_PAGE_TO_PHYS(m); 387 *vap = SH3_PHYS_TO_P2SEG(VM_PAGE_TO_PHYS(m)); 388 389 return 0; 390 } 391 392 #if 0 /* currently unused */ 393 void 394 maple_free_dma(paddr_t paddr, size_t size) 395 { 396 struct pglist mlist; 397 struct vm_page *m; 398 bus_addr_t addr; 399 400 TAILQ_INIT(&mlist); 401 for (addr = paddr; addr < paddr + size; addr += PAGE_SIZE) { 402 m = PHYS_TO_VM_PAGE(addr); 403 TAILQ_INSERT_TAIL(&mlist, m, pageq); 404 } 405 uvm_pglistfree(&mlist); 406 } 407 #endif 408 409 static void 410 maple_begin_txbuf(struct maple_softc *sc) 411 { 412 413 sc->sc_txlink = sc->sc_txpos = sc->sc_txbuf; 414 SIMPLEQ_INIT(&sc->sc_dmaq); 415 } 416 417 static int 418 maple_end_txbuf(struct maple_softc *sc) 419 { 420 421 /* if no frame have been written, we can't mark the 422 list end, and so the DMA must not be activated */ 423 if (sc->sc_txpos == sc->sc_txbuf) 424 return 0; 425 426 *sc->sc_txlink |= 0x80000000; 427 428 return 1; 429 } 430 431 static const int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 }; 432 433 static void 434 maple_queue_command(struct maple_softc *sc, struct maple_unit *u, 435 int command, int datalen, const void *dataaddr) 436 { 437 int to, from; 438 uint32_t *p = sc->sc_txpos; 439 440 /* Max data length = 255 longs = 1020 bytes */ 441 KASSERT(datalen >= 0 && datalen <= 255); 442 443 /* Compute sender and recipient address */ 444 from = u->port << 6; 445 to = from | subunit_code[u->subunit]; 446 447 sc->sc_txlink = p; 448 449 /* Set length of packet and destination port (A-D) */ 450 *p++ = datalen | (u->port << 16); 451 452 /* Write address to receive buffer where the response 453 frame should be put */ 454 *p++ = u->u_rxbuf_phys; 455 456 /* Create the frame header. The fields are assembled "backwards" 457 because of the Maple Bus big-endianness. */ 458 *p++ = (command & 0xff) | (to << 8) | (from << 16) | (datalen << 24); 459 460 /* Copy parameter data, if any */ 461 if (datalen > 0) { 462 const uint32_t *param = dataaddr; 463 int i; 464 for (i = 0; i < datalen; i++) 465 *p++ = *param++; 466 } 467 468 sc->sc_txpos = p; 469 470 SIMPLEQ_INSERT_TAIL(&sc->sc_dmaq, u, u_dmaq); 471 } 472 473 static void 474 maple_write_command(struct maple_softc *sc, struct maple_unit *u, int command, 475 int datalen, const void *dataaddr) 476 { 477 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 478 char buf[16]; 479 480 if (u->u_retrycnt) 481 printf("%s: retrycnt %d\n", 482 maple_unit_name(buf, u->port, u->subunit), u->u_retrycnt); 483 #endif 484 u->u_retrycnt = 0; 485 u->u_command = command; 486 u->u_datalen = datalen; 487 u->u_dataaddr = dataaddr; 488 489 maple_queue_command(sc, u, command, datalen, dataaddr); 490 } 491 492 /* start DMA */ 493 static void 494 maple_start(struct maple_softc *sc) 495 { 496 497 MAPLE_DMAADDR = sc->sc_txbuf_phys; 498 MAPLE_STATE = 1; 499 } 500 501 /* start DMA -- wait until DMA done */ 502 static void 503 maple_start_poll(struct maple_softc *sc) 504 { 505 506 MAPLE_DMAADDR = sc->sc_txbuf_phys; 507 MAPLE_STATE = 1; 508 while (MAPLE_STATE != 0) 509 ; 510 } 511 512 static void 513 maple_check_subunit_change(struct maple_softc *sc, struct maple_unit *u) 514 { 515 struct maple_unit *u1; 516 int port; 517 int8_t unit_map; 518 int units, un; 519 int i; 520 521 KASSERT(u->subunit == 0); 522 523 port = u->port; 524 unit_map = ((int8_t *) u->u_rxbuf)[2]; 525 if (sc->sc_port_unit_map[port] == unit_map) 526 return; 527 528 units = ((unit_map & 0x1f) << 1) | 1; 529 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 530 { 531 char buf[16]; 532 printf("%s: unit_map 0x%x -> 0x%x (units 0x%x)\n", 533 maple_unit_name(buf, u->port, u->subunit), 534 sc->sc_port_unit_map[port], unit_map, units); 535 } 536 #endif 537 #if 0 /* this detects unit removal rapidly but is not reliable */ 538 /* check for unit change */ 539 un = sc->sc_port_units[port] & ~units; 540 541 /* detach removed devices */ 542 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 543 if (un & (1 << i)) 544 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 545 #endif 546 547 sc->sc_port_unit_map[port] = unit_map; 548 549 /* schedule scanning child devices */ 550 un = units & ~sc->sc_port_units[port]; 551 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 552 if (un & (1 << i)) { 553 u1 = &sc->sc_unit[port][i]; 554 maple_remove_from_queues(sc, u1); 555 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 556 { 557 char buf[16]; 558 printf("%s: queued to probe 2\n", 559 maple_unit_name(buf, u1->port, u1->subunit)); 560 } 561 #endif 562 TAILQ_INSERT_HEAD(&sc->sc_probeq, u1, u_q); 563 u1->u_queuestat = MAPLE_QUEUE_PROBE; 564 u1->u_proberetry = 0; 565 } 566 } 567 568 static void 569 maple_check_unit_change(struct maple_softc *sc, struct maple_unit *u) 570 { 571 struct maple_devinfo *newinfo = (void *) (u->u_rxbuf + 1); 572 int port, subunit; 573 574 port = u->port; 575 subunit = u->subunit; 576 if (memcmp(&u->devinfo, newinfo, sizeof(struct maple_devinfo)) == 0) 577 goto out; /* no change */ 578 579 /* unit inserted */ 580 581 /* attach this device */ 582 u->devinfo = *newinfo; 583 maple_attach_unit(sc, u); 584 585 out: 586 maple_remove_from_queues(sc, u); 587 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 588 { 589 char buf[16]; 590 printf("%s: queued to ping\n", 591 maple_unit_name(buf, u->port, u->subunit)); 592 } 593 #endif 594 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 595 u->u_queuestat = MAPLE_QUEUE_PING; 596 } 597 598 static void 599 maple_print_unit(void *aux, const char *pnp) 600 { 601 struct maple_attach_args *ma = aux; 602 int port, subunit; 603 char buf[16]; 604 char *prod, *p, oc; 605 606 port = ma->ma_unit->port; 607 subunit = ma->ma_unit->subunit; 608 609 if (pnp != NULL) 610 printf("%s at %s", maple_unit_name(buf, port, subunit), pnp); 611 612 printf(" port %d", port); 613 614 if (subunit != 0) 615 printf(" subunit %d", subunit); 616 617 #ifdef MAPLE_DEBUG 618 printf(": a %#x c %#x fn %#x d %#x,%#x,%#x", 619 ma->ma_devinfo->di_area_code, 620 ma->ma_devinfo->di_connector_direction, 621 be32toh(ma->ma_devinfo->di_func), 622 be32toh(ma->ma_devinfo->di_function_data[0]), 623 be32toh(ma->ma_devinfo->di_function_data[1]), 624 be32toh(ma->ma_devinfo->di_function_data[2])); 625 #endif 626 627 /* nul termination */ 628 prod = ma->ma_devinfo->di_product_name; 629 for (p = prod + sizeof ma->ma_devinfo->di_product_name; p >= prod; p--) 630 if (p[-1] != '\0' && p[-1] != ' ') 631 break; 632 oc = *p; 633 *p = '\0'; 634 635 printf(": %s", prod); 636 637 *p = oc; /* restore */ 638 } 639 640 static int 641 maplesubmatch(struct device *parent, struct cfdata *match, 642 const int *ldesc, void *aux) 643 { 644 struct maple_attach_args *ma = aux; 645 646 if (match->cf_loc[MAPLECF_PORT] != MAPLECF_PORT_DEFAULT && 647 match->cf_loc[MAPLECF_PORT] != ma->ma_unit->port) 648 return 0; 649 650 if (match->cf_loc[MAPLECF_SUBUNIT] != MAPLECF_SUBUNIT_DEFAULT && 651 match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_unit->subunit) 652 return 0; 653 654 return config_match(parent, match, aux); 655 } 656 657 static int 658 mapleprint(void *aux, const char *str) 659 { 660 struct maple_attach_args *ma = aux; 661 662 #ifdef MAPLE_DEBUG 663 if (str) 664 aprint_normal("%s", str); 665 aprint_normal(" function %d", ma->ma_function); 666 667 return UNCONF; 668 #else /* quiet */ 669 if (!str) 670 aprint_normal(" function %d", ma->ma_function); 671 672 return QUIET; 673 #endif 674 } 675 676 static void 677 maple_attach_unit(struct maple_softc *sc, struct maple_unit *u) 678 { 679 struct maple_attach_args ma; 680 uint32_t func; 681 int f; 682 char oldxname[16]; 683 684 ma.ma_unit = u; 685 ma.ma_devinfo = &u->devinfo; 686 ma.ma_basedevinfo = &sc->sc_unit[u->port][0].devinfo; 687 func = be32toh(ma.ma_devinfo->di_func); 688 689 maple_print_unit(&ma, sc->sc_dev.dv_xname); 690 printf("\n"); 691 strcpy(oldxname, sc->sc_dev.dv_xname); 692 maple_unit_name(sc->sc_dev.dv_xname, u->port, u->subunit); 693 694 for (f = 0; f < MAPLE_NFUNC; f++) { 695 u->u_func[f].f_callback = NULL; 696 u->u_func[f].f_arg = NULL; 697 u->u_func[f].f_cmdstat = MAPLE_CMDSTAT_NONE; 698 u->u_func[f].f_dev = NULL; 699 if (func & MAPLE_FUNC(f)) { 700 ma.ma_function = f; 701 u->u_func[f].f_dev = config_found_sm_loc(&sc->sc_dev, 702 "maple", NULL, &ma, mapleprint, maplesubmatch); 703 u->u_ping_func = f; /* XXX using largest func */ 704 } 705 } 706 #ifdef MAPLE_MEMCARD_PING_HACK 707 /* 708 * Some 3rd party memory card pretend to be Visual Memory, 709 * but need special handling for ping. 710 */ 711 if (func == (MAPLE_FUNC(MAPLE_FN_MEMCARD) | MAPLE_FUNC(MAPLE_FN_LCD) | 712 MAPLE_FUNC(MAPLE_FN_CLOCK))) { 713 u->u_ping_func = MAPLE_FN_MEMCARD; 714 u->u_ping_stat = MAPLE_PING_MEMCARD; 715 } else { 716 u->u_ping_stat = MAPLE_PING_NORMAL; 717 } 718 #endif 719 strcpy(sc->sc_dev.dv_xname, oldxname); 720 721 sc->sc_port_units[u->port] |= 1 << u->subunit; 722 } 723 724 static void 725 maple_detach_unit_nofix(struct maple_softc *sc, struct maple_unit *u) 726 { 727 struct maple_func *fn; 728 struct device *dev; 729 struct maple_unit *u1; 730 int port; 731 int error; 732 int i; 733 char buf[16]; 734 735 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 736 printf("%s: remove\n", maple_unit_name(buf, u->port, u->subunit)); 737 #endif 738 maple_remove_from_queues(sc, u); 739 port = u->port; 740 sc->sc_port_units[port] &= ~(1 << u->subunit); 741 742 if (u->subunit == 0) { 743 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 744 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 745 } 746 747 for (fn = u->u_func; fn < &u->u_func[MAPLE_NFUNC]; fn++) { 748 if ((dev = fn->f_dev) != NULL) { 749 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 750 printf("%s: detaching func %d\n", 751 maple_unit_name(buf, port, u->subunit), 752 fn->f_funcno); 753 #endif 754 755 /* 756 * Remove functions from command queue. 757 */ 758 switch (fn->f_cmdstat) { 759 case MAPLE_CMDSTAT_ASYNC: 760 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 761 TAILQ_REMOVE(&sc->sc_acmdq, fn, f_cmdq); 762 break; 763 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 764 case MAPLE_CMDSTAT_PERIODIC: 765 TAILQ_REMOVE(&sc->sc_pcmdq, fn, f_cmdq); 766 break; 767 default: 768 break; 769 } 770 771 /* 772 * Detach devices. 773 */ 774 if ((error = config_detach(fn->f_dev, DETACH_FORCE))) { 775 printf("%s: failed to detach %s (func %d), errno %d\n", 776 maple_unit_name(buf, port, u->subunit), 777 fn->f_dev->dv_xname, fn->f_funcno, error); 778 } 779 } 780 781 maple_enable_periodic(&sc->sc_dev, u, fn->f_funcno, 0); 782 783 fn->f_dev = NULL; 784 fn->f_callback = NULL; 785 fn->f_arg = NULL; 786 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 787 } 788 if (u->u_dma_stat == MAPLE_DMA_RETRY) { 789 /* XXX expensive? */ 790 SIMPLEQ_FOREACH(u1, &sc->sc_retryq, u_dmaq) { 791 if (u1 == u) { 792 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 793 printf("%s: abort retry\n", 794 maple_unit_name(buf, port, u->subunit)); 795 #endif 796 SIMPLEQ_REMOVE(&sc->sc_retryq, u, maple_unit, 797 u_dmaq); 798 break; 799 } 800 } 801 } 802 u->u_dma_stat = MAPLE_DMA_IDLE; 803 u->u_noping = 0; 804 /* u->u_dma_func = uninitialized; */ 805 KASSERT(u->getcond_func_set == 0); 806 memset(&u->devinfo, 0, sizeof(struct maple_devinfo)); 807 808 if (u->subunit == 0) { 809 sc->sc_port_unit_map[port] = 0; 810 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 811 { 812 char buf[16]; 813 printf("%s: queued to probe 3\n", 814 maple_unit_name(buf, port, u->subunit)); 815 } 816 #endif 817 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 818 u->u_queuestat = MAPLE_QUEUE_PROBE; 819 } 820 } 821 822 static void 823 maple_detach_unit(struct maple_softc *sc, struct maple_unit *u) 824 { 825 826 maple_detach_unit_nofix(sc, u); 827 if (u->subunit != 0) 828 sc->sc_port_unit_map[u->port] &= ~(1 << (u->subunit - 1)); 829 } 830 831 /* 832 * Send a command (called by drivers) 833 * 834 * The "cataaddr" must not point at temporary storage like stack. 835 * Only one command (per function) is valid at a time. 836 */ 837 void 838 maple_command(struct device *dev, struct maple_unit *u, int func, 839 int command, int datalen, const void *dataaddr, int flags) 840 { 841 struct maple_softc *sc = (void *) dev; 842 struct maple_func *fn; 843 int s; 844 845 KASSERT(func >= 0 && func < 32); 846 KASSERT(command); 847 KASSERT((flags & ~MAPLE_FLAG_CMD_PERIODIC_TIMING) == 0); 848 849 s = splsoftclock(); 850 851 fn = &u->u_func[func]; 852 #if 1 /*def DIAGNOSTIC*/ 853 {char buf[16]; 854 if (fn->f_cmdstat != MAPLE_CMDSTAT_NONE) 855 panic("maple_command: %s func %d: requesting more than one commands", 856 maple_unit_name(buf, u->port, u->subunit), func); 857 } 858 #endif 859 fn->f_command = command; 860 fn->f_datalen = datalen; 861 fn->f_dataaddr = dataaddr; 862 if (flags & MAPLE_FLAG_CMD_PERIODIC_TIMING) { 863 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 864 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 865 } else { 866 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 867 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 868 wakeup(&sc->sc_event); /* wake for async event */ 869 } 870 splx(s); 871 } 872 873 static void 874 maple_queue_cmds(struct maple_softc *sc, 875 struct maple_cmdq_head *head) 876 { 877 struct maple_func *fn, *nextfn; 878 struct maple_unit *u; 879 880 /* 881 * Note: since the queue element may be queued immediately, 882 * we can't use TAILQ_FOREACH. 883 */ 884 fn = TAILQ_FIRST(head); 885 TAILQ_INIT(head); 886 for ( ; fn; fn = nextfn) { 887 nextfn = TAILQ_NEXT(fn, f_cmdq); 888 889 KASSERT(fn->f_cmdstat != MAPLE_CMDSTAT_NONE); 890 u = fn->f_unit; 891 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 892 maple_write_command(sc, u, 893 fn->f_command, fn->f_datalen, fn->f_dataaddr); 894 u->u_dma_stat = (fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC || 895 fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC_PERIODICQ) ? 896 MAPLE_DMA_ACMD : MAPLE_DMA_PCMD; 897 u->u_dma_func = fn->f_funcno; 898 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 899 } else if (u->u_dma_stat == MAPLE_DMA_RETRY) { 900 /* unit is busy --- try again */ 901 /* 902 * always add to periodic command queue 903 * (wait until the next periodic timing), 904 * since the unit will never be freed until the 905 * next periodic timing. 906 */ 907 switch (fn->f_cmdstat) { 908 case MAPLE_CMDSTAT_ASYNC: 909 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC_PERIODICQ; 910 break; 911 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 912 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 913 break; 914 default: 915 break; 916 } 917 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 918 } else { 919 /* unit is busy --- try again */ 920 /* 921 * always add to async command queue 922 * (process immediately) 923 */ 924 switch (fn->f_cmdstat) { 925 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 926 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 927 break; 928 case MAPLE_CMDSTAT_PERIODIC: 929 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC_DEFERED; 930 break; 931 default: 932 break; 933 } 934 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 935 } 936 } 937 } 938 939 /* schedule probing a device */ 940 static void 941 maple_unit_probe(struct maple_softc *sc) 942 { 943 struct maple_unit *u; 944 945 if ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 946 KASSERT(u->u_dma_stat == MAPLE_DMA_IDLE); 947 KASSERT(u->u_queuestat == MAPLE_QUEUE_PROBE); 948 maple_remove_from_queues(sc, u); 949 maple_write_command(sc, u, MAPLE_COMMAND_DEVINFO, 0, NULL); 950 u->u_dma_stat = MAPLE_DMA_PROBE; 951 /* u->u_dma_func = ignored; */ 952 } 953 } 954 955 /* 956 * Enable/disable unit pinging (called by drivers) 957 */ 958 /* ARGSUSED */ 959 void 960 maple_enable_unit_ping(struct device *dev, struct maple_unit *u, 961 int func, int enable) 962 { 963 #if 0 /* currently unused */ 964 struct maple_softc *sc = (void *) 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(struct device *dev, struct maple_unit *u, 1020 int func, int on) 1021 { 1022 struct maple_softc *sc = (void *) 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 int s; 1433 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1434 int noreq = 0; 1435 #endif 1436 1437 #ifdef MAPLE_DEBUG 1438 printf("%s: forked event thread, pid %d\n", 1439 sc->sc_dev.dv_xname, sc->event_thread->p_pid); 1440 #endif 1441 1442 /* begin first DMA cycle */ 1443 maple_begin_txbuf(sc); 1444 1445 sc->sc_event = 1; 1446 1447 /* OK, continue booting system */ 1448 maple_polling = 0; 1449 config_pending_decr(); 1450 1451 for (;;) { 1452 /* 1453 * queue requests 1454 */ 1455 1456 /* queue async commands */ 1457 if (!TAILQ_EMPTY(&sc->sc_acmdq)) 1458 maple_queue_cmds(sc, &sc->sc_acmdq); 1459 1460 /* send defered periodic command */ 1461 if (!TAILQ_EMPTY(&sc->sc_periodicdeferq)) 1462 maple_send_defered_periodic(sc); 1463 1464 /* queue periodic commands */ 1465 if (sc->sc_event) { 1466 /* queue commands on periodic timing */ 1467 if (!TAILQ_EMPTY(&sc->sc_pcmdq)) 1468 maple_queue_cmds(sc, &sc->sc_pcmdq); 1469 1470 /* retry */ 1471 if (!SIMPLEQ_EMPTY(&sc->sc_retryq)) 1472 maple_queue_retry(sc); 1473 1474 if ((cnt & 31) == 0) /* XXX */ 1475 maple_unit_probe(sc); 1476 cnt++; 1477 1478 maple_send_periodic(sc); 1479 if ((cnt & 7) == 0) /* XXX */ 1480 maple_unit_ping(sc); 1481 1482 /* 1483 * schedule periodic event 1484 */ 1485 sc->sc_event = 0; 1486 callout_reset(&sc->maple_callout_ch, 1487 MAPLE_CALLOUT_TICKS, maple_callout, sc); 1488 } 1489 1490 if (maple_end_txbuf(sc)) { 1491 1492 /* 1493 * start DMA 1494 */ 1495 s = splmaple(); 1496 maple_start(sc); 1497 1498 /* 1499 * wait until DMA done 1500 */ 1501 if (tsleep(&sc->sc_dmadone, PWAIT, "mdma", hz) 1502 == EWOULDBLOCK) { 1503 /* was DDB active? */ 1504 printf("%s: timed out\n", sc->sc_dev.dv_xname); 1505 } 1506 splx(s); 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 sc->sc_dev.dv_xname, noreq); 1524 noreq++; 1525 } 1526 #endif 1527 1528 /* 1529 * wait for an event 1530 */ 1531 s = splsoftclock(); 1532 if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 && 1533 TAILQ_EMPTY(&sc->sc_periodicdeferq)) { 1534 if (tsleep(&sc->sc_event, PWAIT, "mslp", hz) 1535 == EWOULDBLOCK) { 1536 printf("%s: event timed out\n", 1537 sc->sc_dev.dv_xname); 1538 } 1539 1540 } 1541 splx(s); 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 wakeup(&sc->sc_dmadone); 1557 1558 return 1; 1559 } 1560 1561 static void 1562 maple_callout(void *ctx) 1563 { 1564 struct maple_softc *sc = ctx; 1565 1566 sc->sc_event = 1; /* mark as periodic event */ 1567 wakeup(&sc->sc_event); 1568 } 1569 1570 /* 1571 * Install callback handler (called by drivers) 1572 */ 1573 /* ARGSUSED */ 1574 void 1575 maple_set_callback(struct device *dev, struct maple_unit *u, int func, 1576 void (*callback)(void *, struct maple_response *, int, int), void *arg) 1577 { 1578 #if 0 /* currently unused */ 1579 struct maple_softc *sc = (void *) dev; 1580 #endif 1581 struct maple_func *fn; 1582 1583 KASSERT(func >= 0 && func < MAPLE_NFUNC); 1584 1585 fn = &u->u_func[func]; 1586 1587 fn->f_callback = callback; 1588 fn->f_arg = arg; 1589 } 1590 1591 /* 1592 * Return function definition data (called by drivers) 1593 */ 1594 uint32_t 1595 maple_get_function_data(struct maple_devinfo *devinfo, int function_code) 1596 { 1597 int i, p = 0; 1598 uint32_t func; 1599 1600 func = be32toh(devinfo->di_func); 1601 for (i = 31; i >= 0; --i) 1602 if (func & MAPLE_FUNC(i)) { 1603 if (function_code == i) 1604 return be32toh(devinfo->di_function_data[p]); 1605 else 1606 if (++p >= 3) 1607 break; 1608 } 1609 1610 return 0; 1611 } 1612 1613 /* Generic maple device interface */ 1614 1615 int 1616 mapleopen(dev_t dev, int flag, int mode, struct lwp *l) 1617 { 1618 struct maple_softc *sc; 1619 1620 sc = device_lookup(&maple_cd, MAPLEBUSUNIT(dev)); 1621 if (sc == NULL) /* make sure it was attached */ 1622 return ENXIO; 1623 1624 if (MAPLEPORT(dev) >= MAPLE_PORTS) 1625 return ENXIO; 1626 1627 if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS) 1628 return ENXIO; 1629 1630 if (!(sc->sc_port_units[MAPLEPORT(dev)] & (1 << MAPLESUBUNIT(dev)))) 1631 return ENXIO; 1632 1633 sc->sc_port_units_open[MAPLEPORT(dev)] |= 1 << MAPLESUBUNIT(dev); 1634 1635 return 0; 1636 } 1637 1638 int 1639 mapleclose(dev_t dev, int flag, int mode, struct lwp *l) 1640 { 1641 struct maple_softc *sc; 1642 1643 sc = device_lookup(&maple_cd, MAPLEBUSUNIT(dev)); 1644 1645 sc->sc_port_units_open[MAPLEPORT(dev)] &= ~(1 << MAPLESUBUNIT(dev)); 1646 1647 return 0; 1648 } 1649 1650 int 1651 maple_unit_ioctl(struct device *dev, struct maple_unit *u, u_long cmd, 1652 caddr_t data, int flag, struct lwp *l) 1653 { 1654 struct maple_softc *sc = (struct maple_softc *)dev; 1655 1656 if (!(sc->sc_port_units[u->port] & (1 << u->subunit))) 1657 return ENXIO; 1658 1659 switch(cmd) { 1660 case MAPLEIO_GDEVINFO: 1661 memcpy(data, &u->devinfo, sizeof(struct maple_devinfo)); 1662 break; 1663 default: 1664 return EPASSTHROUGH; 1665 } 1666 1667 return 0; 1668 } 1669 1670 int 1671 mapleioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 1672 { 1673 struct maple_softc *sc; 1674 struct maple_unit *u; 1675 1676 sc = device_lookup(&maple_cd, MAPLEBUSUNIT(dev)); 1677 u = &sc->sc_unit[MAPLEPORT(dev)][MAPLESUBUNIT(dev)]; 1678 1679 return maple_unit_ioctl(&sc->sc_dev, u, cmd, data, flag, l); 1680 } 1681