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