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