1 /* $NetBSD: fwdev.c,v 1.25 2011/05/25 16:33:37 uebayasi Exp $ */ 2 /*- 3 * Copyright (c) 2003 Hidetoshi Shimokawa 4 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the acknowledgement as bellow: 17 * 18 * This product includes software developed by K. Kobayashi and H. Shimokawa 19 * 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.52 2007/06/06 14:31:36 simokawa Exp $ 36 * 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: fwdev.c,v 1.25 2011/05/25 16:33:37 uebayasi Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/device.h> 44 #include <sys/errno.h> 45 #include <sys/buf.h> 46 #include <sys/bus.h> 47 #include <sys/conf.h> 48 #include <sys/kernel.h> 49 #include <sys/malloc.h> 50 #include <sys/mbuf.h> 51 #include <sys/poll.h> 52 #include <sys/proc.h> 53 #include <sys/select.h> 54 55 #include <dev/ieee1394/firewire.h> 56 #include <dev/ieee1394/firewirereg.h> 57 #include <dev/ieee1394/fwdma.h> 58 #include <dev/ieee1394/fwmem.h> 59 #include <dev/ieee1394/iec68113.h> 60 61 #define FWNODE_INVAL 0xffff 62 63 dev_type_open(fw_open); 64 dev_type_close(fw_close); 65 dev_type_read(fw_read); 66 dev_type_write(fw_write); 67 dev_type_ioctl(fw_ioctl); 68 dev_type_poll(fw_poll); 69 dev_type_mmap(fw_mmap); 70 dev_type_strategy(fw_strategy); 71 72 const struct bdevsw fw_bdevsw = { 73 fw_open, fw_close, fw_strategy, fw_ioctl, nodump, nosize, D_OTHER, 74 }; 75 76 const struct cdevsw fw_cdevsw = { 77 fw_open, fw_close, fw_read, fw_write, fw_ioctl, 78 nostop, notty, fw_poll, fw_mmap, nokqfilter, D_OTHER, 79 }; 80 81 struct fw_drv1 { 82 struct firewire_comm *fc; 83 struct fw_xferq *ir; 84 struct fw_xferq *it; 85 struct fw_isobufreq bufreq; 86 STAILQ_HEAD(, fw_bind) binds; 87 STAILQ_HEAD(, fw_xfer) rq; 88 }; 89 90 static int fwdev_allocbuf(struct firewire_comm *, struct fw_xferq *, 91 struct fw_bufspec *); 92 static int fwdev_freebuf(struct fw_xferq *); 93 static int fw_read_async(struct fw_drv1 *, struct uio *, int); 94 static int fw_write_async(struct fw_drv1 *, struct uio *, int); 95 static void fw_hand(struct fw_xfer *); 96 97 extern struct cfdriver ieee1394if_cd; 98 99 int 100 fw_open(dev_t dev, int flags, int fmt, struct lwp *td) 101 { 102 struct firewire_softc *sc; 103 struct fw_drv1 *d; 104 int err = 0; 105 106 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 107 if (sc == NULL) 108 return ENXIO; 109 110 if (DEV_FWMEM(dev)) 111 return fwmem_open(dev, flags, fmt, td); 112 113 mutex_enter(&sc->fc->fc_mtx); 114 if (sc->si_drv1 != NULL) { 115 mutex_exit(&sc->fc->fc_mtx); 116 return EBUSY; 117 } 118 /* set dummy value for allocation */ 119 sc->si_drv1 = (void *)-1; 120 mutex_exit(&sc->fc->fc_mtx); 121 122 sc->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 123 if (sc->si_drv1 == NULL) 124 return ENOMEM; 125 126 d = (struct fw_drv1 *)sc->si_drv1; 127 d->fc = sc->fc; 128 STAILQ_INIT(&d->binds); 129 STAILQ_INIT(&d->rq); 130 131 return err; 132 } 133 134 int 135 fw_close(dev_t dev, int flags, int fmt, struct lwp *td) 136 { 137 struct firewire_softc *sc; 138 struct firewire_comm *fc; 139 struct fw_drv1 *d; 140 struct fw_xfer *xfer; 141 struct fw_bind *fwb; 142 int err = 0; 143 144 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 145 if (sc == NULL) 146 return ENXIO; 147 148 if (DEV_FWMEM(dev)) 149 return fwmem_close(dev, flags, fmt, td); 150 151 d = (struct fw_drv1 *)sc->si_drv1; 152 fc = d->fc; 153 154 /* remove binding */ 155 for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 156 fwb = STAILQ_FIRST(&d->binds)) { 157 fw_bindremove(fc, fwb); 158 STAILQ_REMOVE_HEAD(&d->binds, chlist); 159 fw_xferlist_remove(&fwb->xferlist); 160 free(fwb, M_FW); 161 } 162 if (d->ir != NULL) { 163 struct fw_xferq *ir = d->ir; 164 165 if ((ir->flag & FWXFERQ_OPEN) == 0) 166 return EINVAL; 167 if (ir->flag & FWXFERQ_RUNNING) { 168 ir->flag &= ~FWXFERQ_RUNNING; 169 fc->irx_disable(fc, ir->dmach); 170 } 171 /* free extbuf */ 172 fwdev_freebuf(ir); 173 /* drain receiving buffer */ 174 for (xfer = STAILQ_FIRST(&ir->q); xfer != NULL; 175 xfer = STAILQ_FIRST(&ir->q)) { 176 ir->queued--; 177 STAILQ_REMOVE_HEAD(&ir->q, link); 178 179 xfer->resp = 0; 180 fw_xfer_done(xfer); 181 } 182 ir->flag &= 183 ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 184 d->ir = NULL; 185 186 } 187 if (d->it != NULL) { 188 struct fw_xferq *it = d->it; 189 190 if ((it->flag & FWXFERQ_OPEN) == 0) 191 return EINVAL; 192 if (it->flag & FWXFERQ_RUNNING) { 193 it->flag &= ~FWXFERQ_RUNNING; 194 fc->itx_disable(fc, it->dmach); 195 } 196 /* free extbuf */ 197 fwdev_freebuf(it); 198 it->flag &= 199 ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 200 d->it = NULL; 201 } 202 free(sc->si_drv1, M_FW); 203 sc->si_drv1 = NULL; 204 205 return err; 206 } 207 208 int 209 fw_read(dev_t dev, struct uio *uio, int ioflag) 210 { 211 struct firewire_softc *sc; 212 struct firewire_comm *fc; 213 struct fw_drv1 *d; 214 struct fw_xferq *ir; 215 struct fw_pkt *fp; 216 int err = 0, slept = 0; 217 218 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 219 if (sc == NULL) 220 return ENXIO; 221 222 if (DEV_FWMEM(dev)) 223 return physio(fw_strategy, NULL, dev, ioflag, minphys, uio); 224 225 d = (struct fw_drv1 *)sc->si_drv1; 226 fc = d->fc; 227 ir = d->ir; 228 229 if (ir == NULL) 230 return fw_read_async(d, uio, ioflag); 231 232 if (ir->buf == NULL) 233 return EIO; 234 235 mutex_enter(&fc->fc_mtx); 236 readloop: 237 if (ir->stproc == NULL) { 238 /* iso bulkxfer */ 239 ir->stproc = STAILQ_FIRST(&ir->stvalid); 240 if (ir->stproc != NULL) { 241 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 242 ir->queued = 0; 243 } 244 } 245 if (ir->stproc == NULL) { 246 /* no data avaliable */ 247 if (slept == 0) { 248 slept = 1; 249 ir->flag |= FWXFERQ_WAKEUP; 250 mutex_exit(&fc->fc_mtx); 251 err = tsleep(ir, FWPRI, "fw_read", hz); 252 mutex_enter(&fc->fc_mtx); 253 ir->flag &= ~FWXFERQ_WAKEUP; 254 if (err == 0) 255 goto readloop; 256 } else if (slept == 1) 257 err = EIO; 258 mutex_exit(&fc->fc_mtx); 259 return err; 260 } else if (ir->stproc != NULL) { 261 /* iso bulkxfer */ 262 mutex_exit(&fc->fc_mtx); 263 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 264 ir->stproc->poffset + ir->queued); 265 if (fc->irx_post != NULL) 266 fc->irx_post(fc, fp->mode.ld); 267 if (fp->mode.stream.len == 0) 268 return EIO; 269 err = uiomove((void *)fp, 270 fp->mode.stream.len + sizeof(uint32_t), uio); 271 ir->queued++; 272 if (ir->queued >= ir->bnpacket) { 273 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 274 fc->irx_enable(fc, ir->dmach); 275 ir->stproc = NULL; 276 } 277 if (uio->uio_resid >= ir->psize) { 278 slept = -1; 279 mutex_enter(&fc->fc_mtx); 280 goto readloop; 281 } 282 } else 283 mutex_exit(&fc->fc_mtx); 284 return err; 285 } 286 287 int 288 fw_write(dev_t dev, struct uio *uio, int ioflag) 289 { 290 struct firewire_softc *sc; 291 struct firewire_comm *fc; 292 struct fw_drv1 *d; 293 struct fw_pkt *fp; 294 struct fw_xferq *it; 295 int slept = 0, err = 0; 296 297 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 298 if (sc == NULL) 299 return ENXIO; 300 301 if (DEV_FWMEM(dev)) 302 return physio(fw_strategy, NULL, dev, ioflag, minphys, uio); 303 304 d = (struct fw_drv1 *)sc->si_drv1; 305 fc = d->fc; 306 it = d->it; 307 308 if (it == NULL) 309 return fw_write_async(d, uio, ioflag); 310 311 if (it->buf == NULL) 312 return EIO; 313 314 mutex_enter(&fc->fc_mtx); 315 isoloop: 316 if (it->stproc == NULL) { 317 it->stproc = STAILQ_FIRST(&it->stfree); 318 if (it->stproc != NULL) { 319 STAILQ_REMOVE_HEAD(&it->stfree, link); 320 it->queued = 0; 321 } else if (slept == 0) { 322 slept = 1; 323 #if 0 /* XXX to avoid lock recursion */ 324 err = fc->itx_enable(fc, it->dmach); 325 if (err) 326 goto out; 327 #endif 328 mutex_exit(&fc->fc_mtx); 329 err = tsleep(it, FWPRI, "fw_write", hz); 330 mutex_enter(&fc->fc_mtx); 331 if (err) 332 goto out; 333 goto isoloop; 334 } else { 335 err = EIO; 336 goto out; 337 } 338 } 339 mutex_exit(&fc->fc_mtx); 340 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 341 it->stproc->poffset + it->queued); 342 err = uiomove((void *)fp, sizeof(struct fw_isohdr), uio); 343 if (err != 0) 344 return err; 345 err = 346 uiomove((void *)fp->mode.stream.payload, fp->mode.stream.len, uio); 347 it->queued++; 348 if (it->queued >= it->bnpacket) { 349 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 350 it->stproc = NULL; 351 err = fc->itx_enable(fc, it->dmach); 352 } 353 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 354 slept = 0; 355 mutex_enter(&fc->fc_mtx); 356 goto isoloop; 357 } 358 return err; 359 360 out: 361 mutex_exit(&fc->fc_mtx); 362 return err; 363 } 364 365 int 366 fw_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *td) 367 { 368 struct firewire_softc *sc; 369 struct firewire_comm *fc; 370 struct fw_drv1 *d; 371 struct fw_device *fwdev; 372 struct fw_bind *fwb; 373 struct fw_xferq *ir, *it; 374 struct fw_xfer *xfer; 375 struct fw_pkt *fp; 376 struct fw_devinfo *devinfo; 377 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 378 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 379 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 380 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 381 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 382 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 383 int i, len, err = 0; 384 void *ptr; 385 386 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 387 if (sc == NULL) 388 return ENXIO; 389 390 if (DEV_FWMEM(dev)) 391 return fwmem_ioctl(dev, cmd, data, flag, td); 392 393 if (!data) 394 return EINVAL; 395 396 d = (struct fw_drv1 *)sc->si_drv1; 397 fc = d->fc; 398 ir = d->ir; 399 it = d->it; 400 401 switch (cmd) { 402 case FW_STSTREAM: 403 if (it == NULL) { 404 i = fw_open_isodma(fc, /* tx */1); 405 if (i < 0) { 406 err = EBUSY; 407 break; 408 } 409 it = fc->it[i]; 410 err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 411 if (err) { 412 it->flag &= ~FWXFERQ_OPEN; 413 break; 414 } 415 } 416 it->flag &= ~0xff; 417 it->flag |= (0x3f & ichreq->ch); 418 it->flag |= ((0x3 & ichreq->tag) << 6); 419 d->it = it; 420 break; 421 422 case FW_GTSTREAM: 423 if (it != NULL) { 424 ichreq->ch = it->flag & 0x3f; 425 ichreq->tag = it->flag >> 2 & 0x3; 426 } else 427 err = EINVAL; 428 break; 429 430 case FW_SRSTREAM: 431 if (ir == NULL) { 432 i = fw_open_isodma(fc, /* tx */0); 433 if (i < 0) { 434 err = EBUSY; 435 break; 436 } 437 ir = fc->ir[i]; 438 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 439 if (err) { 440 ir->flag &= ~FWXFERQ_OPEN; 441 break; 442 } 443 } 444 ir->flag &= ~0xff; 445 ir->flag |= (0x3f & ichreq->ch); 446 ir->flag |= ((0x3 & ichreq->tag) << 6); 447 d->ir = ir; 448 err = fc->irx_enable(fc, ir->dmach); 449 break; 450 451 case FW_GRSTREAM: 452 if (d->ir != NULL) { 453 ichreq->ch = ir->flag & 0x3f; 454 ichreq->tag = ir->flag >> 2 & 0x3; 455 } else 456 err = EINVAL; 457 break; 458 459 case FW_SSTBUF: 460 memcpy(&d->bufreq, ibufreq, sizeof(d->bufreq)); 461 break; 462 463 case FW_GSTBUF: 464 memset(&ibufreq->rx, 0, sizeof(ibufreq->rx)); 465 if (ir != NULL) { 466 ibufreq->rx.nchunk = ir->bnchunk; 467 ibufreq->rx.npacket = ir->bnpacket; 468 ibufreq->rx.psize = ir->psize; 469 } 470 memset(&ibufreq->tx, 0, sizeof(ibufreq->tx)); 471 if (it != NULL) { 472 ibufreq->tx.nchunk = it->bnchunk; 473 ibufreq->tx.npacket = it->bnpacket; 474 ibufreq->tx.psize = it->psize; 475 } 476 break; 477 478 case FW_ASYREQ: 479 { 480 const struct tcode_info *tinfo; 481 int pay_len = 0; 482 483 fp = &asyreq->pkt; 484 tinfo = &fc->tcode[fp->mode.hdr.tcode]; 485 486 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 487 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 488 489 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 490 if (xfer == NULL) 491 return ENOMEM; 492 493 switch (asyreq->req.type) { 494 case FWASREQNODE: 495 break; 496 497 case FWASREQEUI: 498 fwdev = fw_noderesolve_eui64(fc, &asyreq->req.dst.eui); 499 if (fwdev == NULL) { 500 aprint_error_dev(fc->bdev, 501 "cannot find node\n"); 502 err = EINVAL; 503 goto out; 504 } 505 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 506 break; 507 508 case FWASRESTL: 509 /* XXX what's this? */ 510 break; 511 512 case FWASREQSTREAM: 513 /* nothing to do */ 514 break; 515 } 516 517 memcpy(&xfer->send.hdr, fp, tinfo->hdr_len); 518 if (pay_len > 0) 519 memcpy(xfer->send.payload, (char *)fp + tinfo->hdr_len, 520 pay_len); 521 xfer->send.spd = asyreq->req.sped; 522 xfer->hand = fw_xferwake; 523 524 if ((err = fw_asyreq(fc, -1, xfer)) != 0) 525 goto out; 526 if ((err = fw_xferwait(xfer)) != 0) 527 goto out; 528 if (xfer->resp != 0) { 529 err = EIO; 530 goto out; 531 } 532 if ((tinfo->flag & FWTI_TLABEL) == 0) 533 goto out; 534 535 /* copy response */ 536 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 537 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 538 xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 539 pay_len = xfer->recv.pay_len; 540 if (asyreq->req.len >= 541 xfer->recv.pay_len + tinfo->hdr_len) 542 asyreq->req.len = 543 xfer->recv.pay_len + tinfo->hdr_len; 544 else { 545 err = EINVAL; 546 pay_len = 0; 547 } 548 } else 549 pay_len = 0; 550 memcpy(fp, &xfer->recv.hdr, tinfo->hdr_len); 551 memcpy((char *)fp + tinfo->hdr_len, xfer->recv.payload, 552 pay_len); 553 out: 554 fw_xfer_free_buf(xfer); 555 break; 556 } 557 558 case FW_IBUSRST: 559 fc->ibr(fc); 560 break; 561 562 case FW_CBINDADDR: 563 fwb = fw_bindlookup(fc, bindreq->start.hi, bindreq->start.lo); 564 if (fwb == NULL) { 565 err = EINVAL; 566 break; 567 } 568 fw_bindremove(fc, fwb); 569 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 570 fw_xferlist_remove(&fwb->xferlist); 571 free(fwb, M_FW); 572 break; 573 574 case FW_SBINDADDR: 575 if (bindreq->len <= 0 ) { 576 err = EINVAL; 577 break; 578 } 579 if (bindreq->start.hi > 0xffff ) { 580 err = EINVAL; 581 break; 582 } 583 fwb = (struct fw_bind *)malloc(sizeof(struct fw_bind), 584 M_FW, M_WAITOK); 585 if (fwb == NULL) { 586 err = ENOMEM; 587 break; 588 } 589 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 590 bindreq->start.lo; 591 fwb->end = fwb->start + bindreq->len; 592 fwb->sc = (void *)d; 593 STAILQ_INIT(&fwb->xferlist); 594 err = fw_bindadd(fc, fwb); 595 if (err == 0) { 596 fw_xferlist_add(&fwb->xferlist, M_FWXFER, 597 /* XXX */ 598 PAGE_SIZE, PAGE_SIZE, 5, fc, (void *)fwb, fw_hand); 599 STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 600 } 601 break; 602 603 case FW_GDEVLST: 604 i = len = 1; 605 /* myself */ 606 devinfo = fwdevlst->dev; 607 devinfo->dst = fc->nodeid; 608 devinfo->status = 0; /* XXX */ 609 devinfo->eui.hi = fc->eui.hi; 610 devinfo->eui.lo = fc->eui.lo; 611 STAILQ_FOREACH(fwdev, &fc->devices, link) { 612 if (len < FW_MAX_DEVLST) { 613 devinfo = &fwdevlst->dev[len++]; 614 devinfo->dst = fwdev->dst; 615 devinfo->status = 616 (fwdev->status == FWDEVINVAL) ? 0 : 1; 617 devinfo->eui.hi = fwdev->eui.hi; 618 devinfo->eui.lo = fwdev->eui.lo; 619 } 620 i++; 621 } 622 fwdevlst->n = i; 623 fwdevlst->info_len = len; 624 break; 625 626 case FW_GTPMAP: 627 memcpy(data, fc->topology_map, 628 (fc->topology_map->crc_len + 1) * 4); 629 break; 630 631 case FW_GCROM: 632 STAILQ_FOREACH(fwdev, &fc->devices, link) 633 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 634 break; 635 if (fwdev == NULL) { 636 if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 637 err = FWNODE_INVAL; 638 break; 639 } 640 /* myself */ 641 ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 642 len = CROMSIZE; 643 for (i = 0; i < CROMSIZE/4; i++) 644 ((uint32_t *)ptr)[i] = ntohl(fc->config_rom[i]); 645 } else { 646 /* found */ 647 ptr = (void *)fwdev->csrrom; 648 if (fwdev->rommax < CSRROMOFF) 649 len = 0; 650 else 651 len = fwdev->rommax - CSRROMOFF + 4; 652 } 653 if (crom_buf->len < len) 654 len = crom_buf->len; 655 else 656 crom_buf->len = len; 657 err = copyout(ptr, crom_buf->ptr, len); 658 if (fwdev == NULL) 659 /* myself */ 660 free(ptr, M_FW); 661 break; 662 663 default: 664 fc->ioctl(dev, cmd, data, flag, td); 665 break; 666 } 667 return err; 668 } 669 670 int 671 fw_poll(dev_t dev, int events, struct lwp *td) 672 { 673 struct firewire_softc *sc; 674 struct fw_xferq *ir; 675 int revents, tmp; 676 677 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 678 if (sc == NULL) 679 return ENXIO; 680 681 ir = ((struct fw_drv1 *)sc->si_drv1)->ir; 682 revents = 0; 683 tmp = POLLIN | POLLRDNORM; 684 if (events & tmp) { 685 if (STAILQ_FIRST(&ir->q) != NULL) 686 revents |= tmp; 687 else 688 selrecord(td, &ir->rsel); 689 } 690 tmp = POLLOUT | POLLWRNORM; 691 if (events & tmp) 692 /* XXX should be fixed */ 693 revents |= tmp; 694 695 return revents; 696 } 697 698 paddr_t 699 fw_mmap(dev_t dev, off_t offset, int nproto) 700 { 701 struct firewire_softc *sc; 702 703 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 704 if (sc == NULL) 705 return ENXIO; 706 707 return EINVAL; 708 } 709 710 void 711 fw_strategy(struct bio *bp) 712 { 713 struct firewire_softc *sc; 714 dev_t dev = bp->bio_dev; 715 716 sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 717 if (sc == NULL) 718 return; 719 720 if (DEV_FWMEM(dev)) { 721 fwmem_strategy(bp); 722 return; 723 } 724 725 bp->bio_error = EOPNOTSUPP; 726 bp->bio_resid = bp->bio_bcount; 727 biodone(bp); 728 } 729 730 731 static int 732 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 733 struct fw_bufspec *b) 734 { 735 int i; 736 737 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 738 return EBUSY; 739 740 q->bulkxfer = 741 (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * b->nchunk, 742 M_FW, M_WAITOK); 743 if (q->bulkxfer == NULL) 744 return ENOMEM; 745 746 b->psize = roundup2(b->psize, sizeof(uint32_t)); 747 q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), b->psize, 748 b->nchunk * b->npacket, BUS_DMA_WAITOK); 749 750 if (q->buf == NULL) { 751 free(q->bulkxfer, M_FW); 752 q->bulkxfer = NULL; 753 return ENOMEM; 754 } 755 q->bnchunk = b->nchunk; 756 q->bnpacket = b->npacket; 757 q->psize = (b->psize + 3) & ~3; 758 q->queued = 0; 759 760 STAILQ_INIT(&q->stvalid); 761 STAILQ_INIT(&q->stfree); 762 STAILQ_INIT(&q->stdma); 763 q->stproc = NULL; 764 765 for (i = 0 ; i < q->bnchunk; i++) { 766 q->bulkxfer[i].poffset = i * q->bnpacket; 767 q->bulkxfer[i].mbuf = NULL; 768 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 769 } 770 771 q->flag &= ~FWXFERQ_MODEMASK; 772 q->flag |= FWXFERQ_STREAM; 773 q->flag |= FWXFERQ_EXTBUF; 774 775 return 0; 776 } 777 778 static int 779 fwdev_freebuf(struct fw_xferq *q) 780 { 781 782 if (q->flag & FWXFERQ_EXTBUF) { 783 if (q->buf != NULL) 784 fwdma_free_multiseg(q->buf); 785 q->buf = NULL; 786 free(q->bulkxfer, M_FW); 787 q->bulkxfer = NULL; 788 q->flag &= ~FWXFERQ_EXTBUF; 789 q->psize = 0; 790 q->maxq = FWMAXQUEUE; 791 } 792 return 0; 793 } 794 795 static int 796 fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 797 { 798 struct fw_xfer *xfer; 799 struct fw_bind *fwb; 800 struct fw_pkt *fp; 801 const struct tcode_info *tinfo; 802 int err = 0; 803 804 mutex_enter(&d->fc->fc_mtx); 805 806 for (;;) { 807 xfer = STAILQ_FIRST(&d->rq); 808 if (xfer == NULL && err == 0) { 809 mutex_exit(&d->fc->fc_mtx); 810 err = tsleep(&d->rq, FWPRI, "fwra", 0); 811 if (err != 0) 812 return err; 813 mutex_enter(&d->fc->fc_mtx); 814 continue; 815 } 816 break; 817 } 818 819 STAILQ_REMOVE_HEAD(&d->rq, link); 820 mutex_exit(&d->fc->fc_mtx); 821 fp = &xfer->recv.hdr; 822 #if 0 /* for GASP ?? */ 823 if (fc->irx_post != NULL) 824 fc->irx_post(fc, fp->mode.ld); 825 #endif 826 tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 827 err = uiomove((void *)fp, tinfo->hdr_len, uio); 828 if (err) 829 goto out; 830 err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio); 831 832 out: 833 /* recycle this xfer */ 834 fwb = (struct fw_bind *)xfer->sc; 835 fw_xfer_unload(xfer); 836 xfer->recv.pay_len = PAGE_SIZE; 837 mutex_enter(&d->fc->fc_mtx); 838 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 839 mutex_exit(&d->fc->fc_mtx); 840 return err; 841 } 842 843 static int 844 fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 845 { 846 struct fw_xfer *xfer; 847 struct fw_pkt pkt; 848 const struct tcode_info *tinfo; 849 int err; 850 851 memset(&pkt, 0, sizeof(struct fw_pkt)); 852 if ((err = uiomove((void *)&pkt, sizeof(uint32_t), uio))) 853 return err; 854 tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 855 if ((err = uiomove((char *)&pkt + sizeof(uint32_t), 856 tinfo->hdr_len - sizeof(uint32_t), uio))) 857 return err; 858 859 if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 860 PAGE_SIZE/*XXX*/)) == NULL) 861 return ENOMEM; 862 863 memcpy(&xfer->send.hdr, &pkt, sizeof(struct fw_pkt)); 864 xfer->send.pay_len = uio->uio_resid; 865 if (uio->uio_resid > 0) { 866 if ((err = 867 uiomove((void *)xfer->send.payload, uio->uio_resid, uio))) 868 goto out; 869 } 870 871 xfer->fc = d->fc; 872 xfer->sc = NULL; 873 xfer->hand = fw_xferwake; 874 xfer->send.spd = 2 /* XXX */; 875 876 if ((err = fw_asyreq(xfer->fc, -1, xfer))) 877 goto out; 878 879 if ((err = fw_xferwait(xfer))) 880 goto out; 881 882 if (xfer->resp != 0) { 883 err = xfer->resp; 884 goto out; 885 } 886 887 if (xfer->flag == FWXF_RCVD) { 888 mutex_enter(&xfer->fc->fc_mtx); 889 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 890 mutex_exit(&xfer->fc->fc_mtx); 891 return 0; 892 } 893 894 out: 895 fw_xfer_free(xfer); 896 return err; 897 } 898 899 static void 900 fw_hand(struct fw_xfer *xfer) 901 { 902 struct fw_bind *fwb; 903 struct fw_drv1 *d; 904 905 fwb = (struct fw_bind *)xfer->sc; 906 d = (struct fw_drv1 *)fwb->sc; 907 mutex_enter(&xfer->fc->fc_mtx); 908 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 909 mutex_exit(&xfer->fc->fc_mtx); 910 wakeup(&d->rq); 911 } 912