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