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