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