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