1 /* $NetBSD: maple.c,v 1.46 2013/10/13 06:55:34 riz 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.46 2013/10/13 06:55:34 riz 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 #include <sys/bus.h> 79 80 #include <uvm/uvm.h> 81 82 #include <machine/cpu.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(device_t, cfdata_t, const int *, void *); 129 static int mapleprint(void *, const char *); 130 static void maple_attach_unit(struct maple_softc *, struct maple_unit *); 131 static void maple_detach_unit_nofix(struct maple_softc *, 132 struct maple_unit *); 133 static void maple_detach_unit(struct maple_softc *, struct maple_unit *); 134 static void maple_queue_cmds(struct maple_softc *, 135 struct maple_cmdq_head *); 136 static void maple_unit_probe(struct maple_softc *); 137 static void maple_unit_ping(struct maple_softc *); 138 static int maple_send_defered_periodic(struct maple_softc *); 139 static void maple_send_periodic(struct maple_softc *); 140 static void maple_remove_from_queues(struct maple_softc *, 141 struct maple_unit *); 142 static int maple_retry(struct maple_softc *, struct maple_unit *, 143 enum maple_dma_stat); 144 static void maple_queue_retry(struct maple_softc *); 145 static void maple_check_responses(struct maple_softc *); 146 static void maple_event_thread(void *); 147 static int maple_intr(void *); 148 static void maple_callout(void *); 149 150 int maple_alloc_dma(size_t, vaddr_t *, paddr_t *); 151 #if 0 152 void maple_free_dma(paddr_t, size_t); 153 #endif 154 155 /* 156 * Global variables. 157 */ 158 int maple_polling; /* Are we polling? (Debugger mode) */ 159 160 CFATTACH_DECL_NEW(maple, sizeof(struct maple_softc), 161 maplematch, mapleattach, NULL, NULL); 162 163 dev_type_open(mapleopen); 164 dev_type_close(mapleclose); 165 dev_type_ioctl(mapleioctl); 166 167 const struct cdevsw maple_cdevsw = { 168 mapleopen, mapleclose, noread, nowrite, mapleioctl, 169 nostop, notty, nopoll, nommap, nokqfilter, 170 }; 171 172 static int 173 maplematch(device_t parent, cfdata_t cf, void *aux) 174 { 175 176 return 1; 177 } 178 179 static void 180 mapleattach(device_t parent, device_t self, void *aux) 181 { 182 struct maple_softc *sc; 183 struct maple_unit *u; 184 vaddr_t dmabuffer; 185 paddr_t dmabuffer_phys; 186 uint32_t *p; 187 int port, subunit, f; 188 189 sc = device_private(self); 190 sc->sc_dev = self; 191 192 printf(": %s\n", sysasic_intr_string(IRL_MAPLE)); 193 194 if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) { 195 printf("%s: unable to allocate DMA buffers.\n", 196 device_xname(self)); 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, IRL_MAPLE, maple_intr, sc); 244 245 config_pending_incr(self); /* create thread before mounting root */ 246 247 if (kthread_create(PRI_NONE, 0, NULL, maple_event_thread, sc, 248 &sc->event_thread, "%s", device_xname(self)) == 0) 249 return; 250 251 panic("%s: unable to create event thread", device_xname(self)); 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(device_t dev) 307 { 308 struct maple_softc *sc; 309 int port, subunit; 310 int i; 311 312 sc = device_private(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(device_t parent, cfdata_t match, const int *ldesc, void *aux) 627 { 628 struct maple_attach_args *ma = aux; 629 630 if (match->cf_loc[MAPLECF_PORT] != MAPLECF_PORT_DEFAULT && 631 match->cf_loc[MAPLECF_PORT] != ma->ma_unit->port) 632 return 0; 633 634 if (match->cf_loc[MAPLECF_SUBUNIT] != MAPLECF_SUBUNIT_DEFAULT && 635 match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_unit->subunit) 636 return 0; 637 638 return config_match(parent, match, aux); 639 } 640 641 static int 642 mapleprint(void *aux, const char *str) 643 { 644 struct maple_attach_args *ma = aux; 645 646 #ifdef MAPLE_DEBUG 647 if (str) 648 aprint_normal("%s", str); 649 aprint_normal(" function %d", ma->ma_function); 650 651 return UNCONF; 652 #else /* quiet */ 653 if (!str) 654 aprint_normal(" function %d", ma->ma_function); 655 656 return QUIET; 657 #endif 658 } 659 660 static void 661 maple_attach_unit(struct maple_softc *sc, struct maple_unit *u) 662 { 663 struct maple_attach_args ma; 664 uint32_t func; 665 int f; 666 char oldxname[16]; 667 668 ma.ma_unit = u; 669 ma.ma_devinfo = &u->devinfo; 670 ma.ma_basedevinfo = &sc->sc_unit[u->port][0].devinfo; 671 func = be32toh(ma.ma_devinfo->di_func); 672 673 maple_print_unit(&ma, device_xname(sc->sc_dev)); 674 printf("\n"); 675 strcpy(oldxname, device_xname(sc->sc_dev)); 676 maple_unit_name(sc->sc_dev->dv_xname, u->port, u->subunit); 677 678 for (f = 0; f < MAPLE_NFUNC; f++) { 679 u->u_func[f].f_callback = NULL; 680 u->u_func[f].f_arg = NULL; 681 u->u_func[f].f_cmdstat = MAPLE_CMDSTAT_NONE; 682 u->u_func[f].f_dev = NULL; 683 if (func & MAPLE_FUNC(f)) { 684 ma.ma_function = f; 685 u->u_func[f].f_dev = config_found_sm_loc(sc->sc_dev, 686 "maple", NULL, &ma, mapleprint, maplesubmatch); 687 u->u_ping_func = f; /* XXX using largest func */ 688 } 689 } 690 #ifdef MAPLE_MEMCARD_PING_HACK 691 /* 692 * Some 3rd party memory card pretend to be Visual Memory, 693 * but need special handling for ping. 694 */ 695 if (func == (MAPLE_FUNC(MAPLE_FN_MEMCARD) | MAPLE_FUNC(MAPLE_FN_LCD) | 696 MAPLE_FUNC(MAPLE_FN_CLOCK))) { 697 u->u_ping_func = MAPLE_FN_MEMCARD; 698 u->u_ping_stat = MAPLE_PING_MEMCARD; 699 } else { 700 u->u_ping_stat = MAPLE_PING_NORMAL; 701 } 702 #endif 703 strcpy(sc->sc_dev->dv_xname, oldxname); 704 705 sc->sc_port_units[u->port] |= 1 << u->subunit; 706 } 707 708 static void 709 maple_detach_unit_nofix(struct maple_softc *sc, struct maple_unit *u) 710 { 711 struct maple_func *fn; 712 device_t dev; 713 struct maple_unit *u1; 714 int port; 715 int error; 716 int i; 717 char buf[16]; 718 719 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 720 printf("%s: remove\n", maple_unit_name(buf, u->port, u->subunit)); 721 #endif 722 maple_remove_from_queues(sc, u); 723 port = u->port; 724 sc->sc_port_units[port] &= ~(1 << u->subunit); 725 726 if (u->subunit == 0) { 727 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 728 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 729 } 730 731 for (fn = u->u_func; fn < &u->u_func[MAPLE_NFUNC]; fn++) { 732 if ((dev = fn->f_dev) != NULL) { 733 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 734 printf("%s: detaching func %d\n", 735 maple_unit_name(buf, port, u->subunit), 736 fn->f_funcno); 737 #endif 738 739 /* 740 * Remove functions from command queue. 741 */ 742 switch (fn->f_cmdstat) { 743 case MAPLE_CMDSTAT_ASYNC: 744 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 745 TAILQ_REMOVE(&sc->sc_acmdq, fn, f_cmdq); 746 break; 747 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 748 case MAPLE_CMDSTAT_PERIODIC: 749 TAILQ_REMOVE(&sc->sc_pcmdq, fn, f_cmdq); 750 break; 751 default: 752 break; 753 } 754 755 /* 756 * Detach devices. 757 */ 758 if ((error = config_detach(fn->f_dev, DETACH_FORCE))) { 759 printf("%s: failed to detach %s (func %d), errno %d\n", 760 maple_unit_name(buf, port, u->subunit), 761 device_xname(fn->f_dev), fn->f_funcno, error); 762 } 763 } 764 765 maple_enable_periodic(sc->sc_dev, u, fn->f_funcno, 0); 766 767 fn->f_dev = NULL; 768 fn->f_callback = NULL; 769 fn->f_arg = NULL; 770 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 771 } 772 if (u->u_dma_stat == MAPLE_DMA_RETRY) { 773 /* XXX expensive? */ 774 SIMPLEQ_FOREACH(u1, &sc->sc_retryq, u_dmaq) { 775 if (u1 == u) { 776 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 777 printf("%s: abort retry\n", 778 maple_unit_name(buf, port, u->subunit)); 779 #endif 780 SIMPLEQ_REMOVE(&sc->sc_retryq, u, maple_unit, 781 u_dmaq); 782 break; 783 } 784 } 785 } 786 u->u_dma_stat = MAPLE_DMA_IDLE; 787 u->u_noping = 0; 788 /* u->u_dma_func = uninitialized; */ 789 KASSERT(u->getcond_func_set == 0); 790 memset(&u->devinfo, 0, sizeof(struct maple_devinfo)); 791 792 if (u->subunit == 0) { 793 sc->sc_port_unit_map[port] = 0; 794 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 795 { 796 char buf2[16]; 797 printf("%s: queued to probe 3\n", 798 maple_unit_name(buf2, port, u->subunit)); 799 } 800 #endif 801 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 802 u->u_queuestat = MAPLE_QUEUE_PROBE; 803 } 804 } 805 806 static void 807 maple_detach_unit(struct maple_softc *sc, struct maple_unit *u) 808 { 809 810 maple_detach_unit_nofix(sc, u); 811 if (u->subunit != 0) 812 sc->sc_port_unit_map[u->port] &= ~(1 << (u->subunit - 1)); 813 } 814 815 /* 816 * Send a command (called by drivers) 817 * 818 * The "cataaddr" must not point at temporary storage like stack. 819 * Only one command (per function) is valid at a time. 820 */ 821 void 822 maple_command(device_t dev, struct maple_unit *u, int func, 823 int command, int datalen, const void *dataaddr, int flags) 824 { 825 struct maple_softc *sc = device_private(dev); 826 struct maple_func *fn; 827 int s; 828 829 KASSERT(func >= 0 && func < 32); 830 KASSERT(command); 831 KASSERT((flags & ~MAPLE_FLAG_CMD_PERIODIC_TIMING) == 0); 832 833 s = splsoftclock(); 834 835 fn = &u->u_func[func]; 836 #if 1 /*def DIAGNOSTIC*/ 837 {char buf[16]; 838 if (fn->f_cmdstat != MAPLE_CMDSTAT_NONE) 839 panic("maple_command: %s func %d: requesting more than one commands", 840 maple_unit_name(buf, u->port, u->subunit), func); 841 } 842 #endif 843 fn->f_command = command; 844 fn->f_datalen = datalen; 845 fn->f_dataaddr = dataaddr; 846 if (flags & MAPLE_FLAG_CMD_PERIODIC_TIMING) { 847 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 848 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 849 } else { 850 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 851 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 852 wakeup(&sc->sc_event); /* wake for async event */ 853 } 854 splx(s); 855 } 856 857 static void 858 maple_queue_cmds(struct maple_softc *sc, 859 struct maple_cmdq_head *head) 860 { 861 struct maple_func *fn, *nextfn; 862 struct maple_unit *u; 863 864 /* 865 * Note: since the queue element may be queued immediately, 866 * we can't use TAILQ_FOREACH. 867 */ 868 fn = TAILQ_FIRST(head); 869 TAILQ_INIT(head); 870 for ( ; fn; fn = nextfn) { 871 nextfn = TAILQ_NEXT(fn, f_cmdq); 872 873 KASSERT(fn->f_cmdstat != MAPLE_CMDSTAT_NONE); 874 u = fn->f_unit; 875 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 876 maple_write_command(sc, u, 877 fn->f_command, fn->f_datalen, fn->f_dataaddr); 878 u->u_dma_stat = (fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC || 879 fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC_PERIODICQ) ? 880 MAPLE_DMA_ACMD : MAPLE_DMA_PCMD; 881 u->u_dma_func = fn->f_funcno; 882 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 883 } else if (u->u_dma_stat == MAPLE_DMA_RETRY) { 884 /* unit is busy --- try again */ 885 /* 886 * always add to periodic command queue 887 * (wait until the next periodic timing), 888 * since the unit will never be freed until the 889 * next periodic timing. 890 */ 891 switch (fn->f_cmdstat) { 892 case MAPLE_CMDSTAT_ASYNC: 893 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC_PERIODICQ; 894 break; 895 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 896 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 897 break; 898 default: 899 break; 900 } 901 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 902 } else { 903 /* unit is busy --- try again */ 904 /* 905 * always add to async command queue 906 * (process immediately) 907 */ 908 switch (fn->f_cmdstat) { 909 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 910 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 911 break; 912 case MAPLE_CMDSTAT_PERIODIC: 913 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC_DEFERED; 914 break; 915 default: 916 break; 917 } 918 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 919 } 920 } 921 } 922 923 /* schedule probing a device */ 924 static void 925 maple_unit_probe(struct maple_softc *sc) 926 { 927 struct maple_unit *u; 928 929 if ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 930 KASSERT(u->u_dma_stat == MAPLE_DMA_IDLE); 931 KASSERT(u->u_queuestat == MAPLE_QUEUE_PROBE); 932 maple_remove_from_queues(sc, u); 933 maple_write_command(sc, u, MAPLE_COMMAND_DEVINFO, 0, NULL); 934 u->u_dma_stat = MAPLE_DMA_PROBE; 935 /* u->u_dma_func = ignored; */ 936 } 937 } 938 939 /* 940 * Enable/disable unit pinging (called by drivers) 941 */ 942 /* ARGSUSED */ 943 void 944 maple_enable_unit_ping(device_t dev, struct maple_unit *u, int func, int enable) 945 { 946 #if 0 /* currently unused */ 947 struct maple_softc *sc = device_private(dev); 948 #endif 949 950 if (enable) 951 u->u_noping &= ~MAPLE_FUNC(func); 952 else 953 u->u_noping |= MAPLE_FUNC(func); 954 } 955 956 /* schedule pinging a device */ 957 static void 958 maple_unit_ping(struct maple_softc *sc) 959 { 960 struct maple_unit *u; 961 struct maple_func *fn; 962 #ifdef MAPLE_MEMCARD_PING_HACK 963 static const uint32_t memcard_ping_arg[2] = { 964 0x02000000, /* htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD)) */ 965 0 /* pt (1 byte) and unused 3 bytes */ 966 }; 967 #endif 968 969 if ((u = TAILQ_FIRST(&sc->sc_pingq)) != NULL) { 970 KASSERT(u->u_queuestat == MAPLE_QUEUE_PING); 971 maple_remove_from_queues(sc, u); 972 if (u->u_dma_stat == MAPLE_DMA_IDLE && u->u_noping == 0) { 973 #ifdef MAPLE_MEMCARD_PING_HACK 974 if (u->u_ping_stat == MAPLE_PING_MINFO) { 975 /* use MINFO for some memory cards */ 976 maple_write_command(sc, u, 977 MAPLE_COMMAND_GETMINFO, 978 2, memcard_ping_arg); 979 } else 980 #endif 981 { 982 fn = &u->u_func[u->u_ping_func]; 983 fn->f_work = htobe32(MAPLE_FUNC(u->u_ping_func)); 984 maple_write_command(sc, u, 985 MAPLE_COMMAND_GETCOND, 986 1, &fn->f_work); 987 } 988 u->u_dma_stat = MAPLE_DMA_PING; 989 /* u->u_dma_func = XXX; */ 990 } else { 991 /* no need if periodic */ 992 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 993 u->u_queuestat = MAPLE_QUEUE_PING; 994 } 995 } 996 } 997 998 /* 999 * Enable/disable periodic GETCOND (called by drivers) 1000 */ 1001 void 1002 maple_enable_periodic(device_t dev, struct maple_unit *u, int func, int on) 1003 { 1004 struct maple_softc *sc = device_private(dev); 1005 struct maple_func *fn; 1006 1007 KASSERT(func >= 0 && func < 32); 1008 1009 fn = &u->u_func[func]; 1010 1011 if (on) { 1012 if (fn->f_periodic_stat == MAPLE_PERIODIC_NONE) { 1013 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1014 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1015 u->getcond_func_set |= MAPLE_FUNC(func); 1016 } 1017 } else { 1018 if (fn->f_periodic_stat == MAPLE_PERIODIC_INQ) 1019 TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq); 1020 else if (fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED) 1021 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1022 fn->f_periodic_stat = MAPLE_PERIODIC_NONE; 1023 u->getcond_func_set &= ~MAPLE_FUNC(func); 1024 } 1025 } 1026 1027 /* 1028 * queue periodic GETCOND 1029 */ 1030 static int 1031 maple_send_defered_periodic(struct maple_softc *sc) 1032 { 1033 struct maple_unit *u; 1034 struct maple_func *fn, *nextfn; 1035 int defer_remain = 0; 1036 1037 for (fn = TAILQ_FIRST(&sc->sc_periodicdeferq); fn; fn = nextfn) { 1038 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED); 1039 1040 nextfn = TAILQ_NEXT(fn, f_periodicq); 1041 1042 u = fn->f_unit; 1043 if (u->u_dma_stat == MAPLE_DMA_IDLE || 1044 u->u_dma_stat == MAPLE_DMA_RETRY) { 1045 /* 1046 * if IDLE -> queue this request 1047 * if RETRY -> the unit never be freed until the next 1048 * periodic timing, so just restore to 1049 * the normal periodic queue. 1050 */ 1051 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1052 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1053 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1054 1055 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 1056 /* 1057 * queue periodic command 1058 */ 1059 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1060 maple_write_command(sc, u, 1061 MAPLE_COMMAND_GETCOND, 1, &fn->f_work); 1062 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1063 u->u_dma_func = fn->f_funcno; 1064 } 1065 } else { 1066 defer_remain = 1; 1067 } 1068 } 1069 1070 return defer_remain; 1071 } 1072 1073 static void 1074 maple_send_periodic(struct maple_softc *sc) 1075 { 1076 struct maple_unit *u; 1077 struct maple_func *fn, *nextfn; 1078 1079 for (fn = TAILQ_FIRST(&sc->sc_periodicq); fn; fn = nextfn) { 1080 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_INQ); 1081 1082 nextfn = TAILQ_NEXT(fn, f_periodicq); 1083 1084 u = fn->f_unit; 1085 if (u->u_dma_stat != MAPLE_DMA_IDLE) { 1086 if (u->u_dma_stat != MAPLE_DMA_RETRY) { 1087 /* 1088 * can't be queued --- move to defered queue 1089 */ 1090 TAILQ_REMOVE(&sc->sc_periodicq, fn, 1091 f_periodicq); 1092 TAILQ_INSERT_TAIL(&sc->sc_periodicdeferq, fn, 1093 f_periodicq); 1094 fn->f_periodic_stat = MAPLE_PERIODIC_DEFERED; 1095 } 1096 } else { 1097 /* 1098 * queue periodic command 1099 */ 1100 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1101 maple_write_command(sc, u, MAPLE_COMMAND_GETCOND, 1102 1, &fn->f_work); 1103 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1104 u->u_dma_func = fn->f_funcno; 1105 } 1106 } 1107 } 1108 1109 static void 1110 maple_remove_from_queues(struct maple_softc *sc, struct maple_unit *u) 1111 { 1112 1113 /* remove from queues */ 1114 if (u->u_queuestat == MAPLE_QUEUE_PROBE) 1115 TAILQ_REMOVE(&sc->sc_probeq, u, u_q); 1116 else if (u->u_queuestat == MAPLE_QUEUE_PING) 1117 TAILQ_REMOVE(&sc->sc_pingq, u, u_q); 1118 #ifdef DIAGNOSTIC 1119 else if (u->u_queuestat != MAPLE_QUEUE_NONE) 1120 panic("maple_remove_from_queues: queuestat %d", u->u_queuestat); 1121 #endif 1122 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1123 if (u->u_queuestat != MAPLE_QUEUE_NONE) { 1124 char buf[16]; 1125 printf("%s: dequeued\n", 1126 maple_unit_name(buf, u->port, u->subunit)); 1127 } 1128 #endif 1129 1130 u->u_queuestat = MAPLE_QUEUE_NONE; 1131 } 1132 1133 /* 1134 * retry current command at next periodic timing 1135 */ 1136 static int 1137 maple_retry(struct maple_softc *sc, struct maple_unit *u, 1138 enum maple_dma_stat st) 1139 { 1140 1141 KASSERT(st != MAPLE_DMA_IDLE && st != MAPLE_DMA_RETRY); 1142 1143 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1144 if (u->u_retrycnt == 0) { 1145 char buf[16]; 1146 printf("%s: retrying: %#x, %#x, %p\n", 1147 maple_unit_name(buf, u->port, u->subunit), 1148 u->u_command, u->u_datalen, u->u_dataaddr); 1149 } 1150 #endif 1151 if (u->u_retrycnt >= MAPLE_RETRY_MAX) 1152 return 1; 1153 1154 u->u_retrycnt++; 1155 1156 u->u_saved_dma_stat = st; 1157 u->u_dma_stat = MAPLE_DMA_RETRY; /* no new command before retry done */ 1158 SIMPLEQ_INSERT_TAIL(&sc->sc_retryq, u, u_dmaq); 1159 1160 return 0; 1161 } 1162 1163 static void 1164 maple_queue_retry(struct maple_softc *sc) 1165 { 1166 struct maple_unit *u, *nextu; 1167 1168 /* 1169 * Note: since the queue element is queued immediately 1170 * in maple_queue_command, we can't use SIMPLEQ_FOREACH. 1171 */ 1172 for (u = SIMPLEQ_FIRST(&sc->sc_retryq); u; u = nextu) { 1173 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1174 1175 /* 1176 * Retrying is in the highest priority, and the unit shall 1177 * always be free. 1178 */ 1179 KASSERT(u->u_dma_stat == MAPLE_DMA_RETRY); 1180 maple_queue_command(sc, u, u->u_command, u->u_datalen, 1181 u->u_dataaddr); 1182 u->u_dma_stat = u->u_saved_dma_stat; 1183 1184 #ifdef DIAGNOSTIC 1185 KASSERT(u->u_saved_dma_stat != MAPLE_DMA_IDLE); 1186 u->u_saved_dma_stat = MAPLE_DMA_IDLE; 1187 #endif 1188 } 1189 SIMPLEQ_INIT(&sc->sc_retryq); 1190 } 1191 1192 /* 1193 * Process DMA results. 1194 * Requires kernel context. 1195 */ 1196 static void 1197 maple_check_responses(struct maple_softc *sc) 1198 { 1199 struct maple_unit *u, *nextu; 1200 struct maple_func *fn; 1201 maple_response_t response; 1202 int func_code, len; 1203 int flags; 1204 char buf[16]; 1205 1206 /* 1207 * Note: since the queue element may be queued immediately, 1208 * we can't use SIMPLEQ_FOREACH. 1209 */ 1210 for (u = SIMPLEQ_FIRST(&sc->sc_dmaq), maple_begin_txbuf(sc); 1211 u; u = nextu) { 1212 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1213 1214 if (u->u_dma_stat == MAPLE_DMA_IDLE) 1215 continue; /* just detached or DDB was active */ 1216 1217 /* 1218 * check for retransmission 1219 */ 1220 if ((response = u->u_rxbuf[0]) == MAPLE_RESPONSE_AGAIN) { 1221 if (maple_retry(sc, u, u->u_dma_stat) == 0) 1222 continue; 1223 /* else pass error to upper layer */ 1224 } 1225 1226 len = (u->u_rxbuf[0] >> 24); /* length in long */ 1227 len <<= 2; /* length in byte */ 1228 1229 /* 1230 * call handler 1231 */ 1232 if (u->u_dma_stat == MAPLE_DMA_PERIODIC) { 1233 /* 1234 * periodic GETCOND 1235 */ 1236 u->u_dma_stat = MAPLE_DMA_IDLE; 1237 func_code = u->u_dma_func; 1238 if (response == MAPLE_RESPONSE_DATATRF && len > 0 && 1239 be32toh(u->u_rxbuf[1]) == MAPLE_FUNC(func_code)) { 1240 fn = &u->u_func[func_code]; 1241 if (fn->f_dev) 1242 (*fn->f_callback)(fn->f_arg, 1243 (void *)u->u_rxbuf, len, 1244 MAPLE_FLAG_PERIODIC); 1245 } else if (response == MAPLE_RESPONSE_NONE) { 1246 /* XXX OK? */ 1247 /* detach */ 1248 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1249 printf("%s: func: %d: periodic response %d\n", 1250 maple_unit_name(buf, u->port, u->subunit), 1251 u->u_dma_func, 1252 response); 1253 #endif 1254 /* 1255 * Some 3rd party devices sometimes 1256 * do not respond. 1257 */ 1258 if (maple_retry(sc, u, MAPLE_DMA_PERIODIC)) 1259 maple_detach_unit(sc, u); 1260 } 1261 /* XXX check unexpected conditions? */ 1262 1263 } else if (u->u_dma_stat == MAPLE_DMA_PROBE) { 1264 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1265 u->u_dma_stat = MAPLE_DMA_IDLE; 1266 switch (response) { 1267 default: 1268 case MAPLE_RESPONSE_NONE: 1269 /* 1270 * Do not use maple_retry(), which conflicts 1271 * with probe structure. 1272 */ 1273 if (u->subunit != 0 && 1274 ++u->u_proberetry > MAPLE_PROBERETRY_MAX) { 1275 printf("%s: no response\n", 1276 maple_unit_name(buf, 1277 u->port, u->subunit)); 1278 } else { 1279 /* probe again */ 1280 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1281 printf("%s: queued to probe 4\n", 1282 maple_unit_name(buf, u->port, u->subunit)); 1283 #endif 1284 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, 1285 u_q); 1286 u->u_queuestat = MAPLE_QUEUE_PROBE; 1287 } 1288 break; 1289 case MAPLE_RESPONSE_DEVINFO: 1290 /* check if the unit is changed */ 1291 maple_check_unit_change(sc, u); 1292 break; 1293 } 1294 1295 } else if (u->u_dma_stat == MAPLE_DMA_PING) { 1296 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1297 u->u_dma_stat = MAPLE_DMA_IDLE; 1298 switch (response) { 1299 default: 1300 case MAPLE_RESPONSE_NONE: 1301 /* 1302 * Some 3rd party devices sometimes 1303 * do not respond. 1304 */ 1305 if (maple_retry(sc, u, MAPLE_DMA_PING)) { 1306 /* detach */ 1307 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1308 printf("%s: ping response %d\n", 1309 maple_unit_name(buf, u->port, 1310 u->subunit), 1311 response); 1312 #endif 1313 #ifdef MAPLE_MEMCARD_PING_HACK 1314 if (u->u_ping_stat 1315 == MAPLE_PING_MEMCARD) { 1316 /* 1317 * The unit claims itself to be 1318 * a Visual Memory, and has 1319 * never responded to GETCOND. 1320 * Try again using MINFO, in 1321 * case it is a poorly 1322 * implemented 3rd party card. 1323 */ 1324 #ifdef MAPLE_DEBUG 1325 printf("%s: switching ping method\n", 1326 maple_unit_name(buf, 1327 u->port, u->subunit)); 1328 #endif 1329 u->u_ping_stat 1330 = MAPLE_PING_MINFO; 1331 TAILQ_INSERT_TAIL(&sc->sc_pingq, 1332 u, u_q); 1333 u->u_queuestat 1334 = MAPLE_QUEUE_PING; 1335 } else 1336 #endif /* MAPLE_MEMCARD_PING_HACK */ 1337 maple_detach_unit(sc, u); 1338 } 1339 break; 1340 case MAPLE_RESPONSE_BADCMD: 1341 case MAPLE_RESPONSE_BADFUNC: 1342 case MAPLE_RESPONSE_DATATRF: 1343 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1344 u->u_queuestat = MAPLE_QUEUE_PING; 1345 #ifdef MAPLE_MEMCARD_PING_HACK 1346 /* 1347 * If the unit responds to GETCOND, it is a 1348 * normal implementation. 1349 */ 1350 if (u->u_ping_stat == MAPLE_PING_MEMCARD) 1351 u->u_ping_stat = MAPLE_PING_NORMAL; 1352 #endif 1353 break; 1354 } 1355 1356 } else { 1357 /* 1358 * Note: Do not rely on the consistency of responses. 1359 */ 1360 1361 if (response == MAPLE_RESPONSE_NONE) { 1362 if (maple_retry(sc, u, u->u_dma_stat)) { 1363 /* detach */ 1364 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1365 printf("%s: command response %d\n", 1366 maple_unit_name(buf, u->port, 1367 u->subunit), 1368 response); 1369 #endif 1370 maple_detach_unit(sc, u); 1371 } 1372 continue; 1373 } 1374 1375 flags = (u->u_dma_stat == MAPLE_DMA_PCMD) ? 1376 MAPLE_FLAG_CMD_PERIODIC_TIMING : 0; 1377 u->u_dma_stat = MAPLE_DMA_IDLE; 1378 1379 func_code = u->u_dma_func; 1380 fn = &u->u_func[func_code]; 1381 if (fn->f_dev == NULL) { 1382 /* detached right now */ 1383 #ifdef MAPLE_DEBUG 1384 printf("%s: unknown function: function %d, response %d\n", 1385 maple_unit_name(buf, u->port, u->subunit), 1386 func_code, response); 1387 #endif 1388 continue; 1389 } 1390 if (fn->f_callback != NULL) { 1391 (*fn->f_callback)(fn->f_arg, 1392 (void *)u->u_rxbuf, len, flags); 1393 } 1394 } 1395 1396 /* 1397 * check for subunit change and schedule probing subunits 1398 */ 1399 if (u->subunit == 0 && response != MAPLE_RESPONSE_NONE && 1400 response != MAPLE_RESPONSE_AGAIN && 1401 ((int8_t *) u->u_rxbuf)[2] != sc->sc_port_unit_map[u->port]) 1402 maple_check_subunit_change(sc, u); 1403 } 1404 } 1405 1406 /* 1407 * Main Maple Bus thread 1408 */ 1409 static void 1410 maple_event_thread(void *arg) 1411 { 1412 struct maple_softc *sc = arg; 1413 unsigned cnt = 1; /* timing counter */ 1414 int s; 1415 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1416 int noreq = 0; 1417 #endif 1418 1419 #ifdef MAPLE_DEBUG 1420 printf("%s: forked event thread, pid %d\n", 1421 device_xname(sc->sc_dev), sc->event_thread->l_proc->p_pid); 1422 #endif 1423 1424 /* begin first DMA cycle */ 1425 maple_begin_txbuf(sc); 1426 1427 sc->sc_event = 1; 1428 1429 /* OK, continue booting system */ 1430 maple_polling = 0; 1431 config_pending_decr(sc->sc_dev); 1432 1433 for (;;) { 1434 /* 1435 * queue requests 1436 */ 1437 1438 /* queue async commands */ 1439 if (!TAILQ_EMPTY(&sc->sc_acmdq)) 1440 maple_queue_cmds(sc, &sc->sc_acmdq); 1441 1442 /* send defered periodic command */ 1443 if (!TAILQ_EMPTY(&sc->sc_periodicdeferq)) 1444 maple_send_defered_periodic(sc); 1445 1446 /* queue periodic commands */ 1447 if (sc->sc_event) { 1448 /* queue commands on periodic timing */ 1449 if (!TAILQ_EMPTY(&sc->sc_pcmdq)) 1450 maple_queue_cmds(sc, &sc->sc_pcmdq); 1451 1452 /* retry */ 1453 if (!SIMPLEQ_EMPTY(&sc->sc_retryq)) 1454 maple_queue_retry(sc); 1455 1456 if ((cnt & 31) == 0) /* XXX */ 1457 maple_unit_probe(sc); 1458 cnt++; 1459 1460 maple_send_periodic(sc); 1461 if ((cnt & 7) == 0) /* XXX */ 1462 maple_unit_ping(sc); 1463 1464 /* 1465 * schedule periodic event 1466 */ 1467 sc->sc_event = 0; 1468 callout_reset(&sc->maple_callout_ch, 1469 MAPLE_CALLOUT_TICKS, maple_callout, sc); 1470 } 1471 1472 if (maple_end_txbuf(sc)) { 1473 1474 /* 1475 * start DMA 1476 */ 1477 s = splmaple(); 1478 maple_start(sc); 1479 1480 /* 1481 * wait until DMA done 1482 */ 1483 if (tsleep(&sc->sc_dmadone, PWAIT, "mdma", hz) 1484 == EWOULDBLOCK) { 1485 /* was DDB active? */ 1486 printf("%s: timed out\n", 1487 device_xname(sc->sc_dev)); 1488 } 1489 splx(s); 1490 1491 /* 1492 * call handlers 1493 */ 1494 maple_check_responses(sc); 1495 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1496 noreq = 0; 1497 #endif 1498 } 1499 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1500 else { 1501 /* weird if occurs in succession */ 1502 #if MAPLE_DEBUG <= 2 1503 if (noreq) /* ignore first time */ 1504 #endif 1505 printf("%s: no request %d\n", 1506 device_xname(sc->sc_dev), noreq); 1507 noreq++; 1508 } 1509 #endif 1510 1511 /* 1512 * wait for an event 1513 */ 1514 s = splsoftclock(); 1515 if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 && 1516 TAILQ_EMPTY(&sc->sc_periodicdeferq)) { 1517 if (tsleep(&sc->sc_event, PWAIT, "mslp", hz) 1518 == EWOULDBLOCK) { 1519 printf("%s: event timed out\n", 1520 device_xname(sc->sc_dev)); 1521 } 1522 1523 } 1524 splx(s); 1525 1526 } 1527 1528 #if 0 /* maple root device can't be detached */ 1529 kthread_exit(0); 1530 /* NOTREACHED */ 1531 #endif 1532 } 1533 1534 static int 1535 maple_intr(void *arg) 1536 { 1537 struct maple_softc *sc = arg; 1538 1539 wakeup(&sc->sc_dmadone); 1540 1541 return 1; 1542 } 1543 1544 static void 1545 maple_callout(void *ctx) 1546 { 1547 struct maple_softc *sc = ctx; 1548 1549 sc->sc_event = 1; /* mark as periodic event */ 1550 wakeup(&sc->sc_event); 1551 } 1552 1553 /* 1554 * Install callback handler (called by drivers) 1555 */ 1556 /* ARGSUSED */ 1557 void 1558 maple_set_callback(device_t dev, struct maple_unit *u, int func, 1559 void (*callback)(void *, struct maple_response *, int, int), void *arg) 1560 { 1561 #if 0 /* currently unused */ 1562 struct maple_softc *sc = device_private(dev); 1563 #endif 1564 struct maple_func *fn; 1565 1566 KASSERT(func >= 0 && func < MAPLE_NFUNC); 1567 1568 fn = &u->u_func[func]; 1569 1570 fn->f_callback = callback; 1571 fn->f_arg = arg; 1572 } 1573 1574 /* 1575 * Return function definition data (called by drivers) 1576 */ 1577 uint32_t 1578 maple_get_function_data(struct maple_devinfo *devinfo, int function_code) 1579 { 1580 int i, p = 0; 1581 uint32_t func; 1582 1583 func = be32toh(devinfo->di_func); 1584 for (i = 31; i >= 0; --i) 1585 if (func & MAPLE_FUNC(i)) { 1586 if (function_code == i) 1587 return be32toh(devinfo->di_function_data[p]); 1588 else 1589 if (++p >= 3) 1590 break; 1591 } 1592 1593 return 0; 1594 } 1595 1596 /* Generic maple device interface */ 1597 1598 int 1599 mapleopen(dev_t dev, int flag, int mode, struct lwp *l) 1600 { 1601 struct maple_softc *sc; 1602 1603 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1604 if (sc == NULL) /* make sure it was attached */ 1605 return ENXIO; 1606 1607 if (MAPLEPORT(dev) >= MAPLE_PORTS) 1608 return ENXIO; 1609 1610 if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS) 1611 return ENXIO; 1612 1613 if (!(sc->sc_port_units[MAPLEPORT(dev)] & (1 << MAPLESUBUNIT(dev)))) 1614 return ENXIO; 1615 1616 sc->sc_port_units_open[MAPLEPORT(dev)] |= 1 << MAPLESUBUNIT(dev); 1617 1618 return 0; 1619 } 1620 1621 int 1622 mapleclose(dev_t dev, int flag, int mode, struct lwp *l) 1623 { 1624 struct maple_softc *sc; 1625 1626 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1627 1628 sc->sc_port_units_open[MAPLEPORT(dev)] &= ~(1 << MAPLESUBUNIT(dev)); 1629 1630 return 0; 1631 } 1632 1633 int 1634 maple_unit_ioctl(device_t dev, struct maple_unit *u, u_long cmd, 1635 void *data, int flag, struct lwp *l) 1636 { 1637 struct maple_softc *sc = device_private(dev); 1638 1639 if (!(sc->sc_port_units[u->port] & (1 << u->subunit))) 1640 return ENXIO; 1641 1642 switch(cmd) { 1643 case MAPLEIO_GDEVINFO: 1644 memcpy(data, &u->devinfo, sizeof(struct maple_devinfo)); 1645 break; 1646 default: 1647 return EPASSTHROUGH; 1648 } 1649 1650 return 0; 1651 } 1652 1653 int 1654 mapleioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1655 { 1656 struct maple_softc *sc; 1657 struct maple_unit *u; 1658 1659 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1660 u = &sc->sc_unit[MAPLEPORT(dev)][MAPLESUBUNIT(dev)]; 1661 1662 return maple_unit_ioctl(sc->sc_dev, u, cmd, data, flag, l); 1663 } 1664