1 /* $NetBSD: maple.c,v 1.40 2008/10/19 14:05:49 mjf 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.40 2008/10/19 14:05:49 mjf Exp $"); 66 67 #include <sys/param.h> 68 #include <sys/device.h> 69 #include <sys/fcntl.h> 70 #include <sys/kernel.h> 71 #include <sys/kthread.h> 72 #include <sys/poll.h> 73 #include <sys/select.h> 74 #include <sys/proc.h> 75 #include <sys/signalvar.h> 76 #include <sys/systm.h> 77 #include <sys/conf.h> 78 79 #include <uvm/uvm_extern.h> 80 81 #include <machine/cpu.h> 82 #include <machine/bus.h> 83 #include <machine/sysasicvar.h> 84 #include <sh3/pmap.h> 85 86 #include <dreamcast/dev/maple/maple.h> 87 #include <dreamcast/dev/maple/mapleconf.h> 88 #include <dreamcast/dev/maple/maplevar.h> 89 #include <dreamcast/dev/maple/maplereg.h> 90 #include <dreamcast/dev/maple/mapleio.h> 91 92 #include "locators.h" 93 94 /* Internal macros, functions, and variables. */ 95 96 #define MAPLE_CALLOUT_TICKS 2 97 98 #define MAPLEBUSUNIT(dev) (minor(dev)>>5) 99 #define MAPLEPORT(dev) ((minor(dev) & 0x18) >> 3) 100 #define MAPLESUBUNIT(dev) (minor(dev) & 0x7) 101 102 /* interrupt priority level */ 103 #define IPL_MAPLE IPL_BIO 104 #define splmaple() splbio() 105 #define IRL_MAPLE SYSASIC_IRL9 106 107 /* 108 * Function declarations. 109 */ 110 static int maplematch(struct device *, struct cfdata *, void *); 111 static void mapleattach(struct device *, struct device *, void *); 112 static void maple_scanbus(struct maple_softc *); 113 static char * maple_unit_name(char *, int port, int subunit); 114 static void maple_begin_txbuf(struct maple_softc *); 115 static int maple_end_txbuf(struct maple_softc *); 116 static void maple_queue_command(struct maple_softc *, struct maple_unit *, 117 int command, int datalen, const void *dataaddr); 118 static void maple_write_command(struct maple_softc *, struct maple_unit *, 119 int, int, const void *); 120 static void maple_start(struct maple_softc *sc); 121 static void maple_start_poll(struct maple_softc *); 122 static void maple_check_subunit_change(struct maple_softc *, 123 struct maple_unit *); 124 static void maple_check_unit_change(struct maple_softc *, 125 struct maple_unit *); 126 static void maple_print_unit(void *, const char *); 127 static int maplesubmatch(struct device *, struct cfdata *, 128 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(maple, sizeof(struct maple_softc), 161 maplematch, mapleattach, NULL, NULL); 162 163 extern struct cfdriver maple_cd; 164 165 dev_type_open(mapleopen); 166 dev_type_close(mapleclose); 167 dev_type_ioctl(mapleioctl); 168 169 const struct cdevsw maple_cdevsw = { 170 mapleopen, mapleclose, noread, nowrite, mapleioctl, 171 nostop, notty, nopoll, nommap, nokqfilter, 172 }; 173 174 static int 175 maplematch(struct device *parent, struct cfdata *cf, void *aux) 176 { 177 178 return 1; 179 } 180 181 static void 182 mapleattach(struct device *parent, struct device *self, void *aux) 183 { 184 struct maple_softc *sc; 185 struct maple_unit *u; 186 vaddr_t dmabuffer; 187 paddr_t dmabuffer_phys; 188 uint32_t *p; 189 int port, subunit, f; 190 191 sc = (struct maple_softc *)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 sc->sc_dev.dv_xname); 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", sc->sc_dev.dv_xname) == 0) 250 return; 251 252 panic("%s: unable to create event thread", sc->sc_dev.dv_xname); 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(struct device *dev) 308 { 309 struct maple_softc *sc; 310 int port, subunit; 311 int i; 312 313 sc = (struct maple_softc *)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, sc->sc_dev.dv_xname); 676 printf("\n"); 677 strcpy(oldxname, sc->sc_dev.dv_xname); 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 fn->f_dev->dv_xname, 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(struct device *dev, struct maple_unit *u, int func, 825 int command, int datalen, const void *dataaddr, int flags) 826 { 827 struct maple_softc *sc = (void *) 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(struct device *dev, struct maple_unit *u, 947 int func, int enable) 948 { 949 #if 0 /* currently unused */ 950 struct maple_softc *sc = (void *) dev; 951 #endif 952 953 if (enable) 954 u->u_noping &= ~MAPLE_FUNC(func); 955 else 956 u->u_noping |= MAPLE_FUNC(func); 957 } 958 959 /* schedule pinging a device */ 960 static void 961 maple_unit_ping(struct maple_softc *sc) 962 { 963 struct maple_unit *u; 964 struct maple_func *fn; 965 #ifdef MAPLE_MEMCARD_PING_HACK 966 static const uint32_t memcard_ping_arg[2] = { 967 0x02000000, /* htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD)) */ 968 0 /* pt (1 byte) and unused 3 bytes */ 969 }; 970 #endif 971 972 if ((u = TAILQ_FIRST(&sc->sc_pingq)) != NULL) { 973 KASSERT(u->u_queuestat == MAPLE_QUEUE_PING); 974 maple_remove_from_queues(sc, u); 975 if (u->u_dma_stat == MAPLE_DMA_IDLE && u->u_noping == 0) { 976 #ifdef MAPLE_MEMCARD_PING_HACK 977 if (u->u_ping_stat == MAPLE_PING_MINFO) { 978 /* use MINFO for some memory cards */ 979 maple_write_command(sc, u, 980 MAPLE_COMMAND_GETMINFO, 981 2, memcard_ping_arg); 982 } else 983 #endif 984 { 985 fn = &u->u_func[u->u_ping_func]; 986 fn->f_work = htobe32(MAPLE_FUNC(u->u_ping_func)); 987 maple_write_command(sc, u, 988 MAPLE_COMMAND_GETCOND, 989 1, &fn->f_work); 990 } 991 u->u_dma_stat = MAPLE_DMA_PING; 992 /* u->u_dma_func = XXX; */ 993 } else { 994 /* no need if periodic */ 995 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 996 u->u_queuestat = MAPLE_QUEUE_PING; 997 } 998 } 999 } 1000 1001 /* 1002 * Enable/disable periodic GETCOND (called by drivers) 1003 */ 1004 void 1005 maple_enable_periodic(struct device *dev, struct maple_unit *u, 1006 int func, int on) 1007 { 1008 struct maple_softc *sc = (void *) dev; 1009 struct maple_func *fn; 1010 1011 KASSERT(func >= 0 && func < 32); 1012 1013 fn = &u->u_func[func]; 1014 1015 if (on) { 1016 if (fn->f_periodic_stat == MAPLE_PERIODIC_NONE) { 1017 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1018 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1019 u->getcond_func_set |= MAPLE_FUNC(func); 1020 } 1021 } else { 1022 if (fn->f_periodic_stat == MAPLE_PERIODIC_INQ) 1023 TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq); 1024 else if (fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED) 1025 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1026 fn->f_periodic_stat = MAPLE_PERIODIC_NONE; 1027 u->getcond_func_set &= ~MAPLE_FUNC(func); 1028 } 1029 } 1030 1031 /* 1032 * queue periodic GETCOND 1033 */ 1034 static int 1035 maple_send_defered_periodic(struct maple_softc *sc) 1036 { 1037 struct maple_unit *u; 1038 struct maple_func *fn, *nextfn; 1039 int defer_remain = 0; 1040 1041 for (fn = TAILQ_FIRST(&sc->sc_periodicdeferq); fn; fn = nextfn) { 1042 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED); 1043 1044 nextfn = TAILQ_NEXT(fn, f_periodicq); 1045 1046 u = fn->f_unit; 1047 if (u->u_dma_stat == MAPLE_DMA_IDLE || 1048 u->u_dma_stat == MAPLE_DMA_RETRY) { 1049 /* 1050 * if IDLE -> queue this request 1051 * if RETRY -> the unit never be freed until the next 1052 * periodic timing, so just restore to 1053 * the normal periodic queue. 1054 */ 1055 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1056 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1057 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1058 1059 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 1060 /* 1061 * queue periodic command 1062 */ 1063 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1064 maple_write_command(sc, u, 1065 MAPLE_COMMAND_GETCOND, 1, &fn->f_work); 1066 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1067 u->u_dma_func = fn->f_funcno; 1068 } 1069 } else { 1070 defer_remain = 1; 1071 } 1072 } 1073 1074 return defer_remain; 1075 } 1076 1077 static void 1078 maple_send_periodic(struct maple_softc *sc) 1079 { 1080 struct maple_unit *u; 1081 struct maple_func *fn, *nextfn; 1082 1083 for (fn = TAILQ_FIRST(&sc->sc_periodicq); fn; fn = nextfn) { 1084 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_INQ); 1085 1086 nextfn = TAILQ_NEXT(fn, f_periodicq); 1087 1088 u = fn->f_unit; 1089 if (u->u_dma_stat != MAPLE_DMA_IDLE) { 1090 if (u->u_dma_stat != MAPLE_DMA_RETRY) { 1091 /* 1092 * can't be queued --- move to defered queue 1093 */ 1094 TAILQ_REMOVE(&sc->sc_periodicq, fn, 1095 f_periodicq); 1096 TAILQ_INSERT_TAIL(&sc->sc_periodicdeferq, fn, 1097 f_periodicq); 1098 fn->f_periodic_stat = MAPLE_PERIODIC_DEFERED; 1099 } 1100 } else { 1101 /* 1102 * queue periodic command 1103 */ 1104 fn->f_work = htobe32(MAPLE_FUNC(fn->f_funcno)); 1105 maple_write_command(sc, u, MAPLE_COMMAND_GETCOND, 1106 1, &fn->f_work); 1107 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1108 u->u_dma_func = fn->f_funcno; 1109 } 1110 } 1111 } 1112 1113 static void 1114 maple_remove_from_queues(struct maple_softc *sc, struct maple_unit *u) 1115 { 1116 1117 /* remove from queues */ 1118 if (u->u_queuestat == MAPLE_QUEUE_PROBE) 1119 TAILQ_REMOVE(&sc->sc_probeq, u, u_q); 1120 else if (u->u_queuestat == MAPLE_QUEUE_PING) 1121 TAILQ_REMOVE(&sc->sc_pingq, u, u_q); 1122 #ifdef DIAGNOSTIC 1123 else if (u->u_queuestat != MAPLE_QUEUE_NONE) 1124 panic("maple_remove_from_queues: queuestat %d", u->u_queuestat); 1125 #endif 1126 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1127 if (u->u_queuestat != MAPLE_QUEUE_NONE) { 1128 char buf[16]; 1129 printf("%s: dequeued\n", 1130 maple_unit_name(buf, u->port, u->subunit)); 1131 } 1132 #endif 1133 1134 u->u_queuestat = MAPLE_QUEUE_NONE; 1135 } 1136 1137 /* 1138 * retry current command at next periodic timing 1139 */ 1140 static int 1141 maple_retry(struct maple_softc *sc, struct maple_unit *u, 1142 enum maple_dma_stat st) 1143 { 1144 1145 KASSERT(st != MAPLE_DMA_IDLE && st != MAPLE_DMA_RETRY); 1146 1147 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1148 if (u->u_retrycnt == 0) { 1149 char buf[16]; 1150 printf("%s: retrying: %#x, %#x, %p\n", 1151 maple_unit_name(buf, u->port, u->subunit), 1152 u->u_command, u->u_datalen, u->u_dataaddr); 1153 } 1154 #endif 1155 if (u->u_retrycnt >= MAPLE_RETRY_MAX) 1156 return 1; 1157 1158 u->u_retrycnt++; 1159 1160 u->u_saved_dma_stat = st; 1161 u->u_dma_stat = MAPLE_DMA_RETRY; /* no new command before retry done */ 1162 SIMPLEQ_INSERT_TAIL(&sc->sc_retryq, u, u_dmaq); 1163 1164 return 0; 1165 } 1166 1167 static void 1168 maple_queue_retry(struct maple_softc *sc) 1169 { 1170 struct maple_unit *u, *nextu; 1171 1172 /* 1173 * Note: since the queue element is queued immediately 1174 * in maple_queue_command, we can't use SIMPLEQ_FOREACH. 1175 */ 1176 for (u = SIMPLEQ_FIRST(&sc->sc_retryq); u; u = nextu) { 1177 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1178 1179 /* 1180 * Retrying is in the highest priority, and the unit shall 1181 * always be free. 1182 */ 1183 KASSERT(u->u_dma_stat == MAPLE_DMA_RETRY); 1184 maple_queue_command(sc, u, u->u_command, u->u_datalen, 1185 u->u_dataaddr); 1186 u->u_dma_stat = u->u_saved_dma_stat; 1187 1188 #ifdef DIAGNOSTIC 1189 KASSERT(u->u_saved_dma_stat != MAPLE_DMA_IDLE); 1190 u->u_saved_dma_stat = MAPLE_DMA_IDLE; 1191 #endif 1192 } 1193 SIMPLEQ_INIT(&sc->sc_retryq); 1194 } 1195 1196 /* 1197 * Process DMA results. 1198 * Requires kernel context. 1199 */ 1200 static void 1201 maple_check_responses(struct maple_softc *sc) 1202 { 1203 struct maple_unit *u, *nextu; 1204 struct maple_func *fn; 1205 maple_response_t response; 1206 int func_code, len; 1207 int flags; 1208 char buf[16]; 1209 1210 /* 1211 * Note: since the queue element may be queued immediately, 1212 * we can't use SIMPLEQ_FOREACH. 1213 */ 1214 for (u = SIMPLEQ_FIRST(&sc->sc_dmaq), maple_begin_txbuf(sc); 1215 u; u = nextu) { 1216 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1217 1218 if (u->u_dma_stat == MAPLE_DMA_IDLE) 1219 continue; /* just detached or DDB was active */ 1220 1221 /* 1222 * check for retransmission 1223 */ 1224 if ((response = u->u_rxbuf[0]) == MAPLE_RESPONSE_AGAIN) { 1225 if (maple_retry(sc, u, u->u_dma_stat) == 0) 1226 continue; 1227 /* else pass error to upper layer */ 1228 } 1229 1230 len = (u->u_rxbuf[0] >> 24); /* length in long */ 1231 len <<= 2; /* length in byte */ 1232 1233 /* 1234 * call handler 1235 */ 1236 if (u->u_dma_stat == MAPLE_DMA_PERIODIC) { 1237 /* 1238 * periodic GETCOND 1239 */ 1240 u->u_dma_stat = MAPLE_DMA_IDLE; 1241 func_code = u->u_dma_func; 1242 if (response == MAPLE_RESPONSE_DATATRF && len > 0 && 1243 be32toh(u->u_rxbuf[1]) == MAPLE_FUNC(func_code)) { 1244 fn = &u->u_func[func_code]; 1245 if (fn->f_dev) 1246 (*fn->f_callback)(fn->f_arg, 1247 (void *)u->u_rxbuf, len, 1248 MAPLE_FLAG_PERIODIC); 1249 } else if (response == MAPLE_RESPONSE_NONE) { 1250 /* XXX OK? */ 1251 /* detach */ 1252 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1253 printf("%s: func: %d: periodic response %d\n", 1254 maple_unit_name(buf, u->port, u->subunit), 1255 u->u_dma_func, 1256 response); 1257 #endif 1258 /* 1259 * Some 3rd party devices sometimes 1260 * do not respond. 1261 */ 1262 if (maple_retry(sc, u, MAPLE_DMA_PERIODIC)) 1263 maple_detach_unit(sc, u); 1264 } 1265 /* XXX check unexpected conditions? */ 1266 1267 } else if (u->u_dma_stat == MAPLE_DMA_PROBE) { 1268 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1269 u->u_dma_stat = MAPLE_DMA_IDLE; 1270 switch (response) { 1271 default: 1272 case MAPLE_RESPONSE_NONE: 1273 /* 1274 * Do not use maple_retry(), which conflicts 1275 * with probe structure. 1276 */ 1277 if (u->subunit != 0 && 1278 ++u->u_proberetry > MAPLE_PROBERETRY_MAX) { 1279 printf("%s: no response\n", 1280 maple_unit_name(buf, 1281 u->port, u->subunit)); 1282 } else { 1283 /* probe again */ 1284 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1285 printf("%s: queued to probe 4\n", 1286 maple_unit_name(buf, u->port, u->subunit)); 1287 #endif 1288 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, 1289 u_q); 1290 u->u_queuestat = MAPLE_QUEUE_PROBE; 1291 } 1292 break; 1293 case MAPLE_RESPONSE_DEVINFO: 1294 /* check if the unit is changed */ 1295 maple_check_unit_change(sc, u); 1296 break; 1297 } 1298 1299 } else if (u->u_dma_stat == MAPLE_DMA_PING) { 1300 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1301 u->u_dma_stat = MAPLE_DMA_IDLE; 1302 switch (response) { 1303 default: 1304 case MAPLE_RESPONSE_NONE: 1305 /* 1306 * Some 3rd party devices sometimes 1307 * do not respond. 1308 */ 1309 if (maple_retry(sc, u, MAPLE_DMA_PING)) { 1310 /* detach */ 1311 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1312 printf("%s: ping response %d\n", 1313 maple_unit_name(buf, u->port, 1314 u->subunit), 1315 response); 1316 #endif 1317 #ifdef MAPLE_MEMCARD_PING_HACK 1318 if (u->u_ping_stat 1319 == MAPLE_PING_MEMCARD) { 1320 /* 1321 * The unit claims itself to be 1322 * a Visual Memory, and has 1323 * never responded to GETCOND. 1324 * Try again using MINFO, in 1325 * case it is a poorly 1326 * implemented 3rd party card. 1327 */ 1328 #ifdef MAPLE_DEBUG 1329 printf("%s: switching ping method\n", 1330 maple_unit_name(buf, 1331 u->port, u->subunit)); 1332 #endif 1333 u->u_ping_stat 1334 = MAPLE_PING_MINFO; 1335 TAILQ_INSERT_TAIL(&sc->sc_pingq, 1336 u, u_q); 1337 u->u_queuestat 1338 = MAPLE_QUEUE_PING; 1339 } else 1340 #endif /* MAPLE_MEMCARD_PING_HACK */ 1341 maple_detach_unit(sc, u); 1342 } 1343 break; 1344 case MAPLE_RESPONSE_BADCMD: 1345 case MAPLE_RESPONSE_BADFUNC: 1346 case MAPLE_RESPONSE_DATATRF: 1347 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1348 u->u_queuestat = MAPLE_QUEUE_PING; 1349 #ifdef MAPLE_MEMCARD_PING_HACK 1350 /* 1351 * If the unit responds to GETCOND, it is a 1352 * normal implementation. 1353 */ 1354 if (u->u_ping_stat == MAPLE_PING_MEMCARD) 1355 u->u_ping_stat = MAPLE_PING_NORMAL; 1356 #endif 1357 break; 1358 } 1359 1360 } else { 1361 /* 1362 * Note: Do not rely on the consistency of responses. 1363 */ 1364 1365 if (response == MAPLE_RESPONSE_NONE) { 1366 if (maple_retry(sc, u, u->u_dma_stat)) { 1367 /* detach */ 1368 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1369 printf("%s: command response %d\n", 1370 maple_unit_name(buf, u->port, 1371 u->subunit), 1372 response); 1373 #endif 1374 maple_detach_unit(sc, u); 1375 } 1376 continue; 1377 } 1378 1379 flags = (u->u_dma_stat == MAPLE_DMA_PCMD) ? 1380 MAPLE_FLAG_CMD_PERIODIC_TIMING : 0; 1381 u->u_dma_stat = MAPLE_DMA_IDLE; 1382 1383 func_code = u->u_dma_func; 1384 fn = &u->u_func[func_code]; 1385 if (fn->f_dev == NULL) { 1386 /* detached right now */ 1387 #ifdef MAPLE_DEBUG 1388 printf("%s: unknown function: function %d, response %d\n", 1389 maple_unit_name(buf, u->port, u->subunit), 1390 func_code, response); 1391 #endif 1392 continue; 1393 } 1394 if (fn->f_callback != NULL) { 1395 (*fn->f_callback)(fn->f_arg, 1396 (void *)u->u_rxbuf, len, flags); 1397 } 1398 } 1399 1400 /* 1401 * check for subunit change and schedule probing subunits 1402 */ 1403 if (u->subunit == 0 && response != MAPLE_RESPONSE_NONE && 1404 response != MAPLE_RESPONSE_AGAIN && 1405 ((int8_t *) u->u_rxbuf)[2] != sc->sc_port_unit_map[u->port]) 1406 maple_check_subunit_change(sc, u); 1407 } 1408 } 1409 1410 /* 1411 * Main Maple Bus thread 1412 */ 1413 static void 1414 maple_event_thread(void *arg) 1415 { 1416 struct maple_softc *sc = arg; 1417 unsigned cnt = 1; /* timing counter */ 1418 int s; 1419 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1420 int noreq = 0; 1421 #endif 1422 1423 #ifdef MAPLE_DEBUG 1424 printf("%s: forked event thread, pid %d\n", 1425 sc->sc_dev.dv_xname, sc->event_thread->l_proc->p_pid); 1426 #endif 1427 1428 /* begin first DMA cycle */ 1429 maple_begin_txbuf(sc); 1430 1431 sc->sc_event = 1; 1432 1433 /* OK, continue booting system */ 1434 maple_polling = 0; 1435 config_pending_decr(); 1436 1437 for (;;) { 1438 /* 1439 * queue requests 1440 */ 1441 1442 /* queue async commands */ 1443 if (!TAILQ_EMPTY(&sc->sc_acmdq)) 1444 maple_queue_cmds(sc, &sc->sc_acmdq); 1445 1446 /* send defered periodic command */ 1447 if (!TAILQ_EMPTY(&sc->sc_periodicdeferq)) 1448 maple_send_defered_periodic(sc); 1449 1450 /* queue periodic commands */ 1451 if (sc->sc_event) { 1452 /* queue commands on periodic timing */ 1453 if (!TAILQ_EMPTY(&sc->sc_pcmdq)) 1454 maple_queue_cmds(sc, &sc->sc_pcmdq); 1455 1456 /* retry */ 1457 if (!SIMPLEQ_EMPTY(&sc->sc_retryq)) 1458 maple_queue_retry(sc); 1459 1460 if ((cnt & 31) == 0) /* XXX */ 1461 maple_unit_probe(sc); 1462 cnt++; 1463 1464 maple_send_periodic(sc); 1465 if ((cnt & 7) == 0) /* XXX */ 1466 maple_unit_ping(sc); 1467 1468 /* 1469 * schedule periodic event 1470 */ 1471 sc->sc_event = 0; 1472 callout_reset(&sc->maple_callout_ch, 1473 MAPLE_CALLOUT_TICKS, maple_callout, sc); 1474 } 1475 1476 if (maple_end_txbuf(sc)) { 1477 1478 /* 1479 * start DMA 1480 */ 1481 s = splmaple(); 1482 maple_start(sc); 1483 1484 /* 1485 * wait until DMA done 1486 */ 1487 if (tsleep(&sc->sc_dmadone, PWAIT, "mdma", hz) 1488 == EWOULDBLOCK) { 1489 /* was DDB active? */ 1490 printf("%s: timed out\n", sc->sc_dev.dv_xname); 1491 } 1492 splx(s); 1493 1494 /* 1495 * call handlers 1496 */ 1497 maple_check_responses(sc); 1498 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1499 noreq = 0; 1500 #endif 1501 } 1502 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1503 else { 1504 /* weird if occurs in succession */ 1505 #if MAPLE_DEBUG <= 2 1506 if (noreq) /* ignore first time */ 1507 #endif 1508 printf("%s: no request %d\n", 1509 sc->sc_dev.dv_xname, noreq); 1510 noreq++; 1511 } 1512 #endif 1513 1514 /* 1515 * wait for an event 1516 */ 1517 s = splsoftclock(); 1518 if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 && 1519 TAILQ_EMPTY(&sc->sc_periodicdeferq)) { 1520 if (tsleep(&sc->sc_event, PWAIT, "mslp", hz) 1521 == EWOULDBLOCK) { 1522 printf("%s: event timed out\n", 1523 sc->sc_dev.dv_xname); 1524 } 1525 1526 } 1527 splx(s); 1528 1529 } 1530 1531 #if 0 /* maple root device can't be detached */ 1532 kthread_exit(0); 1533 /* NOTREACHED */ 1534 #endif 1535 } 1536 1537 static int 1538 maple_intr(void *arg) 1539 { 1540 struct maple_softc *sc = arg; 1541 1542 wakeup(&sc->sc_dmadone); 1543 1544 return 1; 1545 } 1546 1547 static void 1548 maple_callout(void *ctx) 1549 { 1550 struct maple_softc *sc = ctx; 1551 1552 sc->sc_event = 1; /* mark as periodic event */ 1553 wakeup(&sc->sc_event); 1554 } 1555 1556 /* 1557 * Install callback handler (called by drivers) 1558 */ 1559 /* ARGSUSED */ 1560 void 1561 maple_set_callback(struct device *dev, struct maple_unit *u, int func, 1562 void (*callback)(void *, struct maple_response *, int, int), void *arg) 1563 { 1564 #if 0 /* currently unused */ 1565 struct maple_softc *sc = (void *) dev; 1566 #endif 1567 struct maple_func *fn; 1568 1569 KASSERT(func >= 0 && func < MAPLE_NFUNC); 1570 1571 fn = &u->u_func[func]; 1572 1573 fn->f_callback = callback; 1574 fn->f_arg = arg; 1575 } 1576 1577 /* 1578 * Return function definition data (called by drivers) 1579 */ 1580 uint32_t 1581 maple_get_function_data(struct maple_devinfo *devinfo, int function_code) 1582 { 1583 int i, p = 0; 1584 uint32_t func; 1585 1586 func = be32toh(devinfo->di_func); 1587 for (i = 31; i >= 0; --i) 1588 if (func & MAPLE_FUNC(i)) { 1589 if (function_code == i) 1590 return be32toh(devinfo->di_function_data[p]); 1591 else 1592 if (++p >= 3) 1593 break; 1594 } 1595 1596 return 0; 1597 } 1598 1599 /* Generic maple device interface */ 1600 1601 int 1602 mapleopen(dev_t dev, int flag, int mode, struct lwp *l) 1603 { 1604 struct maple_softc *sc; 1605 1606 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1607 if (sc == NULL) /* make sure it was attached */ 1608 return ENXIO; 1609 1610 if (MAPLEPORT(dev) >= MAPLE_PORTS) 1611 return ENXIO; 1612 1613 if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS) 1614 return ENXIO; 1615 1616 if (!(sc->sc_port_units[MAPLEPORT(dev)] & (1 << MAPLESUBUNIT(dev)))) 1617 return ENXIO; 1618 1619 sc->sc_port_units_open[MAPLEPORT(dev)] |= 1 << MAPLESUBUNIT(dev); 1620 1621 return 0; 1622 } 1623 1624 int 1625 mapleclose(dev_t dev, int flag, int mode, struct lwp *l) 1626 { 1627 struct maple_softc *sc; 1628 1629 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1630 1631 sc->sc_port_units_open[MAPLEPORT(dev)] &= ~(1 << MAPLESUBUNIT(dev)); 1632 1633 return 0; 1634 } 1635 1636 int 1637 maple_unit_ioctl(struct device *dev, struct maple_unit *u, u_long cmd, 1638 void *data, int flag, struct lwp *l) 1639 { 1640 struct maple_softc *sc = (struct maple_softc *)dev; 1641 1642 if (!(sc->sc_port_units[u->port] & (1 << u->subunit))) 1643 return ENXIO; 1644 1645 switch(cmd) { 1646 case MAPLEIO_GDEVINFO: 1647 memcpy(data, &u->devinfo, sizeof(struct maple_devinfo)); 1648 break; 1649 default: 1650 return EPASSTHROUGH; 1651 } 1652 1653 return 0; 1654 } 1655 1656 int 1657 mapleioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1658 { 1659 struct maple_softc *sc; 1660 struct maple_unit *u; 1661 1662 sc = device_lookup_private(&maple_cd, MAPLEBUSUNIT(dev)); 1663 u = &sc->sc_unit[MAPLEPORT(dev)][MAPLESUBUNIT(dev)]; 1664 1665 return maple_unit_ioctl(&sc->sc_dev, u, cmd, data, flag, l); 1666 } 1667