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