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